From 5f6d557d4454398c38d85f6774152d5e0a4436d7 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 26 Nov 2024 12:01:29 +0100 Subject: 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 --- pkg/rpcserver/local.go | 3 ++- pkg/rpcserver/mocks/Manager.go | 10 +++++----- pkg/rpcserver/rpcserver.go | 40 ++++++++++++++++++++++++++-------------- pkg/rpcserver/rpcserver_test.go | 13 +++++++++++-- 4 files changed, 44 insertions(+), 22 deletions(-) (limited to 'pkg') 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) -- cgit mrf-deployment