diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2019-12-03 18:46:24 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2019-12-03 18:48:14 +0100 |
| commit | a2d178996b0844c378dd013dde53a5c1f5a17fbd (patch) | |
| tree | 7d883fb040026ee7cbe9048d3a5937497ad58e9b | |
| parent | dfe2e9d84a64066fd15913c7cd02d1853adf3942 (diff) | |
vm: add workdir_template functionality
The new manager config argument workdir_template refers to a directory. Optional.
Each VM will get a recursive copy of the files that are present in workdir_template.
VM config can then use these private copies as needed. The copy directory
can be referenced with "{{TEMPLATE}}" string. This is different from using
the files directly in that each instance will get own clean, private,
scratch copy of the files. Currently supported only for qemu_args argument
of qemu VM type. Use example:
Create a template dir with necessary files:
$ mkdir /mytemplatedir
$ truncate -s 64K /mytemplatedir/fd
Then specify the dir in the manager config:
"workdir_template": "/mytemplatedir"
Then use these files in VM config:
"qemu_args": "-fda {{TEMPLATE}}/fd"
| -rw-r--r-- | pkg/mgrconfig/config.go | 15 | ||||
| -rw-r--r-- | pkg/mgrconfig/load.go | 7 | ||||
| -rw-r--r-- | pkg/osutil/osutil.go | 24 | ||||
| -rw-r--r-- | vm/qemu/qemu.go | 14 | ||||
| -rw-r--r-- | vm/vm.go | 16 |
5 files changed, 69 insertions, 7 deletions
diff --git a/pkg/mgrconfig/config.go b/pkg/mgrconfig/config.go index 07df5d0c7..69df2a801 100644 --- a/pkg/mgrconfig/config.go +++ b/pkg/mgrconfig/config.go @@ -19,6 +19,21 @@ type Config struct { // - <workdir>/corpus.db: corpus with interesting programs // - <workdir>/instance-x: per VM instance temporary files Workdir string `json:"workdir"` + // Refers to a directory. Optional. + // Each VM will get a recursive copy of the files that are present in workdir_template. + // VM config can then use these private copies as needed. The copy directory + // can be referenced with "{{TEMPLATE}}" string. This is different from using + // the files directly in that each instance will get own clean, private, + // scratch copy of the files. Currently supported only for qemu_args argument + // of qemu VM type. Use example: + // Create a template dir with necessary files: + // $ mkdir /mytemplatedir + // $ truncate -s 64K /mytemplatedir/fd + // Then specify the dir in the manager config: + // "workdir_template": "/mytemplatedir" + // Then use these files in VM config: + // "qemu_args": "-fda {{TEMPLATE}}/fd" + WorkdirTemplate string `json:"workdir_template"` // Directory with kernel object files (e.g. `vmlinux` for linux) // (used for report symbolization and coverage reports, optional). KernelObj string `json:"kernel_obj"` diff --git a/pkg/mgrconfig/load.go b/pkg/mgrconfig/load.go index 0733a9c2a..4e4136362 100644 --- a/pkg/mgrconfig/load.go +++ b/pkg/mgrconfig/load.go @@ -5,6 +5,7 @@ package mgrconfig import ( "fmt" + "io/ioutil" "os" "path/filepath" "strings" @@ -82,6 +83,12 @@ func Complete(cfg *Config) error { return fmt.Errorf("config param workdir is empty") } cfg.Workdir = osutil.Abs(cfg.Workdir) + if cfg.WorkdirTemplate != "" { + cfg.WorkdirTemplate = osutil.Abs(cfg.WorkdirTemplate) + if _, err := ioutil.ReadDir(cfg.WorkdirTemplate); err != nil { + return fmt.Errorf("failed to read workdir_template: %v", err) + } + } if cfg.Syzkaller == "" { return fmt.Errorf("config param syzkaller is empty") } diff --git a/pkg/osutil/osutil.go b/pkg/osutil/osutil.go index 32a8054e7..0bc257e76 100644 --- a/pkg/osutil/osutil.go +++ b/pkg/osutil/osutil.go @@ -163,6 +163,30 @@ func CopyFiles(srcDir, dstDir string, files map[string]bool) error { return os.Rename(tmpDir, dstDir) } +func CopyDirRecursively(srcDir, dstDir string) error { + if err := MkdirAll(dstDir); err != nil { + return err + } + files, err := ioutil.ReadDir(srcDir) + if err != nil { + return err + } + for _, file := range files { + src := filepath.Join(srcDir, file.Name()) + dst := filepath.Join(dstDir, file.Name()) + if file.IsDir() { + if err := CopyDirRecursively(src, dst); err != nil { + return err + } + continue + } + if err := CopyFile(src, dst); err != nil { + return err + } + } + return nil +} + // LinkFiles creates hard links for files from dstDir to srcDir. // Files are assumed to be relative names in slash notation. // All other files in dstDir are removed. diff --git a/vm/qemu/qemu.go b/vm/qemu/qemu.go index 44e12246b..dae8f493b 100644 --- a/vm/qemu/qemu.go +++ b/vm/qemu/qemu.go @@ -337,9 +337,7 @@ func (inst *instance) boot() error { "-serial", "stdio", "-no-reboot", } - if inst.cfg.QemuArgs != "" { - args = append(args, strings.Split(inst.cfg.QemuArgs, " ")...) - } + args = append(args, splitArgs(inst.cfg.QemuArgs, filepath.Join(inst.workdir, "template"))...) if inst.image == "9p" { args = append(args, "-fsdev", "local,id=fsdev0,path=/,security_model=none,readonly", @@ -426,6 +424,16 @@ func (inst *instance) boot() error { return nil } +func splitArgs(str, template string) (args []string) { + for _, arg := range strings.Split(str, " ") { + if arg == "" { + continue + } + args = append(args, strings.Replace(arg, "{{TEMPLATE}}", template, -1)) + } + return +} + func (inst *instance) Forward(port int) (string, error) { addr := hostAddr if inst.target.HostFuzzer { @@ -12,6 +12,7 @@ import ( "bytes" "fmt" "os" + "path/filepath" "time" "github.com/google/syzkaller/pkg/mgrconfig" @@ -32,8 +33,9 @@ import ( ) type Pool struct { - impl vmimpl.Pool - workdir string + impl vmimpl.Pool + workdir string + template string } type Instance struct { @@ -86,8 +88,9 @@ func Create(cfg *mgrconfig.Config, debug bool) (*Pool, error) { return nil, err } return &Pool{ - impl: impl, - workdir: env.Workdir, + impl: impl, + workdir: env.Workdir, + template: cfg.WorkdirTemplate, }, nil } @@ -103,6 +106,11 @@ func (pool *Pool) Create(index int) (*Instance, error) { if err != nil { return nil, fmt.Errorf("failed to create instance temp dir: %v", err) } + if pool.template != "" { + if err := osutil.CopyDirRecursively(pool.template, filepath.Join(workdir, "template")); err != nil { + return nil, err + } + } impl, err := pool.impl.Create(workdir, index) if err != nil { os.RemoveAll(workdir) |
