aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-11-26 12:01:29 +0100
committerDmitry Vyukov <dvyukov@google.com>2024-11-26 11:32:06 +0000
commit5f6d557d4454398c38d85f6774152d5e0a4436d7 (patch)
tree9d5fbc2f1fe2c8ef08c64ff0a4c511ddd41bc3fa
parent7de7a5ecf43a5c41b5170d0cb70cb744fdf9de9f (diff)
pkg/rpcserver: refactoring in preparation for dynamic interface extraction
Few assorted changes to reduce future diffs: - add rpcserver.RemoteConfig similar to LocalConfig (there are too many parameters) - add CheckGlobs to requesting additional globs from VMs - pass whole InfoRequest to the MachineChecked callback so that it's possible to read globs information - add per-mode config checking in the manager - add Manager.saveJson helper
-rw-r--r--pkg/rpcserver/local.go3
-rw-r--r--pkg/rpcserver/mocks/Manager.go10
-rw-r--r--pkg/rpcserver/rpcserver.go40
-rw-r--r--pkg/rpcserver/rpcserver_test.go13
-rw-r--r--syz-manager/manager.go37
-rw-r--r--tools/syz-diff/diff.go10
6 files changed, 79 insertions, 34 deletions
diff --git a/pkg/rpcserver/local.go b/pkg/rpcserver/local.go
index 5faa8334b..c8052138a 100644
--- a/pkg/rpcserver/local.go
+++ b/pkg/rpcserver/local.go
@@ -112,7 +112,8 @@ type local struct {
setupDone chan bool
}
-func (ctx *local) MachineChecked(features flatrpc.Feature, syscalls map[*prog.Syscall]bool) queue.Source {
+func (ctx *local) MachineChecked(info *flatrpc.InfoRequest, features flatrpc.Feature,
+ syscalls map[*prog.Syscall]bool) queue.Source {
<-ctx.setupDone
ctx.serv.TriagedCorpus()
return ctx.cfg.MachineChecked(features, syscalls)
diff --git a/pkg/rpcserver/mocks/Manager.go b/pkg/rpcserver/mocks/Manager.go
index 810b5028f..0c14c8c9f 100644
--- a/pkg/rpcserver/mocks/Manager.go
+++ b/pkg/rpcserver/mocks/Manager.go
@@ -72,17 +72,17 @@ func (_m *Manager) CoverageFilter(modules []*vminfo.KernelModule) []uint64 {
return r0
}
-// MachineChecked provides a mock function with given fields: features, syscalls
-func (_m *Manager) MachineChecked(features flatrpc.Feature, syscalls map[*prog.Syscall]bool) queue.Source {
- ret := _m.Called(features, syscalls)
+// MachineChecked provides a mock function with given fields: info, features, syscalls
+func (_m *Manager) MachineChecked(info *flatrpc.InfoRequestRawT, features flatrpc.Feature, syscalls map[*prog.Syscall]bool) queue.Source {
+ ret := _m.Called(info, features, syscalls)
if len(ret) == 0 {
panic("no return value specified for MachineChecked")
}
var r0 queue.Source
- if rf, ok := ret.Get(0).(func(flatrpc.Feature, map[*prog.Syscall]bool) queue.Source); ok {
- r0 = rf(features, syscalls)
+ if rf, ok := ret.Get(0).(func(*flatrpc.InfoRequestRawT, flatrpc.Feature, map[*prog.Syscall]bool) queue.Source); ok {
+ r0 = rf(info, features, syscalls)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(queue.Source)
diff --git a/pkg/rpcserver/rpcserver.go b/pkg/rpcserver/rpcserver.go
index 69fd9e179..c064e6938 100644
--- a/pkg/rpcserver/rpcserver.go
+++ b/pkg/rpcserver/rpcserver.go
@@ -48,15 +48,26 @@ type Config struct {
DebugTimeouts bool
Procs int
Slowdown int
- pcBase uint64
- localModules []*vminfo.KernelModule
+ // Extra globs that will be requested during machine checking,
+ // and will be passed to MachineChecked callback.
+ CheckGlobs []string
+ pcBase uint64
+ localModules []*vminfo.KernelModule
+}
+
+type RemoteConfig struct {
+ *mgrconfig.Config
+ Manager Manager
+ Stats Stats
+ CheckGlobs []string
+ Debug bool
}
//go:generate ../../tools/mockery.sh --name Manager --output ./mocks
type Manager interface {
MaxSignal() signal.Signal
BugFrames() (leaks []string, races []string)
- MachineChecked(features flatrpc.Feature, syscalls map[*prog.Syscall]bool) queue.Source
+ MachineChecked(info *flatrpc.InfoRequest, features flatrpc.Feature, syscalls map[*prog.Syscall]bool) queue.Source
CoverageFilter(modules []*vminfo.KernelModule) []uint64
}
@@ -129,11 +140,11 @@ func NewNamedStats(name string) Stats {
}
}
-func New(cfg *mgrconfig.Config, mgr Manager, stats Stats, debug bool) (Server, error) {
+func New(cfg *RemoteConfig) (Server, error) {
var pcBase uint64
if cfg.KernelObj != "" {
var err error
- pcBase, err = cover.GetPCBase(cfg)
+ pcBase, err = cover.GetPCBase(cfg.Config)
if err != nil {
return nil, err
}
@@ -152,12 +163,12 @@ func New(cfg *mgrconfig.Config, mgr Manager, stats Stats, debug bool) (Server, e
VMType: cfg.Type,
Features: features,
Syscalls: cfg.Syscalls,
- Debug: debug,
+ Debug: cfg.Debug,
Cover: cfg.Cover,
Sandbox: sandbox,
SandboxArg: cfg.SandboxArg,
},
- Stats: stats,
+ Stats: cfg.Stats,
VMArch: cfg.TargetVMArch,
RPC: cfg.RPC,
VMLess: cfg.VMLess,
@@ -170,7 +181,8 @@ func New(cfg *mgrconfig.Config, mgr Manager, stats Stats, debug bool) (Server, e
Slowdown: cfg.Timeouts.Slowdown,
pcBase: pcBase,
localModules: cfg.LocalModules,
- }, mgr), nil
+ CheckGlobs: cfg.CheckGlobs,
+ }, cfg.Manager), nil
}
func newImpl(ctx context.Context, cfg *Config, mgr Manager) *server {
@@ -268,7 +280,7 @@ func (serv *server) handleRunnerConn(runner *Runner, conn *flatrpc.Conn) error {
opts.Features = serv.setupFeatures
} else {
opts.Files = append(opts.Files, serv.checker.CheckFiles()...)
- opts.Globs = serv.target.RequiredGlobs()
+ opts.Globs = append(serv.target.RequiredGlobs(), serv.cfg.CheckGlobs...)
opts.Features = serv.cfg.Features
}
@@ -321,7 +333,7 @@ func (serv *server) handleMachineInfo(infoReq *flatrpc.InfoRequestRawT) (handsha
}
// Now execute check programs.
go func() {
- if err := serv.runCheck(infoReq.Files, infoReq.Features); err != nil {
+ if err := serv.runCheck(infoReq); err != nil {
log.Fatalf("check failed: %v", err)
}
}()
@@ -370,20 +382,20 @@ func checkRevisions(a *flatrpc.ConnectRequest, target *prog.Target) error {
return nil
}
-func (serv *server) runCheck(checkFilesInfo []*flatrpc.FileInfo, checkFeatureInfo []*flatrpc.FeatureInfo) error {
- enabledCalls, disabledCalls, features, checkErr := serv.checker.Run(checkFilesInfo, checkFeatureInfo)
+func (serv *server) runCheck(info *flatrpc.InfoRequest) error {
+ enabledCalls, disabledCalls, features, checkErr := serv.checker.Run(info.Files, info.Features)
enabledCalls, transitivelyDisabled := serv.target.TransitivelyEnabledCalls(enabledCalls)
// Note: need to print disbled syscalls before failing due to an error.
// This helps to debug "all system calls are disabled".
if serv.cfg.PrintMachineCheck {
- serv.printMachineCheck(checkFilesInfo, enabledCalls, disabledCalls, transitivelyDisabled, features)
+ serv.printMachineCheck(info.Files, enabledCalls, disabledCalls, transitivelyDisabled, features)
}
if checkErr != nil {
return checkErr
}
enabledFeatures := features.Enabled()
serv.setupFeatures = features.NeedSetup()
- newSource := serv.mgr.MachineChecked(enabledFeatures, enabledCalls)
+ newSource := serv.mgr.MachineChecked(info, enabledFeatures, enabledCalls)
serv.baseSource.Store(newSource)
serv.checkDone.Store(true)
return nil
diff --git a/pkg/rpcserver/rpcserver_test.go b/pkg/rpcserver/rpcserver_test.go
index 760ae5e13..a885ad720 100644
--- a/pkg/rpcserver/rpcserver_test.go
+++ b/pkg/rpcserver/rpcserver_test.go
@@ -80,7 +80,11 @@ func TestNew(t *testing.T) {
cfg.Target, err = prog.GetTarget(cfg.TargetOS, cfg.TargetArch)
assert.NoError(t, err)
- serv, err := New(cfg, nil, NewStats(), tt.debug)
+ serv, err := New(&RemoteConfig{
+ Config: cfg,
+ Stats: NewStats(),
+ Debug: tt.debug,
+ })
if tt.expectedErr != nil {
assert.Equal(t, tt.expectedErr, err)
} else if tt.expectsErr {
@@ -195,7 +199,12 @@ func TestHandleConn(t *testing.T) {
cfg.Target.Revision = tt.req.SyzRevision
assert.NoError(t, err)
- s, err := New(cfg, managerMock, NewStats(), debug)
+ s, err := New(&RemoteConfig{
+ Config: cfg,
+ Manager: managerMock,
+ Stats: NewStats(),
+ Debug: debug,
+ })
assert.NoError(t, err)
serv := s.(*server)
diff --git a/syz-manager/manager.go b/syz-manager/manager.go
index 4feb3214b..aed721a79 100644
--- a/syz-manager/manager.go
+++ b/syz-manager/manager.go
@@ -118,6 +118,7 @@ type Mode struct {
ExitAfterMachineCheck bool // exit with 0 status when machine check is done
// Exit with non-zero status and save the report to workdir/report.json if any kernel crash happens.
FailOnCrashes bool
+ CheckConfig func(cfg *mgrconfig.Config) error
}
var (
@@ -211,6 +212,11 @@ func main() {
flag.PrintDefaults()
log.Fatalf("unknown mode: %v", *flagMode)
}
+ if mode.CheckConfig != nil {
+ if err := mode.CheckConfig(cfg); err != nil {
+ log.Fatalf("%v mode: %v", mode.Name, err)
+ }
+ }
if !mode.UseDashboard {
cfg.DashboardClient = ""
cfg.HubClient = ""
@@ -273,7 +279,13 @@ func RunManager(mode *Mode, cfg *mgrconfig.Config) {
// Create RPC server for fuzzers.
mgr.servStats = rpcserver.NewStats()
- mgr.serv, err = rpcserver.New(mgr.cfg, mgr, mgr.servStats, *flagDebug)
+ rpcCfg := &rpcserver.RemoteConfig{
+ Config: mgr.cfg,
+ Manager: mgr,
+ Stats: mgr.servStats,
+ Debug: *flagDebug,
+ }
+ mgr.serv, err = rpcserver.New(rpcCfg)
if err != nil {
log.Fatalf("failed to create rpc server: %v", err)
}
@@ -659,13 +671,7 @@ func (mgr *Manager) saveCrash(crash *manager.Crash) bool {
log.Logf(0, "VM %v: crash: %v%v", crash.InstanceIndex, crash.Title, flags)
if mgr.mode.FailOnCrashes {
- data, err := json.Marshal(crash.Report)
- if err != nil {
- log.Fatalf("failed to serialize crash report: %v", err)
- }
- if err := osutil.WriteFile(filepath.Join(mgr.cfg.Workdir, "report.json"), data); err != nil {
- log.Fatal(err)
- }
+ mgr.saveJSON("report.json", crash.Report)
log.Fatalf("kernel crashed in smoke testing mode, exiting")
}
@@ -719,6 +725,16 @@ func (mgr *Manager) saveCrash(crash *manager.Crash) bool {
return mgr.NeedRepro(crash)
}
+func (mgr *Manager) saveJSON(filename string, object any) {
+ data, err := json.MarshalIndent(object, "", "\t")
+ if err != nil {
+ log.Fatalf("failed to serialize json data: %v", err)
+ }
+ if err := osutil.WriteFile(filepath.Join(mgr.cfg.Workdir, filename), data); err != nil {
+ log.Fatal(err)
+ }
+}
+
func (mgr *Manager) needLocalRepro(crash *manager.Crash) bool {
if !mgr.cfg.Reproduce || crash.Corrupted || crash.Suppressed {
return false
@@ -1039,12 +1055,13 @@ func (mgr *Manager) BugFrames() (leaks, races []string) {
return
}
-func (mgr *Manager) MachineChecked(features flatrpc.Feature, enabledSyscalls map[*prog.Syscall]bool) queue.Source {
+func (mgr *Manager) MachineChecked(info *flatrpc.InfoRequest, features flatrpc.Feature,
+ enabledSyscalls map[*prog.Syscall]bool) queue.Source {
if len(enabledSyscalls) == 0 {
log.Fatalf("all system calls are disabled")
}
if mgr.mode.ExitAfterMachineCheck {
- mgr.exit("done")
+ mgr.exit(mgr.mode.Name)
}
mgr.mu.Lock()
diff --git a/tools/syz-diff/diff.go b/tools/syz-diff/diff.go
index 6549aed70..a7609fb2a 100644
--- a/tools/syz-diff/diff.go
+++ b/tools/syz-diff/diff.go
@@ -273,7 +273,12 @@ func setup(ctx context.Context, name string, cfg *mgrconfig.Config) *kernelConte
log.Fatalf("failed to create reporter for %q: %v", name, err)
}
- kernelCtx.serv, err = rpcserver.New(cfg, kernelCtx, kernelCtx.servStats, *flagDebug)
+ kernelCtx.serv, err = rpcserver.New(&rpcserver.RemoteConfig{
+ Config: cfg,
+ Manager: kernelCtx,
+ Stats: kernelCtx.servStats,
+ Debug: *flagDebug,
+ })
if err != nil {
log.Fatalf("failed to create rpc server for %q: %v", name, err)
}
@@ -305,7 +310,8 @@ func (kc *kernelContext) BugFrames() (leaks, races []string) {
return nil, nil
}
-func (kc *kernelContext) MachineChecked(features flatrpc.Feature, syscalls map[*prog.Syscall]bool) queue.Source {
+func (kc *kernelContext) MachineChecked(_ *flatrpc.InfoRequestRawT, features flatrpc.Feature,
+ syscalls map[*prog.Syscall]bool) queue.Source {
if len(syscalls) == 0 {
log.Fatalf("all system calls are disabled")
}