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 }