From 07dedd50ee8834dbca4da7667e69e72b7d0565b9 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 27 Jun 2024 12:01:58 +0200 Subject: pkg/fuzzer: remove signal rotation Signal rotation is intended to make the fuzzer re-discover flaky coverage in non flaky way. However, taking into accout that we get effectively the same effect after each manager restart, and that the fuzzer is overloaded with triage/smash jobs, it does not look to be worth it. --- pkg/flatrpc/flatrpc.fbs | 1 - pkg/flatrpc/flatrpc.go | 52 ++-------------------------------------- pkg/flatrpc/flatrpc.h | 28 ++++------------------ pkg/fuzzer/cover.go | 31 +++++------------------- pkg/fuzzer/fuzzer.go | 12 ---------- pkg/fuzzer/fuzzer_test.go | 60 ---------------------------------------------- pkg/fuzzer/job_test.go | 1 + pkg/rpcserver/rpcserver.go | 7 +++--- pkg/rpcserver/runner.go | 5 ++-- pkg/signal/signal.go | 19 --------------- pkg/signal/signal_test.go | 14 ----------- 11 files changed, 19 insertions(+), 211 deletions(-) (limited to 'pkg') diff --git a/pkg/flatrpc/flatrpc.fbs b/pkg/flatrpc/flatrpc.fbs index f0b03c4a9..121b289e9 100644 --- a/pkg/flatrpc/flatrpc.fbs +++ b/pkg/flatrpc/flatrpc.fbs @@ -164,7 +164,6 @@ table ExecRequestRaw { table SignalUpdateRaw { new_max :[uint64]; - drop_max :[uint64]; } // This message serves as a signal that the corpus was triaged and the fuzzer diff --git a/pkg/flatrpc/flatrpc.go b/pkg/flatrpc/flatrpc.go index 87f6ad19d..79c0d6cf2 100644 --- a/pkg/flatrpc/flatrpc.go +++ b/pkg/flatrpc/flatrpc.go @@ -2061,8 +2061,7 @@ func ExecRequestRawEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { } type SignalUpdateRawT struct { - NewMax []uint64 `json:"new_max"` - DropMax []uint64 `json:"drop_max"` + NewMax []uint64 `json:"new_max"` } func (t *SignalUpdateRawT) Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT { @@ -2078,18 +2077,8 @@ func (t *SignalUpdateRawT) Pack(builder *flatbuffers.Builder) flatbuffers.UOffse } newMaxOffset = builder.EndVector(newMaxLength) } - dropMaxOffset := flatbuffers.UOffsetT(0) - if t.DropMax != nil { - dropMaxLength := len(t.DropMax) - SignalUpdateRawStartDropMaxVector(builder, dropMaxLength) - for j := dropMaxLength - 1; j >= 0; j-- { - builder.PrependUint64(t.DropMax[j]) - } - dropMaxOffset = builder.EndVector(dropMaxLength) - } SignalUpdateRawStart(builder) SignalUpdateRawAddNewMax(builder, newMaxOffset) - SignalUpdateRawAddDropMax(builder, dropMaxOffset) return SignalUpdateRawEnd(builder) } @@ -2099,11 +2088,6 @@ func (rcv *SignalUpdateRaw) UnPackTo(t *SignalUpdateRawT) { for j := 0; j < newMaxLength; j++ { t.NewMax[j] = rcv.NewMax(j) } - dropMaxLength := rcv.DropMaxLength() - t.DropMax = make([]uint64, dropMaxLength) - for j := 0; j < dropMaxLength; j++ { - t.DropMax[j] = rcv.DropMax(j) - } } func (rcv *SignalUpdateRaw) UnPack() *SignalUpdateRawT { @@ -2168,34 +2152,8 @@ func (rcv *SignalUpdateRaw) MutateNewMax(j int, n uint64) bool { return false } -func (rcv *SignalUpdateRaw) DropMax(j int) uint64 { - o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) - if o != 0 { - a := rcv._tab.Vector(o) - return rcv._tab.GetUint64(a + flatbuffers.UOffsetT(j*8)) - } - return 0 -} - -func (rcv *SignalUpdateRaw) DropMaxLength() int { - o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) - if o != 0 { - return rcv._tab.VectorLen(o) - } - return 0 -} - -func (rcv *SignalUpdateRaw) MutateDropMax(j int, n uint64) bool { - o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) - if o != 0 { - a := rcv._tab.Vector(o) - return rcv._tab.MutateUint64(a+flatbuffers.UOffsetT(j*8), n) - } - return false -} - func SignalUpdateRawStart(builder *flatbuffers.Builder) { - builder.StartObject(2) + builder.StartObject(1) } func SignalUpdateRawAddNewMax(builder *flatbuffers.Builder, newMax flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(newMax), 0) @@ -2203,12 +2161,6 @@ func SignalUpdateRawAddNewMax(builder *flatbuffers.Builder, newMax flatbuffers.U func SignalUpdateRawStartNewMaxVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(8, numElems, 8) } -func SignalUpdateRawAddDropMax(builder *flatbuffers.Builder, dropMax flatbuffers.UOffsetT) { - builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(dropMax), 0) -} -func SignalUpdateRawStartDropMaxVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { - return builder.StartVector(8, numElems, 8) -} func SignalUpdateRawEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/pkg/flatrpc/flatrpc.h b/pkg/flatrpc/flatrpc.h index a2704f9e9..7ce247d2e 100644 --- a/pkg/flatrpc/flatrpc.h +++ b/pkg/flatrpc/flatrpc.h @@ -1778,28 +1778,21 @@ flatbuffers::Offset CreateExecRequestRaw(flatbuffers::FlatBuffer struct SignalUpdateRawT : public flatbuffers::NativeTable { typedef SignalUpdateRaw TableType; std::vector new_max{}; - std::vector drop_max{}; }; struct SignalUpdateRaw FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { typedef SignalUpdateRawT NativeTableType; typedef SignalUpdateRawBuilder Builder; enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_NEW_MAX = 4, - VT_DROP_MAX = 6 + VT_NEW_MAX = 4 }; const flatbuffers::Vector *new_max() const { return GetPointer *>(VT_NEW_MAX); } - const flatbuffers::Vector *drop_max() const { - return GetPointer *>(VT_DROP_MAX); - } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NEW_MAX) && verifier.VerifyVector(new_max()) && - VerifyOffset(verifier, VT_DROP_MAX) && - verifier.VerifyVector(drop_max()) && verifier.EndTable(); } SignalUpdateRawT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; @@ -1814,9 +1807,6 @@ struct SignalUpdateRawBuilder { void add_new_max(flatbuffers::Offset> new_max) { fbb_.AddOffset(SignalUpdateRaw::VT_NEW_MAX, new_max); } - void add_drop_max(flatbuffers::Offset> drop_max) { - fbb_.AddOffset(SignalUpdateRaw::VT_DROP_MAX, drop_max); - } explicit SignalUpdateRawBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -1830,24 +1820,19 @@ struct SignalUpdateRawBuilder { inline flatbuffers::Offset CreateSignalUpdateRaw( flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset> new_max = 0, - flatbuffers::Offset> drop_max = 0) { + flatbuffers::Offset> new_max = 0) { SignalUpdateRawBuilder builder_(_fbb); - builder_.add_drop_max(drop_max); builder_.add_new_max(new_max); return builder_.Finish(); } inline flatbuffers::Offset CreateSignalUpdateRawDirect( flatbuffers::FlatBufferBuilder &_fbb, - const std::vector *new_max = nullptr, - const std::vector *drop_max = nullptr) { + const std::vector *new_max = nullptr) { auto new_max__ = new_max ? _fbb.CreateVector(*new_max) : 0; - auto drop_max__ = drop_max ? _fbb.CreateVector(*drop_max) : 0; return rpc::CreateSignalUpdateRaw( _fbb, - new_max__, - drop_max__); + new_max__); } flatbuffers::Offset CreateSignalUpdateRaw(flatbuffers::FlatBufferBuilder &_fbb, const SignalUpdateRawT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); @@ -2821,7 +2806,6 @@ inline void SignalUpdateRaw::UnPackTo(SignalUpdateRawT *_o, const flatbuffers::r (void)_o; (void)_resolver; { auto _e = new_max(); if (_e) { _o->new_max.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->new_max[_i] = _e->Get(_i); } } } - { auto _e = drop_max(); if (_e) { _o->drop_max.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->drop_max[_i] = _e->Get(_i); } } } } inline flatbuffers::Offset SignalUpdateRaw::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SignalUpdateRawT* _o, const flatbuffers::rehasher_function_t *_rehasher) { @@ -2833,11 +2817,9 @@ inline flatbuffers::Offset CreateSignalUpdateRaw(flatbuffers::F (void)_o; struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SignalUpdateRawT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; auto _new_max = _o->new_max.size() ? _fbb.CreateVector(_o->new_max) : 0; - auto _drop_max = _o->drop_max.size() ? _fbb.CreateVector(_o->drop_max) : 0; return rpc::CreateSignalUpdateRaw( _fbb, - _new_max, - _drop_max); + _new_max); } inline CorpusTriagedRawT *CorpusTriagedRaw::UnPack(const flatbuffers::resolver_function_t *_resolver) const { diff --git a/pkg/fuzzer/cover.go b/pkg/fuzzer/cover.go index c34a3b219..4421693b1 100644 --- a/pkg/fuzzer/cover.go +++ b/pkg/fuzzer/cover.go @@ -12,10 +12,9 @@ import ( // Cover keeps track of the signal known to the fuzzer. type Cover struct { - mu sync.RWMutex - maxSignal signal.Signal // max signal ever observed (including flakes) - newSignal signal.Signal // newly identified max signal - dropSignal signal.Signal // the newly dropped max signal + mu sync.RWMutex + maxSignal signal.Signal // max signal ever observed (including flakes) + newSignal signal.Signal // newly identified max signal } func newCover() *Cover { @@ -31,7 +30,6 @@ func (cover *Cover) AddMaxSignal(sign signal.Signal) { cover.mu.Lock() defer cover.mu.Unlock() cover.maxSignal.Merge(sign) - cover.dropSignal.Subtract(sign) } func (cover *Cover) addRawMaxSignal(signal []uint64, prio uint8) signal.Signal { @@ -43,36 +41,19 @@ func (cover *Cover) addRawMaxSignal(signal []uint64, prio uint8) signal.Signal { } cover.maxSignal.Merge(diff) cover.newSignal.Merge(diff) - cover.dropSignal.Subtract(diff) return diff } -func (cover *Cover) pureMaxSignal(corpus signal.Signal) signal.Signal { - cover.mu.RLock() - defer cover.mu.RUnlock() - return corpus.Diff(cover.maxSignal) -} - func (cover *Cover) CopyMaxSignal() signal.Signal { cover.mu.RLock() defer cover.mu.RUnlock() return cover.maxSignal.Copy() } -func (cover *Cover) GrabSignalDelta() (plus, minus signal.Signal) { +func (cover *Cover) GrabSignalDelta() signal.Signal { cover.mu.Lock() defer cover.mu.Unlock() - plus = cover.newSignal + plus := cover.newSignal cover.newSignal = nil - minus = cover.dropSignal - cover.dropSignal = nil - return -} - -func (cover *Cover) subtract(delta signal.Signal) { - cover.mu.Lock() - defer cover.mu.Unlock() - cover.maxSignal.Subtract(delta) - cover.newSignal.Subtract(delta) - cover.dropSignal.Merge(delta) + return plus } diff --git a/pkg/fuzzer/fuzzer.go b/pkg/fuzzer/fuzzer.go index 09ce69c00..a2b2ef475 100644 --- a/pkg/fuzzer/fuzzer.go +++ b/pkg/fuzzer/fuzzer.go @@ -363,18 +363,6 @@ func (fuzzer *Fuzzer) logCurrentStats() { } } -func (fuzzer *Fuzzer) RotateMaxSignal(items int) { - corpusSignal := fuzzer.Config.Corpus.Signal() - pureMaxSignal := fuzzer.Cover.pureMaxSignal(corpusSignal) - if pureMaxSignal.Len() < items { - items = pureMaxSignal.Len() - } - fuzzer.Logf(1, "rotate %d max signal elements", items) - - delta := pureMaxSignal.RandomSubset(fuzzer.rand(), items) - fuzzer.Cover.subtract(delta) -} - func setFlags(execFlags flatrpc.ExecFlag) flatrpc.ExecOpts { return flatrpc.ExecOpts{ ExecFlags: execFlags, diff --git a/pkg/fuzzer/fuzzer_test.go b/pkg/fuzzer/fuzzer_test.go index 55ec09666..d8c532e1a 100644 --- a/pkg/fuzzer/fuzzer_test.go +++ b/pkg/fuzzer/fuzzer_test.go @@ -22,7 +22,6 @@ import ( "github.com/google/syzkaller/pkg/flatrpc" "github.com/google/syzkaller/pkg/fuzzer/queue" "github.com/google/syzkaller/pkg/rpcserver" - "github.com/google/syzkaller/pkg/signal" "github.com/google/syzkaller/pkg/testutil" "github.com/google/syzkaller/pkg/vminfo" "github.com/google/syzkaller/prog" @@ -121,65 +120,6 @@ func BenchmarkFuzzer(b *testing.B) { }) } -const anyTestProg = `syz_compare(&AUTO="00000000", 0x4, &AUTO=@conditional={0x0, @void, @void}, AUTO)` - -func TestRotate(t *testing.T) { - target, err := prog.GetTarget(targets.TestOS, targets.TestArch64Fuzz) - if err != nil { - t.Fatal(err) - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - corpusObj := corpus.NewCorpus(ctx) - fuzzer := NewFuzzer(ctx, &Config{ - Debug: true, - Corpus: corpusObj, - Coverage: true, - EnabledCalls: map[*prog.Syscall]bool{ - target.SyscallMap["syz_compare"]: true, - }, - }, rand.New(testutil.RandSource(t)), target) - - fakeSignal := func(size int) signal.Signal { - var pc []uint64 - for i := 0; i < size; i++ { - pc = append(pc, uint64(i)) - } - return signal.FromRaw(pc, 0) - } - - prog, err := target.Deserialize([]byte(anyTestProg), prog.NonStrict) - assert.NoError(t, err) - corpusObj.Save(corpus.NewInput{ - Prog: prog, - Call: 0, - Signal: fakeSignal(100), - }) - fuzzer.Cover.AddMaxSignal(fakeSignal(1000)) - - assert.Equal(t, 1000, len(fuzzer.Cover.maxSignal)) - assert.Equal(t, 100, corpusObj.StatSignal.Val()) - - // Rotate some of the signal. - fuzzer.RotateMaxSignal(200) - assert.Equal(t, 800, len(fuzzer.Cover.maxSignal)) - assert.Equal(t, 100, corpusObj.StatSignal.Val()) - - plus, minus := fuzzer.Cover.GrabSignalDelta() - assert.Equal(t, 0, plus.Len()) - assert.Equal(t, 200, minus.Len()) - - // Rotate the rest. - fuzzer.RotateMaxSignal(1000) - assert.Equal(t, 100, len(fuzzer.Cover.maxSignal)) - assert.Equal(t, 100, corpusObj.StatSignal.Val()) - plus, minus = fuzzer.Cover.GrabSignalDelta() - assert.Equal(t, 0, plus.Len()) - assert.Equal(t, 700, minus.Len()) -} - // Based on the example from Go documentation. var crc32q = crc32.MakeTable(0xD5828281) diff --git a/pkg/fuzzer/job_test.go b/pkg/fuzzer/job_test.go index 8441c4142..122a50577 100644 --- a/pkg/fuzzer/job_test.go +++ b/pkg/fuzzer/job_test.go @@ -77,6 +77,7 @@ func TestDeflake(t *testing.T) { target, err := prog.GetTarget(targets.TestOS, targets.TestArch64Fuzz) assert.NoError(t, err) + const anyTestProg = `syz_compare(&AUTO="00000000", 0x4, &AUTO=@conditional={0x0, @void, @void}, AUTO)` prog, err := target.Deserialize([]byte(anyTestProg), prog.NonStrict) assert.NoError(t, err) diff --git a/pkg/rpcserver/rpcserver.go b/pkg/rpcserver/rpcserver.go index 58ef2d363..40ca9a316 100644 --- a/pkg/rpcserver/rpcserver.go +++ b/pkg/rpcserver/rpcserver.go @@ -344,7 +344,7 @@ func (serv *Server) connectionLoop(runner *Runner) error { // buffer too much (we don't want to grow it larger than what will be needed // to send programs). n := min(len(maxSignal), 50000) - if err := runner.sendSignalUpdate(maxSignal[:n], nil); err != nil { + if err := runner.sendSignalUpdate(maxSignal[:n]); err != nil { return err } maxSignal = maxSignal[n:] @@ -489,11 +489,10 @@ func (serv *Server) ShutdownInstance(name string, crashed bool) ([]ExecRecord, [ return runner.shutdown(crashed) } -func (serv *Server) DistributeSignalDelta(plus, minus signal.Signal) { +func (serv *Server) DistributeSignalDelta(plus signal.Signal) { plusRaw := plus.ToRaw() - minusRaw := minus.ToRaw() serv.foreachRunnerAsync(func(runner *Runner) { - runner.sendSignalUpdate(plusRaw, minusRaw) + runner.sendSignalUpdate(plusRaw) }) } diff --git a/pkg/rpcserver/runner.go b/pkg/rpcserver/runner.go index b5903848f..219ef2c35 100644 --- a/pkg/rpcserver/runner.go +++ b/pkg/rpcserver/runner.go @@ -311,13 +311,12 @@ func (runner *Runner) convertCallInfo(call *flatrpc.CallInfo) { } } -func (runner *Runner) sendSignalUpdate(plus, minus []uint64) error { +func (runner *Runner) sendSignalUpdate(plus []uint64) error { msg := &flatrpc.HostMessage{ Msg: &flatrpc.HostMessages{ Type: flatrpc.HostMessagesRawSignalUpdate, Value: &flatrpc.SignalUpdate{ - NewMax: runner.canonicalizer.Decanonicalize(plus), - DropMax: runner.canonicalizer.Decanonicalize(minus), + NewMax: runner.canonicalizer.Decanonicalize(plus), }, }, } diff --git a/pkg/signal/signal.go b/pkg/signal/signal.go index 3eb4263de..ca73578fa 100644 --- a/pkg/signal/signal.go +++ b/pkg/signal/signal.go @@ -4,8 +4,6 @@ // Package signal provides types for working with feedback signal. package signal -import "math/rand" - type ( elemType uint64 prioType int8 @@ -142,23 +140,6 @@ func (s *Signal) Subtract(s1 Signal) { } } -func (s Signal) RandomSubset(r *rand.Rand, size int) Signal { - if size > len(s) { - size = len(s) - } - keys := make([]elemType, 0, len(s)) - for e := range s { - keys = append(keys, e) - } - r.Shuffle(len(keys), func(i, j int) { keys[i], keys[j] = keys[j], keys[i] }) - - ret := make(Signal, size) - for _, e := range keys[:size] { - ret[e] = s[e] - } - return ret -} - // FilterRaw returns a subset of original raw elements that either are not present in ignore, // or coincides with the one in alwaysTake. func FilterRaw(raw []uint64, ignore, alwaysTake Signal) []uint64 { diff --git a/pkg/signal/signal_test.go b/pkg/signal/signal_test.go index 52b91fc19..2610fe792 100644 --- a/pkg/signal/signal_test.go +++ b/pkg/signal/signal_test.go @@ -4,25 +4,11 @@ package signal import ( - "math/rand" "testing" - "github.com/google/syzkaller/pkg/testutil" "github.com/stretchr/testify/assert" ) -func TestRandomSubset(t *testing.T) { - r := rand.New(testutil.RandSource(t)) - base := FromRaw([]uint64{0, 1, 2, 3, 4}, 0) - var s Signal - for i := 0; i < 1000 && s.Len() < base.Len(); i++ { - delta := base.RandomSubset(r, 1) - assert.Equal(t, 1, delta.Len()) - s.Merge(delta) - } - assert.Equal(t, base.Len(), s.Len()) -} - func TestSubtract(t *testing.T) { base := FromRaw([]uint64{0, 1, 2, 3, 4}, 0) assert.Equal(t, 5, base.Len()) -- cgit mrf-deployment