github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/ipc/ipc_test.go (about) 1 // Copyright 2015 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 ipc_test 5 6 import ( 7 "bytes" 8 "fmt" 9 "math/rand" 10 "runtime" 11 "testing" 12 "time" 13 14 "github.com/google/syzkaller/pkg/csource" 15 "github.com/google/syzkaller/pkg/flatrpc" 16 "github.com/google/syzkaller/pkg/image" 17 . "github.com/google/syzkaller/pkg/ipc" 18 "github.com/google/syzkaller/pkg/ipc/ipcconfig" 19 "github.com/google/syzkaller/pkg/osutil" 20 "github.com/google/syzkaller/pkg/testutil" 21 "github.com/google/syzkaller/prog" 22 _ "github.com/google/syzkaller/sys" 23 "github.com/google/syzkaller/sys/targets" 24 ) 25 26 func initTest(t *testing.T) (*prog.Target, rand.Source, int, bool, bool, targets.Timeouts) { 27 t.Parallel() 28 iters := 100 29 if testing.Short() { 30 iters = 10 31 } 32 target, err := prog.GetTarget(runtime.GOOS, runtime.GOARCH) 33 if err != nil { 34 t.Fatal(err) 35 } 36 cfg, _, err := ipcconfig.Default(target) 37 if err != nil { 38 t.Fatal(err) 39 } 40 rs := testutil.RandSource(t) 41 return target, rs, iters, cfg.UseShmem, cfg.UseForkServer, cfg.Timeouts 42 } 43 44 // TestExecutor runs all internal executor unit tests. 45 // We do it here because we already build executor binary here. 46 func TestExecutor(t *testing.T) { 47 t.Parallel() 48 for _, sysTarget := range targets.List[runtime.GOOS] { 49 sysTarget := targets.Get(runtime.GOOS, sysTarget.Arch) 50 t.Run(sysTarget.Arch, func(t *testing.T) { 51 if sysTarget.BrokenCompiler != "" { 52 t.Skipf("skipping, broken cross-compiler: %v", sysTarget.BrokenCompiler) 53 } 54 t.Parallel() 55 target, err := prog.GetTarget(runtime.GOOS, sysTarget.Arch) 56 if err != nil { 57 t.Fatal(err) 58 } 59 bin := csource.BuildExecutor(t, target, "../..") 60 // qemu-user may allow us to run some cross-arch binaries. 61 if _, err := osutil.RunCmd(time.Minute, "", bin, "test"); err != nil { 62 if sysTarget.Arch == runtime.GOARCH || sysTarget.VMArch == runtime.GOARCH { 63 t.Fatal(err) 64 } 65 t.Skipf("skipping, cross-arch binary failed: %v", err) 66 } 67 }) 68 } 69 } 70 71 func prepareTestProgram(target *prog.Target) *prog.Prog { 72 p := target.DataMmapProg() 73 if len(p.Calls) > 1 { 74 p.Calls[1].Props.Async = true 75 } 76 return p 77 } 78 79 func TestExecute(t *testing.T) { 80 target, _, _, useShmem, useForkServer, timeouts := initTest(t) 81 82 bin := csource.BuildExecutor(t, target, "../..") 83 84 flags := []flatrpc.ExecFlag{0, flatrpc.ExecFlagThreaded} 85 for _, flag := range flags { 86 t.Logf("testing flags 0x%x", flag) 87 cfg := &Config{ 88 Executor: bin, 89 UseShmem: useShmem, 90 UseForkServer: useForkServer, 91 Timeouts: timeouts, 92 } 93 env, err := MakeEnv(cfg, 0) 94 if err != nil { 95 t.Fatalf("failed to create env: %v", err) 96 } 97 defer env.Close() 98 99 for i := 0; i < 10; i++ { 100 p := prepareTestProgram(target) 101 opts := &ExecOpts{ 102 ExecFlags: flag, 103 } 104 output, info, hanged, err := env.Exec(opts, p) 105 if err != nil { 106 t.Fatalf("failed to run executor: %v", err) 107 } 108 if hanged { 109 t.Fatalf("program hanged:\n%s", output) 110 } 111 if len(info.Calls) != len(p.Calls) { 112 t.Fatalf("executed less calls (%v) than prog len(%v):\n%s", len(info.Calls), len(p.Calls), output) 113 } 114 if info.Calls[0].Errno != 0 { 115 t.Fatalf("simple call failed: %v\n%s", info.Calls[0].Errno, output) 116 } 117 if len(output) != 0 { 118 t.Fatalf("output on empty program") 119 } 120 } 121 } 122 } 123 124 func TestParallel(t *testing.T) { 125 target, _, _, useShmem, useForkServer, timeouts := initTest(t) 126 bin := csource.BuildExecutor(t, target, "../..") 127 cfg := &Config{ 128 Executor: bin, 129 UseShmem: useShmem, 130 UseForkServer: useForkServer, 131 Timeouts: timeouts, 132 } 133 const P = 10 134 errs := make(chan error, P) 135 for p := 0; p < P; p++ { 136 p := p 137 go func() { 138 env, err := MakeEnv(cfg, p) 139 if err != nil { 140 errs <- fmt.Errorf("failed to create env: %w", err) 141 return 142 } 143 defer func() { 144 env.Close() 145 errs <- err 146 }() 147 p := target.DataMmapProg() 148 opts := &ExecOpts{} 149 output, info, hanged, err := env.Exec(opts, p) 150 if err != nil { 151 err = fmt.Errorf("failed to run executor: %w", err) 152 return 153 } 154 if hanged { 155 err = fmt.Errorf("program hanged:\n%s", output) 156 return 157 } 158 if len(info.Calls) == 0 { 159 err = fmt.Errorf("no calls executed:\n%s", output) 160 return 161 } 162 if info.Calls[0].Errno != 0 { 163 err = fmt.Errorf("simple call failed: %v\n%s", info.Calls[0].Errno, output) 164 return 165 } 166 if len(output) != 0 { 167 err = fmt.Errorf("output on empty program") 168 return 169 } 170 }() 171 } 172 for p := 0; p < P; p++ { 173 if err := <-errs; err != nil { 174 t.Fatal(err) 175 } 176 } 177 } 178 179 func TestZlib(t *testing.T) { 180 t.Parallel() 181 target, err := prog.GetTarget(targets.TestOS, targets.TestArch64) 182 if err != nil { 183 t.Fatal(err) 184 } 185 sysTarget := targets.Get(target.OS, target.Arch) 186 if sysTarget.BrokenCompiler != "" { 187 t.Skipf("skipping, broken cross-compiler: %v", sysTarget.BrokenCompiler) 188 } 189 cfg, opts, err := ipcconfig.Default(target) 190 if err != nil { 191 t.Fatal(err) 192 } 193 opts.EnvFlags |= flatrpc.ExecEnvDebug 194 cfg.Executor = csource.BuildExecutor(t, target, "../..") 195 env, err := MakeEnv(cfg, 0) 196 if err != nil { 197 t.Fatalf("failed to create env: %v", err) 198 } 199 defer env.Close() 200 r := rand.New(testutil.RandSource(t)) 201 for i := 0; i < 10; i++ { 202 data := testutil.RandMountImage(r) 203 compressed := image.Compress(data) 204 text := fmt.Sprintf(`syz_compare_zlib(&(0x7f0000000000)="$%s", AUTO, &(0x7f0000800000)="$%s", AUTO)`, 205 image.EncodeB64(data), image.EncodeB64(compressed)) 206 p, err := target.Deserialize([]byte(text), prog.Strict) 207 if err != nil { 208 t.Fatalf("failed to deserialize empty program: %v", err) 209 } 210 output, info, _, err := env.Exec(opts, p) 211 if err != nil { 212 t.Fatalf("failed to run executor: %v", err) 213 } 214 if info.Calls[0].Errno != 0 { 215 t.Fatalf("data comparison failed: %v\n%s", info.Calls[0].Errno, output) 216 } 217 } 218 } 219 220 func TestExecutorCommonExt(t *testing.T) { 221 target, err := prog.GetTarget("test", "64_fork") 222 if err != nil { 223 t.Fatal(err) 224 } 225 sysTarget := targets.Get(target.OS, target.Arch) 226 if sysTarget.BrokenCompiler != "" { 227 t.Skipf("skipping, broken cross-compiler: %v", sysTarget.BrokenCompiler) 228 } 229 bin := csource.BuildExecutor(t, target, "../..", "-DSYZ_TEST_COMMON_EXT_EXAMPLE=1") 230 out, err := osutil.RunCmd(time.Minute, "", bin, "setup", "0") 231 if err != nil { 232 t.Fatal(err) 233 } 234 if !bytes.Contains(out, []byte("example setup_ext called")) { 235 t.Fatalf("setup_ext wasn't called:\n%s", out) 236 } 237 238 // The example setup_ext_test does: 239 // *(uint64*)(SYZ_DATA_OFFSET + 0x1234) = 0xbadc0ffee; 240 // The following program tests that that value is present at 0x1234. 241 test := `syz_compare(&(0x7f0000001234)="", 0x8, &(0x7f0000000000)=@blob="eeffc0ad0b000000", AUTO)` 242 p, err := target.Deserialize([]byte(test), prog.Strict) 243 if err != nil { 244 t.Fatal(err) 245 } 246 cfg, opts, err := ipcconfig.Default(target) 247 if err != nil { 248 t.Fatal(err) 249 } 250 cfg.Executor = bin 251 opts.EnvFlags |= flatrpc.ExecEnvDebug 252 env, err := MakeEnv(cfg, 0) 253 if err != nil { 254 t.Fatalf("failed to create env: %v", err) 255 } 256 defer env.Close() 257 _, info, _, err := env.Exec(opts, p) 258 if err != nil { 259 t.Fatal(err) 260 } 261 if call := info.Calls[0]; (call.Flags&CallFinished) == 0 || call.Errno != 0 { 262 t.Fatalf("bad call result: flags=%x errno=%v", call.Flags, call.Errno) 263 } 264 }