github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/host/features.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 host
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/google/syzkaller/pkg/csource"
    13  	"github.com/google/syzkaller/pkg/flatrpc"
    14  	"github.com/google/syzkaller/pkg/ipc"
    15  	"github.com/google/syzkaller/pkg/log"
    16  	"github.com/google/syzkaller/pkg/osutil"
    17  	"github.com/google/syzkaller/prog"
    18  	"github.com/google/syzkaller/sys/targets"
    19  )
    20  
    21  // SetupFeatures enables and does any one-time setup for the requested features on the host.
    22  // Note: this can be called multiple times and must be idempotent.
    23  func SetupFeatures(target *prog.Target, executor string, mask flatrpc.Feature, flags csource.Features) (
    24  	[]*flatrpc.FeatureInfo, error) {
    25  	if noHostChecks(target) {
    26  		return nil, nil
    27  	}
    28  	var results []*flatrpc.FeatureInfo
    29  	resultC := make(chan *flatrpc.FeatureInfo)
    30  	for feat := range flatrpc.EnumNamesFeature {
    31  		feat := feat
    32  		if mask&feat == 0 {
    33  			continue
    34  		}
    35  		opt := ipc.FlatRPCFeaturesToCSource[feat]
    36  		if opt != "" && flags != nil && !flags["binfmt_misc"].Enabled {
    37  			continue
    38  		}
    39  		results = append(results, nil)
    40  		go setupFeature(executor, feat, resultC)
    41  	}
    42  	// Feature 0 setups common things that are not part of any feature.
    43  	setupFeature(executor, 0, nil)
    44  	for i := range results {
    45  		results[i] = <-resultC
    46  	}
    47  	return results, nil
    48  }
    49  
    50  func setupFeature(executor string, feat flatrpc.Feature, resultC chan *flatrpc.FeatureInfo) {
    51  	args := strings.Split(executor, " ")
    52  	executor = args[0]
    53  	args = append(args[1:], "setup", fmt.Sprint(uint64(feat)))
    54  	output, err := osutil.RunCmd(3*time.Minute, "", executor, args...)
    55  	log.Logf(1, "executor %v\n%s", args, bytes.ReplaceAll(output, []byte("SYZFAIL:"), nil))
    56  	outputStr := string(output)
    57  	if err == nil {
    58  		outputStr = ""
    59  	} else if outputStr == "" {
    60  		outputStr = err.Error()
    61  	}
    62  	needSetup := true
    63  	if strings.Contains(outputStr, "feature setup is not needed") {
    64  		needSetup = false
    65  		outputStr = ""
    66  	}
    67  	if resultC != nil {
    68  		resultC <- &flatrpc.FeatureInfo{
    69  			Id:        feat,
    70  			NeedSetup: needSetup,
    71  			Reason:    outputStr,
    72  		}
    73  	}
    74  }
    75  
    76  func noHostChecks(target *prog.Target) bool {
    77  	// HostFuzzer targets can't run Go binaries on the targets,
    78  	// so we actually run on the host on another OS. The same for targets.TestOS OS.
    79  	return targets.Get(target.OS, target.Arch).HostFuzzer || target.OS == targets.TestOS
    80  }