From 3645389673af4c62a636cfe36f258ae770e8fb6b Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Fri, 22 Dec 2017 11:47:04 +0100 Subject: [PATCH] pkg/csource: fix handling of proc types Generated program always uses pid=0 even when there are multiple processes. Make each process use own pid. Unfortunately required to do quite significant changes to prog, because the current format only supported fixed pid. Fixes #490 --- executor/common_linux.h | 1 + executor/executor.h | 56 +++++--- pkg/csource/csource.go | 54 +++++--- pkg/csource/linux_common.go | 1 + pkg/ipc/ipc.go | 2 +- prog/checksum.go | 10 +- prog/checksum_test.go | 4 +- prog/decodeexec.go | 11 +- prog/encoding_test.go | 2 +- prog/encodingexec.go | 40 +++--- prog/encodingexec_test.go | 255 ++++++++++++++++++++++++------------ prog/prog.go | 43 ++---- 12 files changed, 296 insertions(+), 183 deletions(-) diff --git a/executor/common_linux.h b/executor/common_linux.h index 6c43907b..90a87358 100644 --- a/executor/common_linux.h +++ b/executor/common_linux.h @@ -7,6 +7,7 @@ #define _GNU_SOURCE #endif +#include #include #include #if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) diff --git a/executor/executor.h b/executor/executor.h index 13072a35..84cefecf 100644 --- a/executor/executor.h +++ b/executor/executor.h @@ -183,6 +183,7 @@ uint32_t* write_output(uint32_t v); void write_completed(uint32_t completed); uint64_t read_input(uint64_t** input_posp, bool peek = false); uint64_t read_arg(uint64_t** input_posp); +uint64_t read_const_arg(uint64_t** input_posp, uint64_t* size_p, uint64_t* bf_off_p, uint64_t* bf_len_p); uint64_t read_result(uint64_t** input_posp); void copyin(char* addr, uint64_t val, uint64_t size, uint64_t bf_off, uint64_t bf_len); uint64_t copyout(char* addr, uint64_t size); @@ -309,22 +310,22 @@ retry: if (call_num == instr_copyin) { char* addr = (char*)read_input(&input_pos); uint64_t typ = read_input(&input_pos); - uint64_t size = read_input(&input_pos); debug("copyin to %p\n", addr); switch (typ) { case arg_const: { - uint64_t arg = read_input(&input_pos); - uint64_t bf_off = read_input(&input_pos); - uint64_t bf_len = read_input(&input_pos); + uint64_t size, bf_off, bf_len; + uint64_t arg = read_const_arg(&input_pos, &size, &bf_off, &bf_len); copyin(addr, arg, size, bf_off, bf_len); break; } case arg_result: { + uint64_t size = read_input(&input_pos); uint64_t val = read_result(&input_pos); copyin(addr, val, size, 0, 0); break; } case arg_data: { + uint64_t size = read_input(&input_pos); NONFAILING(memcpy(addr, input_pos, size)); // Read out the data. for (uint64_t i = 0; i < (size + 7) / 8; i++) @@ -333,12 +334,12 @@ retry: } case arg_csum: { debug("checksum found at %llx\n", addr); + uint64_t size = read_input(&input_pos); char* csum_addr = addr; - uint64_t csum_size = size; uint64_t csum_kind = read_input(&input_pos); switch (csum_kind) { case arg_csum_inet: { - if (csum_size != 2) { + if (size != 2) { fail("inet checksum must be 2 bytes, not %lu", size); } debug("calculating checksum for %llx\n", csum_addr); @@ -725,25 +726,46 @@ uint64_t copyout(char* addr, uint64_t size) uint64_t read_arg(uint64_t** input_posp) { uint64_t typ = read_input(input_posp); - uint64_t size = read_input(input_posp); - (void)size; - uint64_t arg = 0; switch (typ) { case arg_const: { - arg = read_input(input_posp); - // Bitfields can't be args of a normal syscall, so just ignore them. - read_input(input_posp); // bit field offset - read_input(input_posp); // bit field length - break; + uint64_t size, bf_off, bf_len; + return read_const_arg(input_posp, &size, &bf_off, &bf_len); } case arg_result: { - arg = read_result(input_posp); - break; + read_input(input_posp); // size + return read_result(input_posp); } default: fail("bad argument type %lu", typ); } - return arg; +} + +uint64_t read_const_arg(uint64_t** input_posp, uint64_t* size_p, uint64_t* bf_off_p, uint64_t* bf_len_p) +{ + uint64_t meta = read_input(input_posp); + uint64_t val = read_input(input_posp); + *size_p = meta & 0xff; + bool be = meta & (1 << 8); + *bf_off_p = (meta >> 16) & 0xff; + *bf_len_p = (meta >> 24) & 0xff; + uint64_t pid_stride = meta >> 32; + val += pid_stride * flag_pid; + if (be) { + switch (*size_p) { + case 2: + val = htobe16(val); + break; + case 4: + val = htobe32(val); + break; + case 8: + val = htobe64(val); + break; + default: + fail("bad big-endian int size %d", (int)*size_p); + } + } + return val; } uint64_t read_result(uint64_t** input_posp) diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index 1fb00d1c..38814c3b 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -42,7 +42,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { ctx.generateSyscallDefines() exec := make([]byte, prog.ExecBufferSize) - progSize, err := ctx.p.SerializeForExec(exec, 0) + progSize, err := ctx.p.SerializeForExec(exec) if err != nil { return nil, fmt.Errorf("failed to serialize program: %v", err) } @@ -54,6 +54,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { if nvar != 0 { ctx.printf("long r[%v];\n", nvar) } + if opts.Procs > 1 { + ctx.printf("uint64_t procid;\n") + } if !opts.Repeat { ctx.generateTestFunc(calls, nvar, "loop") @@ -102,6 +105,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { ctx.print("\tint i;") ctx.printf("\tfor (i = 0; i < %v; i++) {\n", opts.Procs) ctx.print("\t\tif (fork() == 0) {\n") + ctx.printf("\t\t\tprocid = i;\n") if opts.HandleSegv { ctx.printf("\t\t\tinstall_segv_handler();\n") } @@ -256,16 +260,6 @@ func (ctx *context) generateSyscallDefines() { } 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) - } - if arg.AddOp != 0 { - res = fmt.Sprintf("%v+%v", res, arg.AddOp) - } - return res - } var calls []string csumSeq := 0 for ci, call := range p.Calls { @@ -275,15 +269,16 @@ func (ctx *context) generateCalls(p prog.ExecProg) ([]string, uint64) { switch arg := copyin.Arg.(type) { case prog.ExecArgConst: 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) + fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = %v);\n", + arg.Size*8, copyin.Addr, ctx.constArgToStr(arg)) } else { - 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) + fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v_t, 0x%x, %v, %v, %v));\n", + arg.Size*8, copyin.Addr, ctx.constArgToStr(arg), + arg.BitfieldOffset, arg.BitfieldLength) } case prog.ExecArgResult: fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = %v);\n", - arg.Size*8, copyin.Addr, resultRef(arg)) + arg.Size*8, copyin.Addr, ctx.resultArgToStr(arg)) case prog.ExecArgData: fmt.Fprintf(w, "\tNONFAILING(memcpy((void*)0x%x, \"%s\", %v));\n", copyin.Addr, toCString(arg.Data), len(arg.Data)) @@ -349,9 +344,9 @@ func (ctx *context) generateCalls(p prog.ExecProg) ([]string, uint64) { } switch arg := arg.(type) { case prog.ExecArgConst: - fmt.Fprintf(w, "0x%xul", arg.Value) + fmt.Fprintf(w, "%v", ctx.constArgToStr(arg)) case prog.ExecArgResult: - fmt.Fprintf(w, "%v", resultRef(arg)) + fmt.Fprintf(w, "%v", ctx.resultArgToStr(arg)) default: panic(fmt.Sprintf("unknown arg type: %+v", arg)) } @@ -382,6 +377,29 @@ func (ctx *context) generateCalls(p prog.ExecProg) ([]string, uint64) { return calls, p.NumVars } +func (ctx *context) constArgToStr(arg prog.ExecArgConst) string { + mask := (uint64(1) << (arg.Size * 8)) - 1 + val := fmt.Sprintf("0x%x", arg.Value&mask) + if ctx.opts.Procs > 1 && arg.PidStride != 0 { + val += fmt.Sprintf("+procid*0x%xul", arg.PidStride) + } + if arg.BigEndian { + val = fmt.Sprintf("htobe%v(%v)", arg.Size*8, val) + } + return val +} + +func (ctx *context) resultArgToStr(arg prog.ExecArgResult) string { + res := fmt.Sprintf("r[%v]", arg.Index) + if arg.DivOp != 0 { + res = fmt.Sprintf("%v/%v", res, arg.DivOp) + } + if arg.AddOp != 0 { + res = fmt.Sprintf("%v+%v", res, arg.AddOp) + } + return res +} + func toCString(data []byte) []byte { if len(data) == 0 { return nil diff --git a/pkg/csource/linux_common.go b/pkg/csource/linux_common.go index 14a7d91d..5d207bd1 100644 --- a/pkg/csource/linux_common.go +++ b/pkg/csource/linux_common.go @@ -8,6 +8,7 @@ var commonHeaderLinux = ` #define _GNU_SOURCE #endif +#include #include #include #if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE) diff --git a/pkg/ipc/ipc.go b/pkg/ipc/ipc.go index 7aa57ded..5b716b6e 100644 --- a/pkg/ipc/ipc.go +++ b/pkg/ipc/ipc.go @@ -305,7 +305,7 @@ func (env *Env) Exec(opts *ExecOpts, p *prog.Prog) (output []byte, info []CallIn }) } // Copy-in serialized program. - progSize, err := p.SerializeForExec(env.in, env.pid) + progSize, err := p.SerializeForExec(env.in) if err != nil { err0 = fmt.Errorf("executor %v: failed to serialize: %v", env.pid, err) return diff --git a/prog/checksum.go b/prog/checksum.go index b5226e71..f1d2c0dd 100644 --- a/prog/checksum.go +++ b/prog/checksum.go @@ -59,7 +59,7 @@ func extractHeaderParamsIPv6(arg Arg) (Arg, Arg) { return srcAddr, dstAddr } -func composePseudoCsumIPv4(tcpPacket, srcAddr, dstAddr Arg, protocol uint8, pid int) CsumInfo { +func composePseudoCsumIPv4(tcpPacket, srcAddr, dstAddr Arg, protocol uint8) CsumInfo { info := CsumInfo{Kind: CsumInet} info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, srcAddr, 0, 0}) info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, dstAddr, 0, 0}) @@ -69,7 +69,7 @@ func composePseudoCsumIPv4(tcpPacket, srcAddr, dstAddr Arg, protocol uint8, pid return info } -func composePseudoCsumIPv6(tcpPacket, srcAddr, dstAddr Arg, protocol uint8, pid int) CsumInfo { +func composePseudoCsumIPv6(tcpPacket, srcAddr, dstAddr Arg, protocol uint8) CsumInfo { info := CsumInfo{Kind: CsumInet} info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, srcAddr, 0, 0}) info.Chunks = append(info.Chunks, CsumChunk{CsumChunkArg, dstAddr, 0, 0}) @@ -95,7 +95,7 @@ func findCsummedArg(arg Arg, typ *CsumType, parentsMap map[Arg]Arg) Arg { panic(fmt.Sprintf("csum field '%v' references non existent field '%v'", typ.FieldName(), typ.Buf)) } -func calcChecksumsCall(c *Call, pid int) map[Arg]CsumInfo { +func calcChecksumsCall(c *Call) map[Arg]CsumInfo { var inetCsumFields []Arg var pseudoCsumFields []Arg @@ -172,9 +172,9 @@ func calcChecksumsCall(c *Call, pid int) map[Arg]CsumInfo { protocol := uint8(typ.Protocol) var info CsumInfo if ipv4HeaderParsed { - info = composePseudoCsumIPv4(csummedArg, ipSrcAddr, ipDstAddr, protocol, pid) + info = composePseudoCsumIPv4(csummedArg, ipSrcAddr, ipDstAddr, protocol) } else { - info = composePseudoCsumIPv6(csummedArg, ipSrcAddr, ipDstAddr, protocol, pid) + info = composePseudoCsumIPv6(csummedArg, ipSrcAddr, ipDstAddr, protocol) } csumMap[arg] = info } diff --git a/prog/checksum_test.go b/prog/checksum_test.go index d466cf2c..75e18ab7 100644 --- a/prog/checksum_test.go +++ b/prog/checksum_test.go @@ -15,12 +15,12 @@ func TestChecksumCalcRandom(t *testing.T) { for i := 0; i < iters; i++ { p := target.Generate(rs, 10, nil) for _, call := range p.Calls { - CalcChecksumsCall(call, i%32) + CalcChecksumsCall(call) } for try := 0; try <= 10; try++ { p.Mutate(rs, 10, nil, nil) for _, call := range p.Calls { - CalcChecksumsCall(call, i%32) + CalcChecksumsCall(call) } } } diff --git a/prog/decodeexec.go b/prog/decodeexec.go index e62569b4..a1646178 100644 --- a/prog/decodeexec.go +++ b/prog/decodeexec.go @@ -38,6 +38,8 @@ type ExecArgConst struct { Value uint64 BitfieldOffset uint64 BitfieldLength uint64 + PidStride uint64 + BigEndian bool } type ExecArgResult struct { @@ -127,11 +129,14 @@ func (dec *execDecoder) parse() { func (dec *execDecoder) readArg() ExecArg { switch typ := dec.read(); typ { case execArgConst: + meta := dec.read() return ExecArgConst{ - Size: dec.read(), Value: dec.read(), - BitfieldOffset: dec.read(), - BitfieldLength: dec.read(), + Size: meta & 0xff, + BitfieldOffset: (meta >> 16) & 0xff, + BitfieldLength: (meta >> 24) & 0xff, + PidStride: meta >> 32, + BigEndian: (meta & (1 << 8)) != 0, } case execArgResult: return ExecArgResult{ diff --git a/prog/encoding_test.go b/prog/encoding_test.go index 5fce3014..6c063b5a 100644 --- a/prog/encoding_test.go +++ b/prog/encoding_test.go @@ -159,7 +159,7 @@ func TestDeserialize(t *testing.T) { t.Fatalf("deserialization should have failed with:\n%s\ndata:\n%s\n", test.err, test.data) } - p.SerializeForExec(buf, 0) + p.SerializeForExec(buf) } } } diff --git a/prog/encodingexec.go b/prog/encodingexec.go index 86ec1f63..2a41e4a5 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -73,7 +73,7 @@ func (s ByPhysicalAddr) Less(i, j int) bool { // SerializeForExec serializes program p for execution by process pid into the provided buffer. // Returns number of bytes written to the buffer. // If the provided buffer is too small for the program an error is returned. -func (p *Prog) SerializeForExec(buffer []byte, pid int) (int, error) { +func (p *Prog) SerializeForExec(buffer []byte) (int, error) { if debug { if err := p.validate(); err != nil { panic(fmt.Errorf("serializing invalid program: %v", err)) @@ -88,7 +88,7 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) (int, error) { } for _, c := range p.Calls { // Calculate checksums. - csumMap := calcChecksumsCall(c, pid) + csumMap := calcChecksumsCall(c) var csumUses map[Arg]bool if csumMap != nil { csumUses = make(map[Arg]bool) @@ -125,7 +125,7 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) (int, error) { if !IsPad(arg1.Type()) && arg1.Type().Dir() != DirOut { w.write(execInstrCopyin) w.write(addr) - w.writeArg(arg1, pid) + w.writeArg(arg1) } }) } @@ -181,7 +181,7 @@ func (p *Prog) SerializeForExec(buffer []byte, pid int) (int, error) { } w.write(uint64(len(c.Args))) for _, arg := range c.Args { - w.writeArg(arg, pid) + w.writeArg(arg) } // Generate copyout instructions that persist interesting return values. foreachArg(c, func(arg, base Arg, _ *[]Arg) { @@ -258,21 +258,15 @@ func (w *execContext) write(v uint64) { w.buf = w.buf[8:] } -func (w *execContext) writeArg(arg Arg, pid int) { +func (w *execContext) writeArg(arg Arg) { switch a := arg.(type) { case *ConstArg: - w.write(execArgConst) - w.write(a.Size()) - w.write(a.Value(pid)) - w.write(a.Type().BitfieldOffset()) - w.write(a.Type().BitfieldLength()) + val, pidStride, bigEndian := a.Value() + w.writeConstArg(a.Size(), val, a.Type().BitfieldOffset(), a.Type().BitfieldLength(), + pidStride, bigEndian) case *ResultArg: if a.Res == nil { - w.write(execArgConst) - w.write(a.Size()) - w.write(a.Val) - w.write(0) // bit field offset - w.write(0) // bit field length + w.writeConstArg(a.Size(), a.Val, 0, 0, 0, false) } else { info, ok := w.args[a.Res] if !ok { @@ -285,11 +279,7 @@ func (w *execContext) writeArg(arg Arg, pid int) { w.write(a.OpAdd) } case *PointerArg: - 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 + w.writeConstArg(a.Size(), w.target.physicalAddr(arg), 0, 0, 0, false) case *DataArg: data := a.Data() w.write(execArgData) @@ -308,3 +298,13 @@ func (w *execContext) writeArg(arg Arg, pid int) { panic("unknown arg type") } } + +func (w *execContext) writeConstArg(size, val, bfOffset, bfLength, pidStride uint64, bigEndian bool) { + w.write(execArgConst) + meta := size | bfOffset<<16 | bfLength<<24 | pidStride<<32 + if bigEndian { + meta |= 1 << 8 + } + w.write(meta) + w.write(val) +} diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go index 15d58d87..5c2c1853 100644 --- a/prog/encodingexec_test.go +++ b/prog/encodingexec_test.go @@ -16,7 +16,7 @@ func TestSerializeForExecRandom(t *testing.T) { buf := make([]byte, ExecBufferSize) for i := 0; i < iters; i++ { p := target.Generate(rs, 10, nil) - n, err := p.SerializeForExec(buf, i%16) + n, err := p.SerializeForExec(buf) if err != nil { t.Fatalf("failed to serialize: %v", err) } @@ -65,11 +65,11 @@ func TestSerializeForExec(t *testing.T) { "syz_test$int(0x1, 0x2, 0x3, 0x4, 0x5)", []uint64{ callID("syz_test$int"), ExecNoCopyout, 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, + execArgConst, 8, 1, + execArgConst, 1, 2, + execArgConst, 2, 3, + execArgConst, 4, 4, + execArgConst, 8, 5, execInstrEOF, }, nil, @@ -77,12 +77,12 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$align0(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 2, 1, + execInstrCopyin, dataOffset + 4, execArgConst, 4, 2, + execInstrCopyin, dataOffset + 8, execArgConst, 1, 3, + execInstrCopyin, dataOffset + 10, execArgConst, 2, 4, + execInstrCopyin, dataOffset + 16, execArgConst, 8, 5, + callID("syz_test$align0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -90,12 +90,12 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$align1(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 2, 1, + execInstrCopyin, dataOffset + 2, execArgConst, 4, 2, + execInstrCopyin, dataOffset + 6, execArgConst, 1, 3, + execInstrCopyin, dataOffset + 7, execArgConst, 2, 4, + execInstrCopyin, dataOffset + 9, execArgConst, 8, 5, + callID("syz_test$align1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -103,10 +103,10 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$align2(&(0x7f0000000000)={0x42, {[0x43]}, {[0x44]}})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43, + execInstrCopyin, dataOffset + 4, execArgConst, 2, 0x44, + callID("syz_test$align2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -114,10 +114,10 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$align3(&(0x7f0000000000)={0x42, {0x43}, {0x44}})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 1, execArgConst, 1, 0x43, + execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44, + callID("syz_test$align3"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -125,10 +125,10 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$align4(&(0x7f0000000000)={{0x42, 0x43}, 0x44})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43, + execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44, + callID("syz_test$align4"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -136,13 +136,13 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$align5(&(0x7f0000000000)={{0x42, []}, {0x43, [0x44, 0x45, 0x46]}, 0x47})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 8, 0x42, + execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x43, + execInstrCopyin, dataOffset + 16, execArgConst, 2, 0x44, + execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x45, + execInstrCopyin, dataOffset + 20, execArgConst, 2, 0x46, + execInstrCopyin, dataOffset + 22, execArgConst, 1, 0x47, + callID("syz_test$align5"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -150,9 +150,9 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$align6(&(0x7f0000000000)={0x42, [0x43]})", []uint64{ - execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 0, 0, - execInstrCopyin, dataOffset + 4, execArgConst, 4, 0x43, 0, 0, - callID("syz_test$align6"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 4, execArgConst, 4, 0x43, + callID("syz_test$align6"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -160,9 +160,9 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$union0(&(0x7f0000000000)={0x1, @f2=0x2})", []uint64{ - execInstrCopyin, dataOffset + 0, execArgConst, 8, 1, 0, 0, - execInstrCopyin, dataOffset + 8, execArgConst, 1, 2, 0, 0, - callID("syz_test$union0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 8, 1, + execInstrCopyin, dataOffset + 8, execArgConst, 1, 2, + callID("syz_test$union0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -170,9 +170,9 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$union1(&(0x7f0000000000)={@f1=0x42, 0x43})", []uint64{ - execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, 0, 0, - execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x43, 0, 0, - callID("syz_test$union1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, + execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x43, + callID("syz_test$union1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -180,9 +180,9 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$union2(&(0x7f0000000000)={@f1=0x42, 0x43})", []uint64{ - execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, 0, 0, - execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x43, 0, 0, - callID("syz_test$union2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42, + execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x43, + callID("syz_test$union2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -190,11 +190,11 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$array0(&(0x7f0000000000)={0x1, [@f0=0x2, @f1=0x3], 0x4})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 1, 1, + execInstrCopyin, dataOffset + 1, execArgConst, 2, 2, + execInstrCopyin, dataOffset + 3, execArgConst, 8, 3, + execInstrCopyin, dataOffset + 11, execArgConst, 8, 4, + callID("syz_test$array0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -202,9 +202,9 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$array1(&(0x7f0000000000)={0x42, \"0102030405\"})", []uint64{ - execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, execInstrCopyin, dataOffset + 1, execArgData, 5, 0x0504030201, - callID("syz_test$array1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + callID("syz_test$array1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -212,10 +212,10 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$array2(&(0x7f0000000000)={0x42, \"aaaaaaaabbbbbbbbccccccccdddddddd\", 0x43})", []uint64{ - execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42, execInstrCopyin, dataOffset + 2, execArgData, 16, 0xbbbbbbbbaaaaaaaa, 0xddddddddcccccccc, - execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x43, 0, 0, - callID("syz_test$array2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x43, + callID("syz_test$array2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -223,11 +223,11 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$end0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42, + execInstrCopyin, dataOffset + 1, execArgConst, 2 | 1<<8, 0x42, + execInstrCopyin, dataOffset + 3, execArgConst, 4 | 1<<8, 0x42, + execInstrCopyin, dataOffset + 7, execArgConst, 8 | 1<<8, 0x42, + callID("syz_test$end0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -235,10 +235,10 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$end1(&(0x7f0000000000)={0xe, 0x42, 0x1})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 2 | 1<<8, 0xe, + execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x42, + execInstrCopyin, dataOffset + 6, execArgConst, 8 | 1<<8, 0x1, + callID("syz_test$end1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -246,27 +246,112 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$bf0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 2 | 0<<16 | 10<<24, 0x42, + execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x42, + execInstrCopyin, dataOffset + 16, execArgConst, 2 | 0<<16 | 5<<24, 0x42, + execInstrCopyin, dataOffset + 16, execArgConst, 2 | 5<<16 | 6<<24, 0x42, + execInstrCopyin, dataOffset + 20, execArgConst, 4 | 0<<16 | 15<<24, 0x42, + execInstrCopyin, dataOffset + 24, execArgConst, 2 | 0<<16 | 11<<24, 0x42, + execInstrCopyin, dataOffset + 26, execArgConst, 2 | 1<<8 | 0<<16 | 11<<24, 0x42, + execInstrCopyin, dataOffset + 28, execArgConst, 1, 0x42, + callID("syz_test$bf0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, - nil, + &ExecProg{ + Calls: []ExecCall{ + { + Meta: target.SyscallMap["syz_test$bf0"], + Index: ExecNoCopyout, + Args: []ExecArg{ + ExecArgConst{ + Size: ptrSize, + Value: dataOffset, + }, + }, + Copyin: []ExecCopyin{ + { + Addr: dataOffset + 0, + Arg: ExecArgConst{ + Size: 2, + Value: 0x42, + BitfieldOffset: 0, + BitfieldLength: 10, + }, + }, + { + Addr: dataOffset + 8, + Arg: ExecArgConst{ + Size: 8, + Value: 0x42, + }, + }, + { + Addr: dataOffset + 16, + Arg: ExecArgConst{ + Size: 2, + Value: 0x42, + BitfieldOffset: 0, + BitfieldLength: 5, + }, + }, + { + Addr: dataOffset + 16, + Arg: ExecArgConst{ + Size: 2, + Value: 0x42, + BitfieldOffset: 5, + BitfieldLength: 6, + }, + }, + { + Addr: dataOffset + 20, + Arg: ExecArgConst{ + Size: 4, + Value: 0x42, + BitfieldOffset: 0, + BitfieldLength: 15, + }, + }, + { + Addr: dataOffset + 24, + Arg: ExecArgConst{ + Size: 2, + Value: 0x42, + BitfieldOffset: 0, + BitfieldLength: 11, + }, + }, + { + Addr: dataOffset + 26, + Arg: ExecArgConst{ + Size: 2, + Value: 0x42, + BitfieldOffset: 0, + BitfieldLength: 11, + BigEndian: true, + }, + }, + { + Addr: dataOffset + 28, + Arg: ExecArgConst{ + Size: 1, + Value: 0x42, + }, + }, + }, + }, + }, + NumVars: 0, + }, }, { "syz_test$bf1(&(0x7f0000000000)={{0x42, 0x42, 0x42}, 0x42})", []uint64{ - 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"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, 0, 0, + execInstrCopyin, dataOffset + 0, execArgConst, 4 | 0<<16 | 10<<24, 0x42, + execInstrCopyin, dataOffset + 0, execArgConst, 4 | 10<<16 | 10<<24, 0x42, + execInstrCopyin, dataOffset + 0, execArgConst, 4 | 20<<16 | 10<<24, 0x42, + execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x42, + callID("syz_test$bf1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset, execInstrEOF, }, nil, @@ -274,7 +359,7 @@ func TestSerializeForExec(t *testing.T) { { "syz_test$res1(0xffff)", []uint64{ - callID("syz_test$res1"), ExecNoCopyout, 1, execArgConst, 4, 0xffff, 0, 0, + callID("syz_test$res1"), ExecNoCopyout, 1, execArgConst, 4, 0xffff, execInstrEOF, }, nil, @@ -289,7 +374,7 @@ func TestSerializeForExec(t *testing.T) { if err != nil { t.Fatalf("failed to deserialize prog %v: %v", i, err) } - n, err := p.SerializeForExec(buf, i%16) + n, err := p.SerializeForExec(buf) if err != nil { t.Fatalf("failed to serialize: %v", err) } diff --git a/prog/prog.go b/prog/prog.go index f78aac58..4a612d9b 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -63,31 +63,28 @@ func (arg *ConstArg) Size() uint64 { return arg.typ.Size() } -// Returns value taking endianness and executor pid into consideration. -func (arg *ConstArg) Value(pid int) uint64 { +// Value returns value, pid stride and endianness. +func (arg *ConstArg) Value() (uint64, uint64, bool) { switch typ := (*arg).Type().(type) { case *IntType: - return encodeValue(arg.Val, typ.Size(), typ.BigEndian) + return arg.Val, 0, typ.BigEndian case *ConstType: - return encodeValue(arg.Val, typ.Size(), typ.BigEndian) + return arg.Val, 0, typ.BigEndian case *FlagsType: - return encodeValue(arg.Val, typ.Size(), typ.BigEndian) + return arg.Val, 0, typ.BigEndian case *LenType: - return encodeValue(arg.Val, typ.Size(), typ.BigEndian) + return arg.Val, 0, typ.BigEndian case *CsumType: // Checksums are computed dynamically in executor. - return 0 + return 0, 0, false case *ResourceType: - if t, ok := typ.Desc.Type.(*IntType); ok { - return encodeValue(arg.Val, t.Size(), t.BigEndian) - } else { - panic(fmt.Sprintf("bad base type for a resource: %v", t)) - } + t := typ.Desc.Type.(*IntType) + return arg.Val, 0, t.BigEndian case *ProcType: - val := typ.ValuesStart + typ.ValuesPerProc*uint64(pid) + arg.Val - return encodeValue(val, typ.Size(), typ.BigEndian) + return typ.ValuesStart + arg.Val, typ.ValuesPerProc, typ.BigEndian + default: + panic(fmt.Sprintf("unknown ConstArg type %#v", typ)) } - return arg.Val } // Used for PtrType and VmaType. @@ -281,22 +278,6 @@ func InnerArg(arg Arg) Arg { return arg // Not a pointer. } -func encodeValue(value uint64, size uint64, bigEndian bool) uint64 { - if !bigEndian { - return value - } - switch size { - case 2: - return uint64(swap16(uint16(value))) - case 4: - return uint64(swap32(uint32(value))) - case 8: - return swap64(value) - default: - panic(fmt.Sprintf("bad size %v for value %v", size, value)) - } -} - func defaultArg(t Type) Arg { switch typ := t.(type) { case *IntType, *ConstType, *FlagsType, *LenType, *ProcType, *CsumType: