diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2024-04-30 12:15:22 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2024-05-03 11:23:33 +0000 |
| commit | b385c6f4c3087f54a49d5dd38705a67133d07a87 (patch) | |
| tree | 912b4b10228e8632b7fad2e79fb35107c155c0ef /pkg/runtest/run_test.go | |
| parent | 65b976e25e618a5f1036a7aea76bc94553222905 (diff) | |
tools/syz-runtest: switch to the generic program execution
syz-runtest effectively implemented the same execute program/return result
mechanism we use now for normal fuzzing.
So extend the general mechanism to allow collecting output/errors,
repeating program, and executing a precompiled binary as a test.
And switch syz-runtest to the general mechanism.
This removes another chunk of code from syz-fuzzer.
Diffstat (limited to 'pkg/runtest/run_test.go')
| -rw-r--r-- | pkg/runtest/run_test.go | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/pkg/runtest/run_test.go b/pkg/runtest/run_test.go index 5cbbca865..00bf343d7 100644 --- a/pkg/runtest/run_test.go +++ b/pkg/runtest/run_test.go @@ -4,15 +4,18 @@ package runtest import ( + "errors" "flag" "fmt" "os" "path/filepath" "runtime" "testing" + "time" "github.com/google/syzkaller/pkg/csource" "github.com/google/syzkaller/pkg/host" + "github.com/google/syzkaller/pkg/ipc" "github.com/google/syzkaller/pkg/osutil" "github.com/google/syzkaller/pkg/testutil" "github.com/google/syzkaller/prog" @@ -84,7 +87,11 @@ func test(t *testing.T, sysTarget *targets.Target) { requests := make(chan *RunRequest, 2*runtime.GOMAXPROCS(0)) go func() { for req := range requests { - RunTest(req, executor) + if req.Bin != "" { + runTestC(req) + } else { + runTest(req, executor) + } close(req.Done) } }() @@ -108,6 +115,63 @@ func test(t *testing.T, sysTarget *targets.Target) { } } +func runTest(req *RunRequest, executor string) { + cfg := new(ipc.Config) + sysTarget := targets.Get(req.P.Target.OS, req.P.Target.Arch) + cfg.UseShmem = sysTarget.ExecutorUsesShmem + cfg.UseForkServer = sysTarget.ExecutorUsesForkServer + cfg.Timeouts = sysTarget.Timeouts(1) + cfg.Executor = executor + env, err := ipc.MakeEnv(cfg, 0) + if err != nil { + req.Err = fmt.Errorf("failed to create ipc env: %w", err) + return + } + defer env.Close() + for run := 0; run < req.Repeat; run++ { + if run%2 == 0 { + // Recreate Env every few iterations, this allows to cover more paths. + env.ForceRestart() + } + output, info, hanged, err := env.Exec(&req.Opts, req.P) + req.Output = append(req.Output, output...) + if err != nil { + req.Err = fmt.Errorf("run %v: failed to run: %w", run, err) + return + } + if hanged { + req.Err = fmt.Errorf("run %v: hanged", run) + return + } + if run == 0 { + req.Info = *info + } else { + req.Info.Calls = append(req.Info.Calls, info.Calls...) + } + } +} + +func runTestC(req *RunRequest) { + tmpDir, err := os.MkdirTemp("", "syz-runtest") + if err != nil { + req.Err = fmt.Errorf("failed to create temp dir: %w", err) + return + } + defer os.RemoveAll(tmpDir) + cmd := osutil.Command(req.Bin) + cmd.Dir = tmpDir + // Tell ASAN to not mess with our NONFAILING. + cmd.Env = append(append([]string{}, os.Environ()...), "ASAN_OPTIONS=handle_segv=0 allow_user_segv_handler=1") + req.Output, req.Err = osutil.Run(20*time.Second, cmd) + var verr *osutil.VerboseError + if errors.As(req.Err, &verr) { + // The process can legitimately do something like exit_group(1). + // So we ignore the error and rely on the rest of the checks (e.g. syscall return values). + req.Err = nil + req.Output = verr.Output + } +} + func TestParsing(t *testing.T) { t.Parallel() // Test only one target in race mode (we have gazillion of auto-generated Linux test). |
