| // 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") |
| } |