github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/build/gvisor.go (about)

     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
     5  
     6  import (
     7  	"fmt"
     8  	"path/filepath"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/google/syzkaller/pkg/log"
    13  	"github.com/google/syzkaller/pkg/osutil"
    14  	"github.com/google/syzkaller/sys/targets"
    15  )
    16  
    17  type gvisor struct{}
    18  
    19  func (gvisor gvisor) build(params Params) (ImageDetails, error) {
    20  	if params.Compiler == "" {
    21  		params.Compiler = "bazel"
    22  	}
    23  
    24  	// Bring down bazel daemon right away. We don't need it running and consuming memory.
    25  	defer osutil.RunCmd(10*time.Minute, params.KernelDir, params.Compiler, "shutdown")
    26  
    27  	config, err := parseGVisorConfig(params.Config)
    28  	if err != nil {
    29  		return ImageDetails{}, fmt.Errorf("cannot parse gVisor configuration: %w", err)
    30  	}
    31  	bazelOpts := "--verbose_failures"
    32  
    33  	target := "//runsc:runsc"
    34  	if config.Coverage {
    35  		if config.Race {
    36  			target = "//runsc:runsc_race_coverage"
    37  		} else {
    38  			target = "//runsc:runsc_coverage"
    39  		}
    40  	} else if config.Race {
    41  		bazelOpts += " --config=race "
    42  		target = "//runsc:runsc-race"
    43  	}
    44  
    45  	outBinary := filepath.Join(params.OutputDir, "image")
    46  	cmd := osutil.Command("make", "copy",
    47  		"DOCKER_BUILD=0",
    48  		fmt.Sprintf("BAZEL_OPTIONS=%s", bazelOpts),
    49  		fmt.Sprintf("TARGETS=%s", target),
    50  		fmt.Sprintf("DESTINATION=%s", outBinary),
    51  	)
    52  	cmd.Dir = params.KernelDir
    53  
    54  	log.Logf(0, "bazel copy: %v", cmd.Env)
    55  	if _, err := osutil.Run(60*time.Minute, cmd); err != nil {
    56  		return ImageDetails{}, err
    57  	}
    58  
    59  	sysTarget := targets.Get(params.TargetOS, params.TargetArch)
    60  	return ImageDetails{}, osutil.CopyFile(outBinary, filepath.Join(params.OutputDir, "obj", sysTarget.KernelObject))
    61  }
    62  
    63  func (gvisor) clean(params Params) error {
    64  	// Let's assume that bazel always properly handles build without cleaning (until proven otherwise).
    65  	return nil
    66  }
    67  
    68  // Known gVisor configuration flags.
    69  const (
    70  	gvisorFlagCover = "-cover"
    71  	gvisorFlagRace  = "-race"
    72  )
    73  
    74  // gvisorConfig is a gVisor configuration.
    75  type gvisorConfig struct {
    76  	// Coverage represents whether code coverage is enabled.
    77  	Coverage bool
    78  
    79  	// Race represents whether race condition detection is enabled.
    80  	Race bool
    81  }
    82  
    83  // parseGVisorConfig parses a set of flags into a `gvisorConfig`.
    84  func parseGVisorConfig(config []byte) (gvisorConfig, error) {
    85  	var cfg gvisorConfig
    86  	for _, flag := range strings.Fields(string(config)) {
    87  		switch flag {
    88  		case gvisorFlagCover:
    89  			cfg.Coverage = true
    90  		case gvisorFlagRace:
    91  			cfg.Race = true
    92  		default:
    93  			return cfg, fmt.Errorf("unknown gVisor configuration flag: %q", flag)
    94  		}
    95  	}
    96  	return cfg, nil
    97  }