github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/syz-fuzzer/testing.go (about)

     1  // Copyright 2017 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 main
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"net"
    10  	"strings"
    11  	"time"
    12  
    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  )
    19  
    20  type checkArgs struct {
    21  	target         *prog.Target
    22  	sandbox        string
    23  	gitRevision    string
    24  	targetRevision string
    25  	ipcConfig      *ipc.Config
    26  	ipcExecOpts    *ipc.ExecOpts
    27  }
    28  
    29  func testImage(hostAddr string, args *checkArgs) {
    30  	// gVisor uses "stdin" for communication, which is not a real tcp address.
    31  	if hostAddr != "stdin" {
    32  		log.Logf(0, "connecting to host at %v", hostAddr)
    33  		timeout := time.Minute * args.ipcConfig.Timeouts.Scale
    34  		conn, err := net.DialTimeout("tcp", hostAddr, timeout)
    35  		if err != nil {
    36  			log.SyzFatalf("failed to connect to host: %v", err)
    37  		}
    38  		conn.Close()
    39  	}
    40  	if err := checkRevisions(args); err != nil {
    41  		log.SyzFatal(err)
    42  	}
    43  	if err := checkSimpleProgram(args); err != nil {
    44  		log.SyzFatal(err)
    45  	}
    46  }
    47  
    48  func checkRevisions(args *checkArgs) error {
    49  	log.Logf(0, "checking revisions...")
    50  	arch, syzRev, gitRev, err := executorVersion(args.ipcConfig.Executor)
    51  	if err != nil {
    52  		return err
    53  	}
    54  	if args.target.Arch != arch {
    55  		return fmt.Errorf("mismatching target/executor arches: %v vs %v", args.target.Arch, arch)
    56  	}
    57  	if prog.GitRevision != gitRev {
    58  		return fmt.Errorf("mismatching fuzzer/executor git revisions: %v vs %v",
    59  			prog.GitRevision, gitRev)
    60  	}
    61  	if args.gitRevision != prog.GitRevision {
    62  		return fmt.Errorf("mismatching manager/fuzzer git revisions: %v vs %v",
    63  			args.gitRevision, prog.GitRevision)
    64  	}
    65  	if args.target.Revision != syzRev {
    66  		return fmt.Errorf("mismatching fuzzer/executor system call descriptions: %v vs %v",
    67  			args.target.Revision, syzRev)
    68  	}
    69  	if args.target.Revision != args.targetRevision {
    70  		return fmt.Errorf("mismatching fuzzer/manager system call descriptions: %v vs %v",
    71  			args.target.Revision, args.targetRevision)
    72  	}
    73  	return nil
    74  }
    75  
    76  func executorVersion(bin string) (string, string, string, error) {
    77  	args := strings.Split(bin, " ")
    78  	args = append(args, "version")
    79  	cmd := osutil.Command(args[0], args[1:]...)
    80  	cmd.Stderr = io.Discard
    81  	if _, err := cmd.StdinPipe(); err != nil { // for the case executor is wrapped with ssh
    82  		return "", "", "", err
    83  	}
    84  	out, err := osutil.Run(time.Minute, cmd)
    85  	if err != nil {
    86  		return "", "", "", fmt.Errorf("failed to run executor version: %w", err)
    87  	}
    88  	// Executor returns OS, arch, descriptions hash, git revision.
    89  	vers := strings.Split(strings.TrimSpace(string(out)), " ")
    90  	if len(vers) != 4 {
    91  		return "", "", "", fmt.Errorf("executor version returned bad result: %q", string(out))
    92  	}
    93  	return vers[1], vers[2], vers[3], nil
    94  }
    95  
    96  func checkSimpleProgram(args *checkArgs) error {
    97  	log.Logf(0, "testing simple program...")
    98  	env, err := ipc.MakeEnv(args.ipcConfig, 0)
    99  	if err != nil {
   100  		return fmt.Errorf("failed to create ipc env: %w", err)
   101  	}
   102  	defer env.Close()
   103  	p := args.target.DataMmapProg()
   104  	output, info, hanged, err := env.Exec(args.ipcExecOpts, p)
   105  	if err != nil {
   106  		return fmt.Errorf("program execution failed: %w\n%s", err, output)
   107  	}
   108  	if hanged {
   109  		return fmt.Errorf("program hanged:\n%s", output)
   110  	}
   111  	if len(info.Calls) == 0 {
   112  		return fmt.Errorf("no calls executed:\n%s", output)
   113  	}
   114  	if info.Calls[0].Errno != 0 {
   115  		return fmt.Errorf("simple call failed: %+v\n%s", info.Calls[0], output)
   116  	}
   117  	if args.ipcExecOpts.EnvFlags&flatrpc.ExecEnvSignal != 0 && len(info.Calls[0].Signal) < 2 {
   118  		return fmt.Errorf("got no coverage:\n%s", output)
   119  	}
   120  	return nil
   121  }