aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/build/cuttlefish.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/build/cuttlefish.go')
-rw-r--r--pkg/build/cuttlefish.go160
1 files changed, 160 insertions, 0 deletions
diff --git a/pkg/build/cuttlefish.go b/pkg/build/cuttlefish.go
new file mode 100644
index 000000000..42ec8af26
--- /dev/null
+++ b/pkg/build/cuttlefish.go
@@ -0,0 +1,160 @@
+// Copyright 2022 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
+
+import (
+ "archive/tar"
+ "compress/gzip"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/google/syzkaller/pkg/osutil"
+)
+
+const (
+ kernelConfig = "common/build.config.gki_kasan.x86_64"
+ moduleConfig = "common-modules/virtual-device/build.config.virtual_device_kasan.x86_64"
+ bazelTarget = "//common-modules/virtual-device:virtual_device_x86_64_dist"
+)
+
+type cuttlefish struct{}
+
+func (c cuttlefish) runBuild(kernelDir, buildConfig string) error {
+ cmd := osutil.Command("build/build.sh")
+ cmd.Dir = kernelDir
+ cmd.Env = append(cmd.Env, "OUT_DIR=out", "DIST_DIR=dist", fmt.Sprintf("BUILD_CONFIG=%s", buildConfig))
+
+ _, err := osutil.Run(time.Hour, cmd)
+ return err
+}
+
+func (c cuttlefish) runBazel(kernelDir string) error {
+ cmd := osutil.Command("tools/bazel", "run", "--kasan", bazelTarget, "--", "--dist_dir=dist")
+ cmd.Dir = kernelDir
+ _, err := osutil.Run(time.Hour, cmd)
+ return err
+}
+
+func (c cuttlefish) readCompiler(archivePath string) (string, error) {
+ f, err := os.Open(archivePath)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+
+ gr, err := gzip.NewReader(f)
+ if err != nil {
+ return "", err
+ }
+ defer gr.Close()
+
+ tr := tar.NewReader(gr)
+
+ h, err := tr.Next()
+ for ; err == nil; h, err = tr.Next() {
+ if filepath.Base(h.Name) == "compile.h" {
+ bytes, err := ioutil.ReadAll(tr)
+ if err != nil {
+ return "", err
+ }
+ result := linuxCompilerRegexp.FindSubmatch(bytes)
+ if result == nil {
+ return "", fmt.Errorf("include/generated/compile.h does not contain build information")
+ }
+
+ return string(result[1]), nil
+ }
+ }
+
+ return "", fmt.Errorf("archive %s doesn't contain include/generated/compile.h", archivePath)
+}
+
+func (c cuttlefish) build(params Params) (ImageDetails, error) {
+ var details ImageDetails
+
+ if params.CmdlineFile != "" {
+ return details, fmt.Errorf("cmdline file is not supported for android cuttlefish images")
+ }
+ if params.SysctlFile != "" {
+ return details, fmt.Errorf("sysctl file is not supported for android cuttlefish images")
+ }
+
+ var config string
+ var err error
+ // Default to build.sh if compiler is not specified.
+ if params.Compiler == "bazel" {
+ if err := c.runBazel(params.KernelDir); err != nil {
+ return details, fmt.Errorf("failed to build kernel: %s", err)
+ }
+ // Find the .config file; it is placed in a temporary output directory during the build.
+ cmd := osutil.Command("find", ".", "-wholename", "*virtual_device_x86_64_config/out_dir/.config")
+ cmd.Dir = params.KernelDir
+ configBytes, err := osutil.Run(time.Minute, cmd)
+ if err != nil {
+ return details, fmt.Errorf("failed to find build config: %v", err)
+ }
+ config = filepath.Join(params.KernelDir, strings.TrimSpace(string(configBytes)))
+ } else {
+ if err := c.runBuild(params.KernelDir, kernelConfig); err != nil {
+ return details, fmt.Errorf("failed to build kernel: %s", err)
+ }
+ if err := c.runBuild(params.KernelDir, moduleConfig); err != nil {
+ return details, fmt.Errorf("failed to build modules: %s", err)
+ }
+ config = filepath.Join(params.KernelDir, "out", "common", ".config")
+ }
+
+ buildDistDir := filepath.Join(params.KernelDir, "dist")
+ bzImage := filepath.Join(buildDistDir, "bzImage")
+ vmlinux := filepath.Join(buildDistDir, "vmlinux")
+ initramfs := filepath.Join(buildDistDir, "initramfs.img")
+
+ details.CompilerID, err = c.readCompiler(filepath.Join(buildDistDir, "kernel-headers.tar.gz"))
+ if err != nil {
+ return details, err
+ }
+
+ if err := embedFiles(params, func(mountDir string) error {
+ homeDir := filepath.Join(mountDir, "root")
+
+ if err := osutil.CopyFile(bzImage, filepath.Join(homeDir, "bzImage")); err != nil {
+ return err
+ }
+ if err := osutil.CopyFile(vmlinux, filepath.Join(homeDir, "vmlinux")); err != nil {
+ return err
+ }
+ if err := osutil.CopyFile(initramfs, filepath.Join(homeDir, "initramfs.img")); err != nil {
+ return err
+ }
+
+ return nil
+ }); err != nil {
+ return details, err
+ }
+
+ if err := osutil.CopyFile(vmlinux, filepath.Join(params.OutputDir, "obj", "vmlinux")); err != nil {
+ return details, err
+ }
+ if err := osutil.CopyFile(initramfs, filepath.Join(params.OutputDir, "obj", "initrd")); err != nil {
+ return details, err
+ }
+ if err := osutil.CopyFile(config, filepath.Join(params.OutputDir, "kernel.config")); err != nil {
+ return details, err
+ }
+
+ details.Signature, err = elfBinarySignature(vmlinux, params.Tracer)
+ if err != nil {
+ return details, fmt.Errorf("failed to generate signature: %s", err)
+ }
+
+ return details, nil
+}
+
+func (c cuttlefish) clean(kernelDir, targetArch string) error {
+ return osutil.RemoveAll(filepath.Join(kernelDir, "out"))
+}