1// Copyright 2018 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 contains helper functions for building kernels/images. 5package build 6 7import ( 8 "fmt" 9 "path/filepath" 10 "strings" 11 "time" 12 13 "github.com/google/syzkaller/pkg/osutil" 14) 15 16// Image creates a disk image for the specified OS/ARCH/VM. 17// Kernel is taken from kernelDir, userspace system is taken from userspaceDir. 18// If cmdlineFile is not empty, contents of the file are appended to the kernel command line. 19// If sysctlFile is not empty, contents of the file are appended to the image /etc/sysctl.conf. 20// Output is stored in outputDir and includes (everything except for image is optional): 21// - image: the image 22// - key: ssh key for the image 23// - kernel: kernel for injected boot 24// - initrd: initrd for injected boot 25// - kernel.config: actual kernel config used during build 26// - obj/: directory with kernel object files (e.g. vmlinux for linux) 27func Image(targetOS, targetArch, vmType, kernelDir, outputDir, compiler, userspaceDir, 28 cmdlineFile, sysctlFile string, config []byte) error { 29 builder, err := getBuilder(targetOS, targetArch, vmType) 30 if err != nil { 31 return err 32 } 33 if err := osutil.MkdirAll(filepath.Join(outputDir, "obj")); err != nil { 34 return err 35 } 36 if len(config) != 0 { 37 // Write kernel config early, so that it's captured on build failures. 38 if err := osutil.WriteFile(filepath.Join(outputDir, "kernel.config"), config); err != nil { 39 return fmt.Errorf("failed to write config file: %v", err) 40 } 41 } 42 return builder.build(targetArch, vmType, kernelDir, outputDir, compiler, userspaceDir, cmdlineFile, sysctlFile, config) 43} 44 45func Clean(targetOS, targetArch, vmType, kernelDir string) error { 46 builder, err := getBuilder(targetOS, targetArch, vmType) 47 if err != nil { 48 return err 49 } 50 return builder.clean(kernelDir) 51} 52 53type KernelBuildError struct { 54 *osutil.VerboseError 55} 56 57type builder interface { 58 build(targetArch, vmType, kernelDir, outputDir, compiler, userspaceDir, 59 cmdlineFile, sysctlFile string, config []byte) error 60 clean(kernelDir string) error 61} 62 63func getBuilder(targetOS, targetArch, vmType string) (builder, error) { 64 switch { 65 case targetOS == "linux" && targetArch == "amd64" && vmType == "gvisor": 66 return gvisor{}, nil 67 case targetOS == "linux" && targetArch == "amd64" && (vmType == "qemu" || vmType == "gce"): 68 return linux{}, nil 69 case targetOS == "fuchsia" && (targetArch == "amd64" || targetArch == "arm64") && vmType == "qemu": 70 return fuchsia{}, nil 71 case targetOS == "akaros" && targetArch == "amd64" && vmType == "qemu": 72 return akaros{}, nil 73 default: 74 return nil, fmt.Errorf("unsupported image type %v/%v/%v", targetOS, targetArch, vmType) 75 } 76} 77 78func CompilerIdentity(compiler string) (string, error) { 79 if compiler == "" { 80 return "", nil 81 } 82 arg := "--version" 83 if strings.HasSuffix(compiler, "bazel") { 84 arg = "" 85 } 86 output, err := osutil.RunCmd(time.Minute, "", compiler, arg) 87 if err != nil { 88 return "", err 89 } 90 for _, line := range strings.Split(string(output), "\n") { 91 if strings.Contains(line, "Extracting Bazel") { 92 continue 93 } 94 return strings.TrimSpace(line), nil 95 } 96 return "", fmt.Errorf("no output from compiler --version") 97} 98