aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/build/gvisor.go
blob: 861fced1ba8c31b74089291b138ee3774b613639 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// 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

import (
	"fmt"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/google/syzkaller/pkg/log"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/sys/targets"
)

type gvisor struct{}

var bazelTargetPath = regexp.MustCompile(`(?sm:.*^)\s*Outputs: \[(.*)\](?sm:$.*)`)

func (gvisor gvisor) build(params Params) (ImageDetails, error) {
	if params.Compiler == "" {
		params.Compiler = "bazel"
	}

	// Bring down bazel daemon right away. We don't need it running and consuming memory.
	defer osutil.RunCmd(10*time.Minute, params.KernelDir, params.Compiler, "shutdown")

	config := strings.Fields(string(params.Config))
	args := []string{}

	target := "//runsc:runsc"
	race := raceEnabled(config)
	if race {
		args = append(args, "--@io_bazel_rules_go//go/config:race")
		target = "//runsc:runsc-race"
	}
	if coverageEnabled(config) {
		coverageFiles := "//pkg/..."
		exclusions := []string{
			"//pkg/sentry/platform", "//pkg/ring0", // Breaks kvm.
			"//pkg/coverage:coverage", // Too slow.
		}
		if race {
			// These targets use go:norace, which is not
			// respected by coverage instrumentation. Race builds
			// will be instrumented with atomic coverage (using
			// sync/atomic.AddInt32), which will not work.
			exclusions = append(exclusions, []string{
				"//pkg/sleep:sleep",
				"//pkg/syncevent:syncevent",
			}...)
		}
		for _, f := range exclusions {
			coverageFiles += ",-" + f
		}
		args = append(args, []string{
			"--collect_code_coverage",
			"--instrumentation_filter=" + coverageFiles}...)
	}
	buildArgs := []string{"build", "--verbose_failures"}
	buildArgs = append(buildArgs, args...)
	buildArgs = append(buildArgs, target)
	log.Logf(0, "bazel: %v", buildArgs)
	// The 1 hour timeout is quite high. But we've seen false positives with 20 mins
	// on the first build after bazel/deps update. Also other gvisor instances running
	// on the same machine contribute to longer build times.
	if _, err := osutil.RunCmd(60*time.Minute, params.KernelDir, params.Compiler, buildArgs...); err != nil {
		return ImageDetails{}, err
	}

	// Find out a path to the runsc binary.
	aqueryArgs := append([]string{"aquery"}, args...)
	aqueryArgs = append(aqueryArgs, fmt.Sprintf("mnemonic(\"GoLink\", %s)", target))
	log.Logf(0, "bazel: %v", aqueryArgs)
	out, err := osutil.RunCmd(10*time.Minute, params.KernelDir, params.Compiler, aqueryArgs...)
	if err != nil {
		return ImageDetails{}, err
	}

	match := bazelTargetPath.FindSubmatch(out)
	if match == nil {
		return ImageDetails{}, fmt.Errorf("failed to find the runsc binary")
	}
	outBinary := filepath.Join(params.KernelDir, filepath.FromSlash(string(match[1])))

	if err := osutil.CopyFile(outBinary, filepath.Join(params.OutputDir, "image")); err != nil {
		return ImageDetails{}, err
	}
	sysTarget := targets.Get(params.TargetOS, params.TargetArch)
	return ImageDetails{}, osutil.CopyFile(outBinary, filepath.Join(params.OutputDir, "obj", sysTarget.KernelObject))
}

func (gvisor) clean(kernelDir, targetArch string) error {
	// Let's assume that bazel always properly handles build without cleaning (until proven otherwise).
	return nil
}

func coverageEnabled(config []string) bool {
	for _, flag := range config {
		if flag == "-cover" {
			return true
		}
	}
	return false
}

func raceEnabled(config []string) bool {
	for _, flag := range config {
		if flag == "-race" {
			return true
		}
	}
	return false
}