diff options
| -rw-r--r-- | pkg/csource/csource.go | 201 | ||||
| -rw-r--r-- | prog/decodeexec.go | 213 | ||||
| -rw-r--r-- | prog/encodingexec.go | 47 | ||||
| -rw-r--r-- | prog/encodingexec_test.go | 280 |
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") + } }) } } |
