// 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 contains helper functions for building kernels/images. package build import ( "fmt" "path/filepath" "strings" "time" "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 (everything except for image is optional): // - image: the image // - key: ssh key for the image // - kernel: kernel for injected boot // - initrd: initrd for injected boot // - 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 } if err := osutil.MkdirAll(filepath.Join(outputDir, "obj")); err != nil { return err } if len(config) != 0 { // Write kernel config early, so that it's captured on build failures. if err := osutil.WriteFile(filepath.Join(outputDir, "kernel.config"), config); err != nil { return fmt.Errorf("failed to write config file: %v", 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 case targetOS == "fuchsia" && (targetArch == "amd64" || targetArch == "arm64") && vmType == "qemu": return fuchsia{}, nil case targetOS == "akaros" && targetArch == "amd64" && vmType == "qemu": return akaros{}, nil default: return nil, fmt.Errorf("unsupported image type %v/%v/%v", targetOS, targetArch, vmType) } } func CompilerIdentity(compiler string) (string, error) { if compiler == "" { return "", nil } arg := "--version" if strings.HasSuffix(compiler, "bazel") { arg = "" } output, err := osutil.RunCmd(time.Minute, "", compiler, arg) if err != nil { return "", err } for _, line := range strings.Split(string(output), "\n") { if strings.Contains(line, "Extracting Bazel") { continue } return strings.TrimSpace(line), nil } return "", fmt.Errorf("no output from compiler --version") }