From b2bebe1217cea83046897e28cf1366b72c3ff329 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 4 Mar 2021 16:03:50 +0100 Subject: prog: detect copyout overflow Detect the case when a program requires more copyout than executor can handle. Curretnly these result in: "SYZFAIL: command refers to bad result" failures. Now syz-fuzzer should ignore them. --- prog/encodingexec.go | 4 ++- prog/encodingexec_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) (limited to 'prog') diff --git a/prog/encodingexec.go b/prog/encodingexec.go index c15eb25bc..e0c7ec59d 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -52,6 +52,8 @@ const ( const ( ExecBufferSize = 4 << 20 // keep in sync with kMaxInput in executor.cc ExecNoCopyout = ^uint64(0) + + execMaxCommands = 1000 // executor knows about this constant (kMaxCommands) ) var ErrExecBufferTooSmall = errors.New("encodingexec: provided buffer is too small") @@ -72,7 +74,7 @@ func (p *Prog) SerializeForExec(buffer []byte) (int, error) { w.serializeCall(c) } w.write(execInstrEOF) - if w.eof { + if w.eof || w.copyoutSeq > execMaxCommands { return 0, ErrExecBufferTooSmall } return len(buffer) - len(w.buf), nil diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go index 7cda63cc0..d5b92f59a 100644 --- a/prog/encodingexec_test.go +++ b/prog/encodingexec_test.go @@ -498,3 +498,70 @@ func TestSerializeForExec(t *testing.T) { }) } } + +func TestSerializeForExecOverflow(t *testing.T) { + target := initTargetTest(t, "test", "64") + type Test struct { + name string + overflow bool + gen func(w *bytes.Buffer) + } + tests := []Test{ + { + name: "few-resources", + overflow: false, + gen: func(w *bytes.Buffer) { + for i := 0; i < execMaxCommands-10; i++ { + fmt.Fprintf(w, "r%v = test$res0()\ntest$res1(r%v)\n", i, i) + } + }, + }, + { + name: "overflow-resources", + overflow: true, + gen: func(w *bytes.Buffer) { + for i := 0; i < execMaxCommands+1; i++ { + fmt.Fprintf(w, "r%v = test$res0()\ntest$res1(r%v)\n", i, i) + } + }, + }, + { + name: "no-verflow-buffer", + overflow: false, + gen: func(w *bytes.Buffer) { + fmt.Fprintf(w, "r0 = test$res0()\n") + for i := 0; i < 58e3; i++ { + fmt.Fprintf(w, "test$res1(r0)\n") + } + }, + }, + { + name: "overflow-buffer", + overflow: true, + gen: func(w *bytes.Buffer) { + fmt.Fprintf(w, "r0 = test$res0()\n") + for i := 0; i < 59e3; i++ { + fmt.Fprintf(w, "test$res1(r0)\n") + } + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + data := new(bytes.Buffer) + test.gen(data) + p, err := target.Deserialize(data.Bytes(), Strict) + if err != nil { + t.Fatal(err) + } + buf := make([]byte, ExecBufferSize) + _, err = p.SerializeForExec(buf) + if test.overflow && err != ErrExecBufferTooSmall { + t.Fatalf("want overflow but got %v", err) + } + if !test.overflow && err != nil { + t.Fatalf("want no overflow but got %v", err) + } + }) + } +} -- cgit mrf-deployment