• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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