aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pkg/csource/csource.go201
-rw-r--r--prog/decodeexec.go213
-rw-r--r--prog/encodingexec.go47
-rw-r--r--prog/encodingexec_test.go280
4 files changed, 473 insertions, 268 deletions
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index d99a0168d..ca61cf662 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -9,7 +9,6 @@ import (
"fmt"
"regexp"
"strings"
- "unsafe"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys/targets"
@@ -47,7 +46,11 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
if err != nil {
return nil, fmt.Errorf("failed to serialize program: %v", err)
}
- calls, nvar := ctx.generateCalls(exec[:progSize])
+ decoded, err := ctx.target.DeserializeExec(exec[:progSize])
+ if err != nil {
+ return nil, err
+ }
+ calls, nvar := ctx.generateCalls(decoded)
ctx.printf("long r[%v];\n", nvar)
if !opts.Repeat {
@@ -243,65 +246,38 @@ func (ctx *context) generateSyscallDefines() {
ctx.printf("\n")
}
-func (ctx *context) generateCalls(exec []byte) ([]string, int) {
- read := func() uint64 {
- if len(exec) < 8 {
- panic("exec program overflow")
+func (ctx *context) generateCalls(p prog.ExecProg) ([]string, uint64) {
+ resultRef := func(arg prog.ExecArgResult) string {
+ res := fmt.Sprintf("r[%v]", arg.Index)
+ if arg.DivOp != 0 {
+ res = fmt.Sprintf("%v/%v", res, arg.DivOp)
}
- v := *(*uint64)(unsafe.Pointer(&exec[0]))
- exec = exec[8:]
- return v
- }
- resultRef := func() string {
- arg := read()
- res := fmt.Sprintf("r[%v]", arg)
- if opDiv := read(); opDiv != 0 {
- res = fmt.Sprintf("%v/%v", res, opDiv)
- }
- if opAdd := read(); opAdd != 0 {
- res = fmt.Sprintf("%v+%v", res, opAdd)
+ if arg.AddOp != 0 {
+ res = fmt.Sprintf("%v+%v", res, arg.AddOp)
}
return res
}
- lastCall := 0
- seenCall := false
var calls []string
- w := new(bytes.Buffer)
- newCall := func() {
- if seenCall {
- seenCall = false
- calls = append(calls, w.String())
- w = new(bytes.Buffer)
- }
- }
- n := 0
-loop:
- for ; ; n++ {
- switch instr := read(); instr {
- case prog.ExecInstrEOF:
- break loop
- case prog.ExecInstrCopyin:
- newCall()
- addr := read()
- typ := read()
- size := read()
- switch typ {
+ csumSeq := 0
+ for ci, call := range p.Calls {
+ w := new(bytes.Buffer)
+ // Copyin.
+ for _, copyin := range call.Copyin {
+ switch arg := copyin.Arg.(type) {
case prog.ExecArgConst:
- arg := read()
- bfOff := read()
- bfLen := read()
- if bfOff == 0 && bfLen == 0 {
- fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = (uint%v_t)0x%x);\n", size*8, addr, size*8, arg)
+ if arg.BitfieldOffset == 0 && arg.BitfieldLength == 0 {
+ fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = (uint%v_t)0x%x);\n",
+ arg.Size*8, copyin.Addr, arg.Size*8, arg.Value)
} else {
- fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v_t, 0x%x, 0x%x, %v, %v));\n", size*8, addr, arg, bfOff, bfLen)
+ fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v_t, 0x%x, 0x%x, %v, %v));\n",
+ arg.Size*8, copyin.Addr, arg.Value, arg.BitfieldOffset, arg.BitfieldLength)
}
case prog.ExecArgResult:
- fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = %v);\n", size*8, addr, resultRef())
+ fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = %v);\n",
+ arg.Size*8, copyin.Addr, resultRef(arg))
case prog.ExecArgData:
- data := exec[:size]
- exec = exec[(size+7)/8*8:]
var esc []byte
- for _, v := range data {
+ for _, v := range arg.Data {
hex := func(v byte) byte {
if v < 10 {
return '0' + v
@@ -310,99 +286,76 @@ loop:
}
esc = append(esc, '\\', 'x', hex(v>>4), hex(v<<4>>4))
}
- fmt.Fprintf(w, "\tNONFAILING(memcpy((void*)0x%x, \"%s\", %v));\n", addr, esc, size)
+ fmt.Fprintf(w, "\tNONFAILING(memcpy((void*)0x%x, \"%s\", %v));\n",
+ copyin.Addr, esc, len(arg.Data))
case prog.ExecArgCsum:
- csum_kind := read()
- switch csum_kind {
+ switch arg.Kind {
case prog.ExecArgCsumInet:
- fmt.Fprintf(w, "\tstruct csum_inet csum_%d;\n", n)
- fmt.Fprintf(w, "\tcsum_inet_init(&csum_%d);\n", n)
- csumChunksNum := read()
- for i := uint64(0); i < csumChunksNum; i++ {
- chunk_kind := read()
- chunk_value := read()
- chunk_size := read()
- switch chunk_kind {
+ csumSeq++
+ fmt.Fprintf(w, "\tstruct csum_inet csum_%d;\n", csumSeq)
+ fmt.Fprintf(w, "\tcsum_inet_init(&csum_%d);\n", csumSeq)
+ for i, chunk := range arg.Chunks {
+ switch chunk.Kind {
case prog.ExecArgCsumChunkData:
- fmt.Fprintf(w, "\tNONFAILING(csum_inet_update(&csum_%d, (const uint8_t*)0x%x, %d));\n", n, chunk_value, chunk_size)
+ fmt.Fprintf(w, "\tNONFAILING(csum_inet_update(&csum_%d, (const uint8_t*)0x%x, %d));\n", csumSeq, chunk.Value, chunk.Size)
case prog.ExecArgCsumChunkConst:
- fmt.Fprintf(w, "\tuint%d_t csum_%d_chunk_%d = 0x%x;\n", chunk_size*8, n, i, chunk_value)
- fmt.Fprintf(w, "\tcsum_inet_update(&csum_%d, (const uint8_t*)&csum_%d_chunk_%d, %d);\n", n, n, i, chunk_size)
+ fmt.Fprintf(w, "\tuint%d_t csum_%d_chunk_%d = 0x%x;\n", chunk.Size*8, csumSeq, i, chunk.Value)
+ fmt.Fprintf(w, "\tcsum_inet_update(&csum_%d, (const uint8_t*)&csum_%d_chunk_%d, %d);\n", csumSeq, csumSeq, i, chunk.Size)
default:
- panic(fmt.Sprintf("unknown checksum chunk kind %v", chunk_kind))
+ panic(fmt.Sprintf("unknown checksum chunk kind %v", chunk.Kind))
}
}
- fmt.Fprintf(w, "\tNONFAILING(*(uint16_t*)0x%x = csum_inet_digest(&csum_%d));\n", addr, n)
+ fmt.Fprintf(w, "\tNONFAILING(*(uint16_t*)0x%x = csum_inet_digest(&csum_%d));\n", copyin.Addr, csumSeq)
default:
- panic(fmt.Sprintf("unknown csum kind %v", csum_kind))
+ panic(fmt.Sprintf("unknown csum kind %v", arg.Kind))
}
default:
- panic(fmt.Sprintf("bad argument type %v", instr))
- }
- case prog.ExecInstrCopyout:
- addr := read()
- size := read()
- fmt.Fprintf(w, "\tif (r[%v] != -1)\n", lastCall)
- fmt.Fprintf(w, "\t\tNONFAILING(r[%v] = *(uint%v_t*)0x%x);\n", n, size*8, addr)
- default:
- // Normal syscall.
- newCall()
- if ctx.opts.Fault && ctx.opts.FaultCall == len(calls) {
- fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/failslab/ignore-gfp-wait\", \"N\");\n")
- fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_futex/ignore-private\", \"N\");\n")
- fmt.Fprintf(w, "\tinject_fault(%v);\n", ctx.opts.FaultNth)
- }
- meta := ctx.target.Syscalls[instr]
- emitCall := true
- if meta.CallName == "syz_test" {
- emitCall = false
+ panic(fmt.Sprintf("bad argument type: %+v", arg))
}
- if !ctx.opts.EnableTun && (meta.CallName == "syz_emit_ethernet" ||
- meta.CallName == "syz_extract_tcp_res") {
- emitCall = false
- }
- native := !strings.HasPrefix(meta.CallName, "syz_")
- if emitCall {
- if native {
- fmt.Fprintf(w, "\tr[%v] = syscall(%v%v",
- n, ctx.sysTarget.SyscallPrefix, meta.CallName)
- } else {
- fmt.Fprintf(w, "\tr[%v] = %v(", n, meta.CallName)
- }
+ }
+
+ // Call itself.
+ if ctx.opts.Fault && ctx.opts.FaultCall == ci {
+ fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/failslab/ignore-gfp-wait\", \"N\");\n")
+ fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_futex/ignore-private\", \"N\");\n")
+ fmt.Fprintf(w, "\tinject_fault(%v);\n", ctx.opts.FaultNth)
+ }
+ callName := call.Meta.CallName
+ // TODO: if we don't emit the call we must also not emit copyin, copyout and fault injection.
+ // However, simply skipping whole iteration breaks tests due to unused static functions.
+ if ctx.opts.EnableTun || callName != "syz_emit_ethernet" &&
+ callName != "syz_extract_tcp_res" {
+ native := !strings.HasPrefix(callName, "syz_")
+ if native {
+ fmt.Fprintf(w, "\tr[%v] = syscall(%v%v",
+ call.Index, ctx.sysTarget.SyscallPrefix, callName)
+ } else {
+ fmt.Fprintf(w, "\tr[%v] = %v(", call.Index, callName)
}
- nargs := read()
- for i := uint64(0); i < nargs; i++ {
- typ := read()
- size := read()
- _ = size
- if emitCall && (native || i > 0) {
+ for ai, arg := range call.Args {
+ if native || ai > 0 {
fmt.Fprintf(w, ", ")
}
- switch typ {
+ switch arg := arg.(type) {
case prog.ExecArgConst:
- value := read()
- if emitCall {
- fmt.Fprintf(w, "0x%xul", value)
- }
- // Bitfields can't be args of a normal syscall, so just ignore them.
- read() // bit field offset
- read() // bit field length
+ fmt.Fprintf(w, "0x%xul", arg.Value)
case prog.ExecArgResult:
- ref := resultRef()
- if emitCall {
- fmt.Fprintf(w, "%v", ref)
- }
+ fmt.Fprintf(w, "%v", resultRef(arg))
default:
- panic(fmt.Sprintf("unknown arg type %v", typ))
+ panic(fmt.Sprintf("unknown arg type: %+v", arg))
}
}
- if emitCall {
- fmt.Fprintf(w, ");\n")
- }
- lastCall = n
- seenCall = true
+ fmt.Fprintf(w, ");\n")
}
+
+ // Copyout.
+ for _, copyout := range call.Copyout {
+ fmt.Fprintf(w, "\tif (r[%v] != -1)\n", call.Index)
+ fmt.Fprintf(w, "\t\tNONFAILING(r[%v] = *(uint%v_t*)0x%x);\n",
+ copyout.Index, copyout.Size*8, copyout.Addr)
+ }
+
+ calls = append(calls, w.String())
}
- newCall()
- return calls, n
+ return calls, p.NumVars
}
diff --git a/prog/decodeexec.go b/prog/decodeexec.go
new file mode 100644
index 000000000..696de461e
--- /dev/null
+++ b/prog/decodeexec.go
@@ -0,0 +1,213 @@
+// Copyright 2017 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package prog
+
+import (
+ "fmt"
+)
+
+type ExecProg struct {
+ Calls []ExecCall
+ NumVars uint64
+}
+
+type ExecCall struct {
+ Meta *Syscall
+ Index uint64
+ Args []ExecArg
+ Copyin []ExecCopyin
+ Copyout []ExecCopyout
+}
+
+type ExecCopyin struct {
+ Addr uint64
+ Arg ExecArg
+}
+
+type ExecCopyout struct {
+ Index uint64
+ Addr uint64
+ Size uint64
+}
+
+type ExecArg interface{} // one of ExecArg*
+
+type ExecArgConst struct {
+ Size uint64
+ Value uint64
+ BitfieldOffset uint64
+ BitfieldLength uint64
+}
+
+type ExecArgResult struct {
+ Size uint64
+ Index uint64
+ DivOp uint64
+ AddOp uint64
+}
+
+type ExecArgData struct {
+ Data []byte
+}
+
+type ExecArgCsum struct {
+ Size uint64
+ Kind uint64
+ Chunks []ExecCsumChunk
+}
+
+type ExecCsumChunk struct {
+ Kind uint64
+ Value uint64
+ Size uint64
+}
+
+func (target *Target) DeserializeExec(exec []byte) (ExecProg, error) {
+ dec := &execDecoder{target: target, data: exec}
+ dec.parse()
+ if dec.err != nil {
+ return ExecProg{}, dec.err
+ }
+ p := ExecProg{
+ Calls: dec.calls,
+ NumVars: dec.numInstr,
+ }
+ return p, nil
+}
+
+type execDecoder struct {
+ target *Target
+ data []byte
+ err error
+ numInstr uint64
+ call ExecCall
+ calls []ExecCall
+}
+
+func (dec *execDecoder) parse() {
+ for ; dec.err == nil; dec.numInstr++ {
+ switch instr := dec.read(); instr {
+ case execInstrCopyin:
+ dec.commitCall()
+ dec.call.Copyin = append(dec.call.Copyin, ExecCopyin{
+ Addr: dec.read(),
+ Arg: dec.readArg(),
+ })
+ case execInstrCopyout:
+ dec.call.Copyout = append(dec.call.Copyout, ExecCopyout{
+ Index: dec.numInstr,
+ Addr: dec.read(),
+ Size: dec.read(),
+ })
+ default:
+ dec.commitCall()
+ if instr >= uint64(len(dec.target.Syscalls)) {
+ dec.setErr(fmt.Errorf("bad syscall %v", instr))
+ return
+ }
+ dec.call.Meta = dec.target.Syscalls[instr]
+ dec.call.Index = dec.numInstr
+ for i := dec.read(); i > 0; i-- {
+ switch arg := dec.readArg(); arg.(type) {
+ case ExecArgConst, ExecArgResult:
+ dec.call.Args = append(dec.call.Args, arg)
+ default:
+ dec.setErr(fmt.Errorf("bad call arg %+v", arg))
+ return
+ }
+ }
+ case execInstrEOF:
+ dec.commitCall()
+ return
+ }
+ }
+}
+
+func (dec *execDecoder) readArg() ExecArg {
+ switch typ := dec.read(); typ {
+ case execArgConst:
+ return ExecArgConst{
+ Size: dec.read(),
+ Value: dec.read(),
+ BitfieldOffset: dec.read(),
+ BitfieldLength: dec.read(),
+ }
+ case execArgResult:
+ return ExecArgResult{
+ Size: dec.read(),
+ Index: dec.read(),
+ DivOp: dec.read(),
+ AddOp: dec.read(),
+ }
+ case execArgData:
+ return ExecArgData{
+ Data: dec.readBlob(dec.read()),
+ }
+ case execArgCsum:
+ size := dec.read()
+ switch kind := dec.read(); kind {
+ case ExecArgCsumInet:
+ chunks := make([]ExecCsumChunk, dec.read())
+ for i := range chunks {
+ chunks[i] = ExecCsumChunk{
+ Kind: dec.read(),
+ Value: dec.read(),
+ Size: dec.read(),
+ }
+ }
+ return ExecArgCsum{
+ Size: size,
+ Kind: kind,
+ Chunks: chunks,
+ }
+ default:
+ dec.setErr(fmt.Errorf("unknown csum kind %v", kind))
+ return nil
+ }
+ default:
+ dec.setErr(fmt.Errorf("bad argument type %v", typ))
+ return nil
+ }
+}
+
+func (dec *execDecoder) read() uint64 {
+ if len(dec.data) < 8 {
+ dec.setErr(fmt.Errorf("exec program overflow"))
+ }
+ if dec.err != nil {
+ return 0
+ }
+ var v uint64
+ for i := 0; i < 8; i++ {
+ v |= uint64(dec.data[i]) << uint(i*8)
+ }
+ dec.data = dec.data[8:]
+ return v
+}
+
+func (dec *execDecoder) readBlob(size uint64) []byte {
+ padded := (size + 7) / 8 * 8
+ if uint64(len(dec.data)) < padded {
+ dec.setErr(fmt.Errorf("exec program overflow"))
+ }
+ if dec.err != nil {
+ return nil
+ }
+ data := dec.data[:size]
+ dec.data = dec.data[padded:]
+ return data
+}
+
+func (dec *execDecoder) setErr(err error) {
+ if dec.err == nil {
+ dec.err = err
+ }
+}
+
+func (dec *execDecoder) commitCall() {
+ if dec.call.Meta != nil {
+ dec.calls = append(dec.calls, dec.call)
+ dec.call = ExecCall{}
+ }
+}
diff --git a/prog/encodingexec.go b/prog/encodingexec.go
index 3c6466d7b..b89788378 100644
--- a/prog/encodingexec.go
+++ b/prog/encodingexec.go
@@ -4,6 +4,19 @@
// This file does serialization of programs for executor binary.
// The format aims at simple parsing: binary and irreversible.
+// Exec format is an sequence of uint64's which encodes a sequence of calls.
+// The sequence is terminated by a speciall call execInstrEOF.
+// Each call is (call ID, number of arguments, arguments...).
+// Each argument is (type, size, value).
+// There are 4 types of arguments:
+// - execArgConst: value is const value
+// - execArgResult: value is index of a call whose result we want to reference
+// - execArgData: value is a binary blob (represented as ]size/8[ uint64's)
+// - execArgCsum: runtime checksum calculation
+// There are 2 other special calls:
+// - execInstrCopyin: copies its second argument into address specified by first argument
+// - execInstrCopyout: reads value at address specified by first argument (result can be referenced by execArgResult)
+
package prog
import (
@@ -12,16 +25,16 @@ import (
)
const (
- ExecInstrEOF = ^uint64(iota)
- ExecInstrCopyin
- ExecInstrCopyout
+ execInstrEOF = ^uint64(iota)
+ execInstrCopyin
+ execInstrCopyout
)
const (
- ExecArgConst = uint64(iota)
- ExecArgResult
- ExecArgData
- ExecArgCsum
+ execArgConst = uint64(iota)
+ execArgResult
+ execArgData
+ execArgCsum
)
const (
@@ -109,7 +122,7 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) (int, error) {
return
}
if !IsPad(arg1.Type()) && arg1.Type().Dir() != DirOut {
- w.write(ExecInstrCopyin)
+ w.write(execInstrCopyin)
w.write(addr)
w.writeArg(arg1, pid)
instrSeq++
@@ -130,9 +143,9 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) (int, error) {
if _, ok := arg.Type().(*CsumType); !ok {
panic("csum arg is not csum type")
}
- w.write(ExecInstrCopyin)
+ w.write(execInstrCopyin)
w.write(w.args[arg].Addr)
- w.write(ExecArgCsum)
+ w.write(execArgCsum)
w.write(arg.Size())
switch csumMap[arg].Kind {
case CsumInet:
@@ -185,7 +198,7 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) (int, error) {
info.Idx = instrSeq
instrSeq++
w.args[arg] = info
- w.write(ExecInstrCopyout)
+ w.write(execInstrCopyout)
w.write(info.Addr)
w.write(arg.Size())
default:
@@ -193,7 +206,7 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) (int, error) {
}
})
}
- w.write(ExecInstrEOF)
+ w.write(execInstrEOF)
if w.eof {
return 0, fmt.Errorf("provided buffer is too small")
}
@@ -245,34 +258,34 @@ func (w *execContext) write(v uint64) {
func (w *execContext) writeArg(arg Arg, pid int) {
switch a := arg.(type) {
case *ConstArg:
- w.write(ExecArgConst)
+ w.write(execArgConst)
w.write(a.Size())
w.write(a.Value(pid))
w.write(a.Type().BitfieldOffset())
w.write(a.Type().BitfieldLength())
case *ResultArg:
if a.Res == nil {
- w.write(ExecArgConst)
+ w.write(execArgConst)
w.write(a.Size())
w.write(a.Val)
w.write(0) // bit field offset
w.write(0) // bit field length
} else {
- w.write(ExecArgResult)
+ w.write(execArgResult)
w.write(a.Size())
w.write(uint64(w.args[a.Res].Idx))
w.write(a.OpDiv)
w.write(a.OpAdd)
}
case *PointerArg:
- w.write(ExecArgConst)
+ w.write(execArgConst)
w.write(a.Size())
w.write(w.target.physicalAddr(arg))
w.write(0) // bit field offset
w.write(0) // bit field length
case *DataArg:
data := a.Data()
- w.write(ExecArgData)
+ w.write(execArgData)
w.write(uint64(len(data)))
padded := len(data)
if pad := 8 - len(data)%8; pad != 8 {
diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go
index 29715e654..8a0325f0a 100644
--- a/prog/encodingexec_test.go
+++ b/prog/encodingexec_test.go
@@ -7,6 +7,7 @@ import (
"bytes"
"encoding/binary"
"fmt"
+ "reflect"
"testing"
)
@@ -15,33 +16,18 @@ func TestSerializeForExecRandom(t *testing.T) {
buf := make([]byte, ExecBufferSize)
for i := 0; i < iters; i++ {
p := target.Generate(rs, 10, nil)
- if _, err := p.SerializeForExec(buf, i%16); err != nil {
+ n, err := p.SerializeForExec(buf, i%16)
+ if err != nil {
t.Fatalf("failed to serialize: %v", err)
}
+ _, err = target.DeserializeExec(buf[:n])
+ if err != nil {
+ t.Fatal(err)
+ }
}
}
func TestSerializeForExec(t *testing.T) {
- // A brief recap of exec format.
- // Exec format is an sequence of uint64's which encodes a sequence of calls.
- // The sequence is terminated by a speciall call ExecInstrEOF.
- // Each call is (call ID, number of arguments, arguments...).
- // Each argument is (type, size, value).
- // There are 3 types of arguments:
- // - ExecArgConst: value is const value
- // - ExecArgResult: value is index of a call whose result we want to reference
- // - ExecArgData: value is a binary blob (represented as ]size/8[ uint64's)
- // There are 2 other special call:
- // - ExecInstrCopyin: copies its second argument into address specified by first argument
- // - ExecInstrCopyout: reads value at address specified by first argument (result can be referenced by ExecArgResult)
- const (
- instrEOF = uint64(ExecInstrEOF)
- instrCopyin = uint64(ExecInstrCopyin)
- instrCopyout = uint64(ExecInstrCopyout)
- argConst = uint64(ExecArgConst)
- argResult = uint64(ExecArgResult)
- argData = uint64(ExecArgData)
- )
target := initTargetTest(t, "test", "64")
var (
dataOffset = target.DataOffset
@@ -57,207 +43,241 @@ func TestSerializeForExec(t *testing.T) {
tests := []struct {
prog string
serialized []uint64
+ decoded *ExecProg
}{
{
"syz_test()",
[]uint64{
callID("syz_test"), 0,
- instrEOF,
+ execInstrEOF,
+ },
+ &ExecProg{
+ Calls: []ExecCall{
+ {
+ Meta: target.SyscallMap["syz_test"],
+ Index: 0,
+ },
+ },
+ NumVars: 1,
},
},
{
"syz_test$int(0x1, 0x2, 0x3, 0x4, 0x5)",
[]uint64{
- callID("syz_test$int"), 5, argConst, 8, 1, 0, 0, argConst, 1, 2, 0, 0, argConst, 2, 3, 0, 0, argConst, 4, 4, 0, 0, argConst, 8, 5, 0, 0,
- instrEOF,
+ callID("syz_test$int"), 5,
+ execArgConst, 8, 1, 0, 0,
+ execArgConst, 1, 2, 0, 0,
+ execArgConst, 2, 3, 0, 0,
+ execArgConst, 4, 4, 0, 0,
+ execArgConst, 8, 5, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$align0(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 2, 1, 0, 0,
- instrCopyin, dataOffset + 4, argConst, 4, 2, 0, 0,
- instrCopyin, dataOffset + 8, argConst, 1, 3, 0, 0,
- instrCopyin, dataOffset + 10, argConst, 2, 4, 0, 0,
- instrCopyin, dataOffset + 16, argConst, 8, 5, 0, 0,
- callID("syz_test$align0"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 2, 1, 0, 0,
+ execInstrCopyin, dataOffset + 4, execArgConst, 4, 2, 0, 0,
+ execInstrCopyin, dataOffset + 8, execArgConst, 1, 3, 0, 0,
+ execInstrCopyin, dataOffset + 10, execArgConst, 2, 4, 0, 0,
+ execInstrCopyin, dataOffset + 16, execArgConst, 8, 5, 0, 0,
+ callID("syz_test$align0"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$align1(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 2, 1, 0, 0,
- instrCopyin, dataOffset + 2, argConst, 4, 2, 0, 0,
- instrCopyin, dataOffset + 6, argConst, 1, 3, 0, 0,
- instrCopyin, dataOffset + 7, argConst, 2, 4, 0, 0,
- instrCopyin, dataOffset + 9, argConst, 8, 5, 0, 0,
- callID("syz_test$align1"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 2, 1, 0, 0,
+ execInstrCopyin, dataOffset + 2, execArgConst, 4, 2, 0, 0,
+ execInstrCopyin, dataOffset + 6, execArgConst, 1, 3, 0, 0,
+ execInstrCopyin, dataOffset + 7, execArgConst, 2, 4, 0, 0,
+ execInstrCopyin, dataOffset + 9, execArgConst, 8, 5, 0, 0,
+ callID("syz_test$align1"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$align2(&(0x7f0000000000)={0x42, {[0x43]}, {[0x44]}})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 1, 0x42, 0, 0,
- instrCopyin, dataOffset + 1, argConst, 2, 0x43, 0, 0,
- instrCopyin, dataOffset + 4, argConst, 2, 0x44, 0, 0,
- callID("syz_test$align2"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43, 0, 0,
+ execInstrCopyin, dataOffset + 4, execArgConst, 2, 0x44, 0, 0,
+ callID("syz_test$align2"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$align3(&(0x7f0000000000)={0x42, {0x43}, {0x44}})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 1, 0x42, 0, 0,
- instrCopyin, dataOffset + 1, argConst, 1, 0x43, 0, 0,
- instrCopyin, dataOffset + 4, argConst, 1, 0x44, 0, 0,
- callID("syz_test$align3"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 1, execArgConst, 1, 0x43, 0, 0,
+ execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44, 0, 0,
+ callID("syz_test$align3"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$align4(&(0x7f0000000000)={{0x42, 0x43}, 0x44})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 1, 0x42, 0, 0,
- instrCopyin, dataOffset + 1, argConst, 2, 0x43, 0, 0,
- instrCopyin, dataOffset + 4, argConst, 1, 0x44, 0, 0,
- callID("syz_test$align4"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43, 0, 0,
+ execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44, 0, 0,
+ callID("syz_test$align4"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$align5(&(0x7f0000000000)={{0x42, []}, {0x43, [0x44, 0x45, 0x46]}, 0x47})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 8, 0x42, 0, 0,
- instrCopyin, dataOffset + 8, argConst, 8, 0x43, 0, 0,
- instrCopyin, dataOffset + 16, argConst, 2, 0x44, 0, 0,
- instrCopyin, dataOffset + 18, argConst, 2, 0x45, 0, 0,
- instrCopyin, dataOffset + 20, argConst, 2, 0x46, 0, 0,
- instrCopyin, dataOffset + 22, argConst, 1, 0x47, 0, 0,
- callID("syz_test$align5"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 8, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x43, 0, 0,
+ execInstrCopyin, dataOffset + 16, execArgConst, 2, 0x44, 0, 0,
+ execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x45, 0, 0,
+ execInstrCopyin, dataOffset + 20, execArgConst, 2, 0x46, 0, 0,
+ execInstrCopyin, dataOffset + 22, execArgConst, 1, 0x47, 0, 0,
+ callID("syz_test$align5"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$align6(&(0x7f0000000000)={0x42, [0x43]})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 1, 0x42, 0, 0,
- instrCopyin, dataOffset + 4, argConst, 4, 0x43, 0, 0,
- callID("syz_test$align6"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 4, execArgConst, 4, 0x43, 0, 0,
+ callID("syz_test$align6"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$union0(&(0x7f0000000000)={0x1, @f2=0x2})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 8, 1, 0, 0,
- instrCopyin, dataOffset + 8, argConst, 1, 2, 0, 0,
- callID("syz_test$union0"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 8, 1, 0, 0,
+ execInstrCopyin, dataOffset + 8, execArgConst, 1, 2, 0, 0,
+ callID("syz_test$union0"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$union1(&(0x7f0000000000)={@f1=0x42, 0x43})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 4, 0x42, 0, 0,
- instrCopyin, dataOffset + 8, argConst, 1, 0x43, 0, 0,
- callID("syz_test$union1"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x43, 0, 0,
+ callID("syz_test$union1"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$union2(&(0x7f0000000000)={@f1=0x42, 0x43})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 4, 0x42, 0, 0,
- instrCopyin, dataOffset + 4, argConst, 1, 0x43, 0, 0,
- callID("syz_test$union2"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x43, 0, 0,
+ callID("syz_test$union2"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$array0(&(0x7f0000000000)={0x1, [@f0=0x2, @f1=0x3], 0x4})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 1, 1, 0, 0,
- instrCopyin, dataOffset + 1, argConst, 2, 2, 0, 0,
- instrCopyin, dataOffset + 3, argConst, 8, 3, 0, 0,
- instrCopyin, dataOffset + 11, argConst, 8, 4, 0, 0,
- callID("syz_test$array0"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 1, 1, 0, 0,
+ execInstrCopyin, dataOffset + 1, execArgConst, 2, 2, 0, 0,
+ execInstrCopyin, dataOffset + 3, execArgConst, 8, 3, 0, 0,
+ execInstrCopyin, dataOffset + 11, execArgConst, 8, 4, 0, 0,
+ callID("syz_test$array0"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$array1(&(0x7f0000000000)={0x42, \"0102030405\"})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 1, 0x42, 0, 0,
- instrCopyin, dataOffset + 1, argData, 5, 0x0504030201,
- callID("syz_test$array1"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 1, execArgData, 5, 0x0504030201,
+ callID("syz_test$array1"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$array2(&(0x7f0000000000)={0x42, \"aaaaaaaabbbbbbbbccccccccdddddddd\", 0x43})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 2, 0x42, 0, 0,
- instrCopyin, dataOffset + 2, argData, 16, 0xbbbbbbbbaaaaaaaa, 0xddddddddcccccccc,
- instrCopyin, dataOffset + 18, argConst, 2, 0x43, 0, 0,
- callID("syz_test$array2"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 2, execArgData, 16, 0xbbbbbbbbaaaaaaaa, 0xddddddddcccccccc,
+ execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x43, 0, 0,
+ callID("syz_test$array2"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$end0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 1, 0x42, 0, 0,
- instrCopyin, dataOffset + 1, argConst, 2, 0x4200, 0, 0,
- instrCopyin, dataOffset + 3, argConst, 4, 0x42000000, 0, 0,
- instrCopyin, dataOffset + 7, argConst, 8, 0x4200000000000000, 0, 0,
- callID("syz_test$end0"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x4200, 0, 0,
+ execInstrCopyin, dataOffset + 3, execArgConst, 4, 0x42000000, 0, 0,
+ execInstrCopyin, dataOffset + 7, execArgConst, 8, 0x4200000000000000, 0, 0,
+ callID("syz_test$end0"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$end1(&(0x7f0000000000)={0xe, 0x42, 0x1})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 2, 0x0e00, 0, 0,
- instrCopyin, dataOffset + 2, argConst, 4, 0x42000000, 0, 0,
- instrCopyin, dataOffset + 6, argConst, 8, 0x0100000000000000, 0, 0,
- callID("syz_test$end1"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x0e00, 0, 0,
+ execInstrCopyin, dataOffset + 2, execArgConst, 4, 0x42000000, 0, 0,
+ execInstrCopyin, dataOffset + 6, execArgConst, 8, 0x0100000000000000, 0, 0,
+ callID("syz_test$end1"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$bf0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 2, 0x42, 0, 10,
- instrCopyin, dataOffset + 8, argConst, 8, 0x42, 0, 0,
- instrCopyin, dataOffset + 16, argConst, 2, 0x42, 0, 5,
- instrCopyin, dataOffset + 16, argConst, 2, 0x42, 5, 6,
- instrCopyin, dataOffset + 20, argConst, 4, 0x42, 0, 15,
- instrCopyin, dataOffset + 24, argConst, 2, 0x42, 0, 11,
- instrCopyin, dataOffset + 26, argConst, 2, 0x4200, 0, 11,
- instrCopyin, dataOffset + 28, argConst, 1, 0x42, 0, 0,
- callID("syz_test$bf0"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42, 0, 10,
+ execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x42, 0, 0,
+ execInstrCopyin, dataOffset + 16, execArgConst, 2, 0x42, 0, 5,
+ execInstrCopyin, dataOffset + 16, execArgConst, 2, 0x42, 5, 6,
+ execInstrCopyin, dataOffset + 20, execArgConst, 4, 0x42, 0, 15,
+ execInstrCopyin, dataOffset + 24, execArgConst, 2, 0x42, 0, 11,
+ execInstrCopyin, dataOffset + 26, execArgConst, 2, 0x4200, 0, 11,
+ execInstrCopyin, dataOffset + 28, execArgConst, 1, 0x42, 0, 0,
+ callID("syz_test$bf0"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$bf1(&(0x7f0000000000)={{0x42, 0x42, 0x42}, 0x42})",
[]uint64{
- instrCopyin, dataOffset + 0, argConst, 4, 0x42, 0, 10,
- instrCopyin, dataOffset + 0, argConst, 4, 0x42, 10, 10,
- instrCopyin, dataOffset + 0, argConst, 4, 0x42, 20, 10,
- instrCopyin, dataOffset + 4, argConst, 1, 0x42, 0, 0,
- callID("syz_test$bf1"), 1, argConst, ptrSize, dataOffset, 0, 0,
- instrEOF,
+ execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, 0, 10,
+ execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, 10, 10,
+ execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, 20, 10,
+ execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x42, 0, 0,
+ callID("syz_test$bf1"), 1, execArgConst, ptrSize, dataOffset, 0, 0,
+ execInstrEOF,
},
+ nil,
},
{
"syz_test$res1(0xffff)",
[]uint64{
- callID("syz_test$res1"), 1, argConst, 4, 0xffff, 0, 0,
- instrEOF,
+ callID("syz_test$res1"), 1, execArgConst, 4, 0xffff, 0, 0,
+ execInstrEOF,
},
+ nil,
},
}
@@ -269,15 +289,13 @@ func TestSerializeForExec(t *testing.T) {
if err != nil {
t.Fatalf("failed to deserialize prog %v: %v", i, err)
}
- if _, err := p.SerializeForExec(buf, i%16); err != nil {
+ n, err := p.SerializeForExec(buf, i%16)
+ if err != nil {
t.Fatalf("failed to serialize: %v", err)
}
w := new(bytes.Buffer)
binary.Write(w, binary.LittleEndian, test.serialized)
- data := buf
- if len(data) > len(w.Bytes()) {
- data = data[:len(w.Bytes())]
- }
+ data := buf[:n]
if !bytes.Equal(data, w.Bytes()) {
got := make([]uint64, len(data)/8)
binary.Read(bytes.NewReader(data), binary.LittleEndian, &got)
@@ -285,7 +303,15 @@ func TestSerializeForExec(t *testing.T) {
t.Logf("got: %v", got)
t.Fatalf("mismatch")
}
-
+ decoded, err := target.DeserializeExec(data)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if test.decoded != nil && !reflect.DeepEqual(decoded, *test.decoded) {
+ t.Logf("want: %#v", *test.decoded)
+ t.Logf("got: %#v", decoded)
+ t.Fatalf("decoded mismatch")
+ }
})
}
}