aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-06-21 17:45:53 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-06-22 16:40:45 +0200
commitea804a7120e0b87dabd3f24227f9550332c42c79 (patch)
treeab4a2a07ca204e6756219af41edecd2ba1d4919c /pkg
parent8c9738f9c7a89b865866092a7b48cc0b6c1d34c9 (diff)
pkg/build: pave way for multi-OS support
Unify kernel and image build, that distinction is really uninteresting. Define interface that each OS needs to implement. Add gvisor stub.
Diffstat (limited to 'pkg')
-rw-r--r--pkg/bisect/bisect.go6
-rw-r--r--pkg/build/build.go47
-rw-r--r--pkg/build/gvisor.go15
-rw-r--r--pkg/build/linux.go80
-rw-r--r--pkg/instance/instance.go17
5 files changed, 121 insertions, 44 deletions
diff --git a/pkg/bisect/bisect.go b/pkg/bisect/bisect.go
index 4e2ee143f..78ac998a4 100644
--- a/pkg/bisect/bisect.go
+++ b/pkg/bisect/bisect.go
@@ -101,7 +101,8 @@ func (env *env) bisect() (*git.Commit, error) {
if env.head, err = git.Poll(cfg.Manager.KernelSrc, cfg.Kernel.Repo, cfg.Kernel.Branch); err != nil {
return nil, err
}
- if err := build.Clean(cfg.Manager.KernelSrc); err != nil {
+ if err := build.Clean(cfg.Manager.TargetOS, cfg.Manager.TargetArch,
+ cfg.Manager.Type, cfg.Manager.KernelSrc); err != nil {
return nil, fmt.Errorf("kernel clean failed: %v", err)
}
env.log("building syzkaller on %v", cfg.Syzkaller.Commit)
@@ -220,7 +221,8 @@ func (env *env) test() (git.BisectResult, error) {
}
env.log("testing commit %v with %v", current.Hash, compilerID)
buildStart := time.Now()
- if err := build.Clean(cfg.Manager.KernelSrc); err != nil {
+ if err := build.Clean(cfg.Manager.TargetOS, cfg.Manager.TargetArch,
+ cfg.Manager.Type, cfg.Manager.KernelSrc); err != nil {
return 0, fmt.Errorf("kernel clean failed: %v", err)
}
err = env.inst.BuildKernel(be.compiler, cfg.Kernel.Userspace,
diff --git a/pkg/build/build.go b/pkg/build/build.go
index 0d959cbb4..6eb912e21 100644
--- a/pkg/build/build.go
+++ b/pkg/build/build.go
@@ -12,6 +12,53 @@ import (
"github.com/google/syzkaller/pkg/osutil"
)
+// Image creates a disk image for the specified OS/ARCH/VM.
+// Kernel is taken from kernelDir, userspace system is taken from userspaceDir.
+// If cmdlineFile is not empty, contents of the file are appended to the kernel command line.
+// If sysctlFile is not empty, contents of the file are appended to the image /etc/sysctl.conf.
+// Output is stored in outputDir and includes:
+// - image: the image
+// - key: ssh key for the image if applicable
+// - kernel.config: actual kernel config used during build
+// - obj/: directory with kernel object files (e.g. vmlinux for linux)
+func Image(targetOS, targetArch, vmType, kernelDir, outputDir, compiler, userspaceDir,
+ cmdlineFile, sysctlFile string, config []byte) error {
+ builder, err := getBuilder(targetOS, targetArch, vmType)
+ if err != nil {
+ return err
+ }
+ return builder.build(targetArch, vmType, kernelDir, outputDir, compiler, userspaceDir, cmdlineFile, sysctlFile, config)
+}
+
+func Clean(targetOS, targetArch, vmType, kernelDir string) error {
+ builder, err := getBuilder(targetOS, targetArch, vmType)
+ if err != nil {
+ return err
+ }
+ return builder.clean(kernelDir)
+}
+
+type KernelBuildError struct {
+ *osutil.VerboseError
+}
+
+type builder interface {
+ build(targetArch, vmType, kernelDir, outputDir, compiler, userspaceDir,
+ cmdlineFile, sysctlFile string, config []byte) error
+ clean(kernelDir string) error
+}
+
+func getBuilder(targetOS, targetArch, vmType string) (builder, error) {
+ switch {
+ case targetOS == "linux" && targetArch == "amd64" && vmType == "gvisor":
+ return gvisor{}, nil
+ case targetOS == "linux" && targetArch == "amd64" && (vmType == "qemu" || vmType == "gce"):
+ return linux{}, nil
+ default:
+ return nil, fmt.Errorf("unsupported image type %v/%v/%v", targetOS, targetArch, vmType)
+ }
+}
+
func CompilerIdentity(compiler string) (string, error) {
arg := "--version"
if strings.HasSuffix(compiler, "bazel") {
diff --git a/pkg/build/gvisor.go b/pkg/build/gvisor.go
new file mode 100644
index 000000000..8649e7e65
--- /dev/null
+++ b/pkg/build/gvisor.go
@@ -0,0 +1,15 @@
+// Copyright 2018 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package build
+
+type gvisor struct{}
+
+func (gvisor) build(targetArch, vmType, kernelDir, outputDir, compiler, userspaceDir,
+ cmdlineFile, sysctlFile string, config []byte) error {
+ return nil
+}
+
+func (gvisor) clean(kernelDir string) error {
+ return nil
+}
diff --git a/pkg/build/linux.go b/pkg/build/linux.go
index ae296674a..a2afc3011 100644
--- a/pkg/build/linux.go
+++ b/pkg/build/linux.go
@@ -22,8 +22,24 @@ import (
"github.com/google/syzkaller/pkg/osutil"
)
-func Build(dir, compiler string, config []byte) error {
- configFile := filepath.Join(dir, ".config")
+type linux struct{}
+
+func (linux linux) build(targetArch, vmType, kernelDir, outputDir, compiler, userspaceDir,
+ cmdlineFile, sysctlFile string, config []byte) error {
+ if err := osutil.MkdirAll(filepath.Join(outputDir, "obj")); err != nil {
+ return err
+ }
+ if err := linux.buildKernel(kernelDir, outputDir, compiler, config); err != nil {
+ return err
+ }
+ if err := linux.createImage(vmType, kernelDir, outputDir, userspaceDir, cmdlineFile, sysctlFile); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (linux) buildKernel(kernelDir, outputDir, compiler string, config []byte) error {
+ configFile := filepath.Join(kernelDir, ".config")
if err := osutil.WriteFile(configFile, config); err != nil {
return fmt.Errorf("failed to write config file: %v", err)
}
@@ -37,7 +53,7 @@ func Build(dir, compiler string, config []byte) error {
if err := osutil.Sandbox(cmd, true, true); err != nil {
return err
}
- cmd.Dir = dir
+ cmd.Dir = kernelDir
if _, err := osutil.Run(10*time.Minute, cmd); err != nil {
return err
}
@@ -47,38 +63,23 @@ func Build(dir, compiler string, config []byte) error {
if err := osutil.Sandbox(cmd, true, true); err != nil {
return err
}
- cmd.Dir = dir
- // Build of a large kernel can take a while on a 1 CPU VM.
- if _, err := osutil.Run(3*time.Hour, cmd); err != nil {
+ cmd.Dir = kernelDir
+ if _, err := osutil.Run(time.Hour, cmd); err != nil {
return extractRootCause(err)
}
- return nil
-}
-
-func Clean(dir string) error {
- cpu := strconv.Itoa(runtime.NumCPU())
- cmd := osutil.Command("make", "distclean", "-j", cpu)
- if err := osutil.Sandbox(cmd, true, true); err != nil {
+ outputConfig := filepath.Join(outputDir, "kernel.config")
+ if err := osutil.CopyFile(configFile, outputConfig); err != nil {
return err
}
- cmd.Dir = dir
- _, err := osutil.Run(10*time.Minute, cmd)
- return err
+ vmlinux := filepath.Join(kernelDir, "vmlinux")
+ outputVmlinux := filepath.Join(outputDir, "obj", "vmlinux")
+ if err := os.Rename(vmlinux, outputVmlinux); err != nil {
+ return fmt.Errorf("failed to rename vmlinux: %v", err)
+ }
+ return nil
}
-// CreateImage creates a disk image that is suitable for syzkaller.
-// Kernel is taken from kernelDir, userspace system is taken from userspaceDir.
-// If cmdlineFile is not empty, contents of the file are appended to the kernel command line.
-// If sysctlFile is not empty, contents of the file are appended to the image /etc/sysctl.conf.
-// Produces image and root ssh key in the specified files.
-func CreateImage(targetOS, targetArch, vmType, kernelDir, userspaceDir, cmdlineFile, sysctlFile,
- image, sshkey string) error {
- if targetOS != "linux" || targetArch != "amd64" {
- return fmt.Errorf("only linux/amd64 is supported")
- }
- if vmType != "qemu" && vmType != "gce" {
- return fmt.Errorf("images can be built only for qemu/gce machines")
- }
+func (linux) createImage(vmType, kernelDir, outputDir, userspaceDir, cmdlineFile, sysctlFile string) error {
tempDir, err := ioutil.TempDir("", "syz-build")
if err != nil {
return err
@@ -101,18 +102,31 @@ func CreateImage(targetOS, targetArch, vmType, kernelDir, userspaceDir, cmdlineF
return fmt.Errorf("image build failed: %v", err)
}
// Note: we use CopyFile instead of Rename because src and dst can be on different filesystems.
- if err := osutil.CopyFile(filepath.Join(tempDir, "disk.raw"), image); err != nil {
+ imageFile := filepath.Join(outputDir, "image")
+ if err := osutil.CopyFile(filepath.Join(tempDir, "disk.raw"), imageFile); err != nil {
return err
}
- if err := osutil.CopyFile(filepath.Join(tempDir, "key"), sshkey); err != nil {
+ keyFile := filepath.Join(outputDir, "key")
+ if err := osutil.CopyFile(filepath.Join(tempDir, "key"), keyFile); err != nil {
return err
}
- if err := os.Chmod(sshkey, 0600); err != nil {
+ if err := os.Chmod(keyFile, 0600); err != nil {
return err
}
return nil
}
+func (linux) clean(kernelDir string) error {
+ cpu := strconv.Itoa(runtime.NumCPU())
+ cmd := osutil.Command("make", "distclean", "-j", cpu)
+ if err := osutil.Sandbox(cmd, true, true); err != nil {
+ return err
+ }
+ cmd.Dir = kernelDir
+ _, err := osutil.Run(10*time.Minute, cmd)
+ return err
+}
+
func extractRootCause(err error) error {
verr, ok := err.(*osutil.VerboseError)
if !ok {
@@ -133,7 +147,7 @@ func extractRootCause(err error) error {
if cause != nil {
verr.Title = string(cause)
}
- return verr
+ return KernelBuildError{verr}
}
type buildFailureCause struct {
diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go
index 2294fed9b..cec79459a 100644
--- a/pkg/instance/instance.go
+++ b/pkg/instance/instance.go
@@ -79,16 +79,15 @@ func (env *Env) BuildSyzkaller(repo, commit string) error {
func (env *Env) BuildKernel(compilerBin, userspaceDir, cmdlineFile, sysctlFile string, kernelConfig []byte) error {
cfg := env.cfg
- if err := build.Build(cfg.KernelSrc, compilerBin, kernelConfig); err != nil {
- return osutil.PrependContext("kernel build failed", err)
- }
- cfg.KernelObj = cfg.KernelSrc
- cfg.Image = filepath.Join(cfg.Workdir, "syz-image")
- cfg.SSHKey = filepath.Join(cfg.Workdir, "syz-key")
- if err := build.CreateImage(cfg.TargetOS, cfg.TargetVMArch, cfg.Type,
- cfg.KernelSrc, userspaceDir, cmdlineFile, sysctlFile, cfg.Image, cfg.SSHKey); err != nil {
- return osutil.PrependContext("image build failed", err)
+ imageDir := filepath.Join(cfg.Workdir, "image")
+ if err := build.Image(cfg.TargetOS, cfg.TargetVMArch, cfg.Type,
+ cfg.KernelSrc, imageDir, compilerBin, userspaceDir,
+ cmdlineFile, sysctlFile, kernelConfig); err != nil {
+ return err
}
+ cfg.KernelObj = filepath.Join(imageDir, "obj")
+ cfg.Image = filepath.Join(imageDir, "image")
+ cfg.SSHKey = filepath.Join(imageDir, "key")
return nil
}