From 4f0d9df0078216bcadfc7d4a744a160a1d3659be Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 26 Nov 2024 15:25:16 +0100 Subject: 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. --- syz-manager/manager.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'syz-manager') 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)) } -- cgit mrf-deployment