aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/runtest/run_test.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-04-30 12:15:22 +0200
committerDmitry Vyukov <dvyukov@google.com>2024-05-03 11:23:33 +0000
commitb385c6f4c3087f54a49d5dd38705a67133d07a87 (patch)
tree912b4b10228e8632b7fad2e79fb35107c155c0ef /pkg/runtest/run_test.go
parent65b976e25e618a5f1036a7aea76bc94553222905 (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.go66
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).