diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2024-11-26 15:25:16 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2024-11-27 10:28:33 +0000 |
| commit | 4f0d9df0078216bcadfc7d4a744a160a1d3659be (patch) | |
| tree | 551a402090bd19e9d98e678dc28a6d2d19d3944b /syz-manager | |
| parent | 52b38cc1f0ef7be017dc51c45e16a1054254f95f (diff) | |
pkg/ifaceprobe: add package
Package ifaceprobe implements dynamic component of automatic kernel interface extraction.
Currently it discovers all /{dev,sys,proc} files, and collects coverage for open/read/write/mmap/ioctl
syscalls on these files. Later this allows to build file path <-> file_operations mapping.
I've tried 2 other approaches:
1. Immediately map file to file_operations callbacks similar to tools/fops_probe,
and export only that. This required lots of hardcoding of kernel function/file
names, did not work well in all cases, and presumably would produce more
maintanance in future.
2. Automatically infer what kernel functions are common, and which correspond
to file_operations callbacks by first collecting coverage for all files/programs,
and then counting how many times wach PC is encountered in combined coverage.
Presumably common functions (SYS_read, vfs_read) will be present in most/all traces,
while the actual file_operations callback will be present in only one/few traces.
This also did not work well and produced lots of bugs where common functions
were somehow called in few programs, or common file_operations callbacks were
called in too many traces.
Diffstat (limited to 'syz-manager')
| -rw-r--r-- | syz-manager/manager.go | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/syz-manager/manager.go b/syz-manager/manager.go index aed721a79..3b6072629 100644 --- a/syz-manager/manager.go +++ b/syz-manager/manager.go @@ -30,6 +30,7 @@ import ( "github.com/google/syzkaller/pkg/fuzzer" "github.com/google/syzkaller/pkg/fuzzer/queue" "github.com/google/syzkaller/pkg/gce" + "github.com/google/syzkaller/pkg/ifaceprobe" "github.com/google/syzkaller/pkg/log" "github.com/google/syzkaller/pkg/manager" "github.com/google/syzkaller/pkg/mgrconfig" @@ -154,6 +155,20 @@ var ( Description: `run unit tests Run sys/os/test/* tests in various modes and print results.`, } + ModeIfaceProbe = &Mode{ + Name: "iface-probe", + Description: `run dynamic part of kernel interface auto-extraction + When the probe is finished, manager writes the result to workdir/interfaces.json file and exits.`, + CheckConfig: func(cfg *mgrconfig.Config) error { + if cfg.Snapshot { + return fmt.Errorf("snapshot mode is not supported") + } + if cfg.Sandbox != "none" { + return fmt.Errorf("sandbox \"%v\" is not supported (only \"none\")", cfg.Sandbox) + } + return nil + }, + } modes = []*Mode{ ModeFuzzing, @@ -161,6 +176,7 @@ var ( ModeCorpusTriage, ModeCorpusRun, ModeRunTests, + ModeIfaceProbe, } ) @@ -285,6 +301,9 @@ func RunManager(mode *Mode, cfg *mgrconfig.Config) { Stats: mgr.servStats, Debug: *flagDebug, } + if mode == ModeIfaceProbe { + rpcCfg.CheckGlobs = ifaceprobe.Globs() + } mgr.serv, err = rpcserver.New(rpcCfg) if err != nil { log.Fatalf("failed to create rpc server: %v", err) @@ -1164,6 +1183,17 @@ func (mgr *Manager) MachineChecked(info *flatrpc.InfoRequest, features flatrpc.F mgr.exit("tests") }() return ctx + } else if mgr.mode == ModeIfaceProbe { + exec := queue.Plain() + go func() { + res, err := ifaceprobe.Run(vm.ShutdownCtx(), mgr.cfg, exec, info) + if err != nil { + log.Fatalf("interface probing failed: %v", err) + } + mgr.saveJSON("interfaces.json", res) + mgr.exit("interface probe") + }() + return exec } panic(fmt.Sprintf("unexpected mode %q", mgr.mode.Name)) } |
