aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/build/gvisor.go
blob: ca28d89842d006e834f4f36cb1477d91b3f5a66e (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
// 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"
	"strings"
	"time"

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

type gvisor struct{}

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, err := parseGVisorConfig(params.Config)
	if err != nil {
		return ImageDetails{}, fmt.Errorf("cannot parse gVisor configuration: %w", err)
	}
	bazelOpts := "--verbose_failures"

	target := "//runsc:runsc"
	if config.Coverage {
		if config.Race {
			target = "//runsc:runsc_race_coverage"
		} else {
			target = "//runsc:runsc_coverage"
		}
	} else if config.Race {
		bazelOpts += " --config=race "
		target = "//runsc:runsc-race"
	}

	outBinary := filepath.Join(params.OutputDir, "image")
	cmd := osutil.Command("make", "copy",
		"DOCKER_BUILD=0",
		fmt.Sprintf("BAZEL_OPTIONS=%s", bazelOpts),
		fmt.Sprintf("TARGETS=%s", target),
		fmt.Sprintf("DESTINATION=%s", outBinary),
	)
	cmd.Dir = params.KernelDir

	log.Logf(0, "bazel copy: %v", cmd.Env)
	if _, err := osutil.Run(60*time.Minute, cmd); 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(params Params) error {
	// Let's assume that bazel always properly handles build without cleaning (until proven otherwise).
	return nil
}

// Known gVisor configuration flags.
const (
	gvisorFlagCover = "-cover"
	gvisorFlagRace  = "-race"
)

// gvisorConfig is a gVisor configuration.
type gvisorConfig struct {
	// Coverage represents whether code coverage is enabled.
	Coverage bool

	// Race represents whether race condition detection is enabled.
	Race bool
}

// parseGVisorConfig parses a set of flags into a `gvisorConfig`.
func parseGVisorConfig(config []byte) (gvisorConfig, error) {
	var cfg gvisorConfig
	for _, flag := range strings.Fields(string(config)) {
		switch flag {
		case gvisorFlagCover:
			cfg.Coverage = true
		case gvisorFlagRace:
			cfg.Race = true
		default:
			return cfg, fmt.Errorf("unknown gVisor configuration flag: %q", flag)
		}
	}
	return cfg, nil
}