github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/build/cuttlefish.go (about) 1 // Copyright 2022 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package build 5 6 import ( 7 "archive/tar" 8 "compress/gzip" 9 "fmt" 10 "io" 11 "os" 12 "path/filepath" 13 "strings" 14 "time" 15 16 "github.com/google/syzkaller/pkg/osutil" 17 ) 18 19 const ( 20 kernelConfig = "common/build.config.gki_kasan.x86_64" 21 moduleConfig = "common-modules/virtual-device/build.config.virtual_device_kasan.x86_64" 22 bazelTarget = "//common-modules/virtual-device:virtual_device_x86_64_dist" 23 ) 24 25 type cuttlefish struct{} 26 27 func (c cuttlefish) runBuild(kernelDir, buildConfig string) error { 28 cmd := osutil.Command("build/build.sh") 29 cmd.Dir = kernelDir 30 cmd.Env = append(cmd.Env, "OUT_DIR=out", "DIST_DIR=dist", fmt.Sprintf("BUILD_CONFIG=%s", buildConfig)) 31 32 _, err := osutil.Run(time.Hour, cmd) 33 return err 34 } 35 36 func (c cuttlefish) runBazel(kernelDir string) error { 37 cmd := osutil.Command("tools/bazel", "run", "--kasan", bazelTarget, "--", "--dist_dir=dist") 38 if err := osutil.Sandbox(cmd, true, false); err != nil { 39 return fmt.Errorf("failed to sandbox build command: %w", err) 40 } 41 cmd.Dir = kernelDir 42 _, err := osutil.Run(time.Hour, cmd) 43 return err 44 } 45 46 func (c cuttlefish) readCompiler(archivePath string) (string, error) { 47 f, err := os.Open(archivePath) 48 if err != nil { 49 return "", err 50 } 51 defer f.Close() 52 53 gr, err := gzip.NewReader(f) 54 if err != nil { 55 return "", err 56 } 57 defer gr.Close() 58 59 tr := tar.NewReader(gr) 60 61 h, err := tr.Next() 62 for ; err == nil; h, err = tr.Next() { 63 if filepath.Base(h.Name) == "compile.h" { 64 bytes, err := io.ReadAll(tr) 65 if err != nil { 66 return "", err 67 } 68 result := linuxCompilerRegexp.FindSubmatch(bytes) 69 if result == nil { 70 return "", fmt.Errorf("include/generated/compile.h does not contain build information") 71 } 72 73 return string(result[1]), nil 74 } 75 } 76 77 return "", fmt.Errorf("archive %s doesn't contain include/generated/compile.h", archivePath) 78 } 79 80 func (c cuttlefish) build(params Params) (ImageDetails, error) { 81 var details ImageDetails 82 83 if params.CmdlineFile != "" { 84 return details, fmt.Errorf("cmdline file is not supported for android cuttlefish images") 85 } 86 if params.SysctlFile != "" { 87 return details, fmt.Errorf("sysctl file is not supported for android cuttlefish images") 88 } 89 90 var config string 91 var err error 92 // Clean output directory if it exists. 93 if err := osutil.RemoveAll(filepath.Join(params.KernelDir, "out")); err != nil { 94 return details, fmt.Errorf("failed to clean before kernel build: %w", err) 95 } 96 // Default to build.sh if compiler is not specified. 97 if params.Compiler == "bazel" { 98 if err := c.runBazel(params.KernelDir); err != nil { 99 return details, fmt.Errorf("failed to build kernel: %w", err) 100 } 101 // Find the .config file; it is placed in a temporary output directory during the build. 102 cmd := osutil.Command("find", ".", "-regex", ".*virtual_device_x86_64_config.*/\\.config") 103 cmd.Dir = params.KernelDir 104 configBytes, err := osutil.Run(time.Minute, cmd) 105 if err != nil { 106 return details, fmt.Errorf("failed to find build config: %w", err) 107 } 108 config = filepath.Join(params.KernelDir, strings.TrimSpace(string(configBytes))) 109 } else { 110 if err := c.runBuild(params.KernelDir, kernelConfig); err != nil { 111 return details, fmt.Errorf("failed to build kernel: %w", err) 112 } 113 if err := c.runBuild(params.KernelDir, moduleConfig); err != nil { 114 return details, fmt.Errorf("failed to build modules: %w", err) 115 } 116 config = filepath.Join(params.KernelDir, "out", "common", ".config") 117 } 118 119 buildDistDir := filepath.Join(params.KernelDir, "dist") 120 bzImage := filepath.Join(buildDistDir, "bzImage") 121 vmlinux := filepath.Join(buildDistDir, "vmlinux") 122 initramfs := filepath.Join(buildDistDir, "initramfs.img") 123 124 details.CompilerID, err = c.readCompiler(filepath.Join(buildDistDir, "kernel-headers.tar.gz")) 125 if err != nil { 126 return details, err 127 } 128 129 if err := embedFiles(params, func(mountDir string) error { 130 homeDir := filepath.Join(mountDir, "root") 131 132 if err := osutil.CopyFile(bzImage, filepath.Join(homeDir, "bzImage")); err != nil { 133 return err 134 } 135 if err := osutil.CopyFile(vmlinux, filepath.Join(homeDir, "vmlinux")); err != nil { 136 return err 137 } 138 if err := osutil.CopyFile(initramfs, filepath.Join(homeDir, "initramfs.img")); err != nil { 139 return err 140 } 141 142 return nil 143 }); err != nil { 144 return details, err 145 } 146 147 if err := osutil.CopyFile(vmlinux, filepath.Join(params.OutputDir, "obj", "vmlinux")); err != nil { 148 return details, err 149 } 150 if err := osutil.CopyFile(initramfs, filepath.Join(params.OutputDir, "obj", "initrd")); err != nil { 151 return details, err 152 } 153 if err := osutil.CopyFile(config, filepath.Join(params.OutputDir, "kernel.config")); err != nil { 154 return details, err 155 } 156 157 details.Signature, err = elfBinarySignature(vmlinux, params.Tracer) 158 if err != nil { 159 return details, fmt.Errorf("failed to generate signature: %w", err) 160 } 161 162 return details, nil 163 } 164 165 func (c cuttlefish) clean(kernelDir, targetArch string) error { 166 if err := osutil.RemoveAll(filepath.Join(kernelDir, "out")); err != nil { 167 return err 168 } 169 return osutil.RemoveAll(filepath.Join(kernelDir, "dist")) 170 }