mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-23 19:39:40 +00:00
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.
This commit is contained in:
parent
8c9738f9c7
commit
ea804a7120
@ -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,
|
||||
|
@ -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") {
|
||||
|
15
pkg/build/gvisor.go
Normal file
15
pkg/build/gvisor.go
Normal file
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
outputConfig := filepath.Join(outputDir, "kernel.config")
|
||||
if err := osutil.CopyFile(configFile, outputConfig); err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
cmd.Dir = dir
|
||||
_, err := osutil.Run(10*time.Minute, cmd)
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ func (jp *JobProcessor) test(job *Job) error {
|
||||
resp.Build.KernelCommitTitle = kernelCommit.Title
|
||||
resp.Build.KernelCommitDate = kernelCommit.Date
|
||||
|
||||
if err := build.Clean(kernelDir); err != nil {
|
||||
if err := build.Clean(mgrcfg.TargetOS, mgrcfg.TargetArch, mgrcfg.Type, kernelDir); err != nil {
|
||||
return fmt.Errorf("kernel clean failed: %v", err)
|
||||
}
|
||||
if len(req.Patch) != 0 {
|
||||
|
@ -270,36 +270,20 @@ func (mgr *Manager) build() error {
|
||||
if err := config.SaveFile(filepath.Join(tmpDir, "tag"), info); err != nil {
|
||||
return fmt.Errorf("failed to write tag file: %v", err)
|
||||
}
|
||||
|
||||
if err := build.Build(mgr.kernelDir, mgr.mgrcfg.Compiler, kernelConfigData); err != nil {
|
||||
rep := &report.Report{
|
||||
Title: fmt.Sprintf("%v build error", mgr.mgrcfg.RepoAlias),
|
||||
Output: []byte(err.Error()),
|
||||
}
|
||||
if err := mgr.reportBuildError(rep, info, tmpDir); err != nil {
|
||||
mgr.Errorf("failed to report image error: %v", err)
|
||||
if err := build.Image(mgr.managercfg.TargetOS, mgr.managercfg.TargetVMArch, mgr.managercfg.Type,
|
||||
mgr.kernelDir, tmpDir, mgr.mgrcfg.Compiler, mgr.mgrcfg.Userspace,
|
||||
mgr.mgrcfg.KernelCmdline, mgr.mgrcfg.KernelSysctl, kernelConfigData); err != nil {
|
||||
if _, ok := err.(build.KernelBuildError); ok {
|
||||
rep := &report.Report{
|
||||
Title: fmt.Sprintf("%v build error", mgr.mgrcfg.RepoAlias),
|
||||
Output: []byte(err.Error()),
|
||||
}
|
||||
if err := mgr.reportBuildError(rep, info, tmpDir); err != nil {
|
||||
mgr.Errorf("failed to report image error: %v", err)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("kernel build failed: %v", err)
|
||||
}
|
||||
kernelConfig := filepath.Join(tmpDir, "kernel.config")
|
||||
if err := osutil.CopyFile(filepath.Join(mgr.kernelDir, ".config"), kernelConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
image := filepath.Join(tmpDir, "image")
|
||||
key := filepath.Join(tmpDir, "key")
|
||||
err = build.CreateImage(mgr.managercfg.TargetOS, mgr.managercfg.TargetVMArch, mgr.managercfg.Type,
|
||||
mgr.kernelDir, mgr.mgrcfg.Userspace, mgr.mgrcfg.KernelCmdline, mgr.mgrcfg.KernelSysctl, image, key)
|
||||
if err != nil {
|
||||
return fmt.Errorf("image build failed: %v", err)
|
||||
}
|
||||
|
||||
vmlinux := filepath.Join(mgr.kernelDir, "vmlinux")
|
||||
objDir := filepath.Join(tmpDir, "obj")
|
||||
osutil.MkdirAll(objDir)
|
||||
if err := os.Rename(vmlinux, filepath.Join(objDir, "vmlinux")); err != nil {
|
||||
return fmt.Errorf("failed to rename vmlinux file: %v", err)
|
||||
}
|
||||
|
||||
if err := mgr.testImage(tmpDir, info); err != nil {
|
||||
return err
|
||||
|
Loading…
Reference in New Issue
Block a user