aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2019-12-03 18:46:24 +0100
committerDmitry Vyukov <dvyukov@google.com>2019-12-03 18:48:14 +0100
commita2d178996b0844c378dd013dde53a5c1f5a17fbd (patch)
tree7d883fb040026ee7cbe9048d3a5937497ad58e9b
parentdfe2e9d84a64066fd15913c7cd02d1853adf3942 (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.go15
-rw-r--r--pkg/mgrconfig/load.go7
-rw-r--r--pkg/osutil/osutil.go24
-rw-r--r--vm/qemu/qemu.go14
-rw-r--r--vm/vm.go16
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 {
diff --git a/vm/vm.go b/vm/vm.go
index 2e499f567..1b6e7eb2e 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -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)