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
This commit is contained in:
Dmitry Vyukov 2017-12-22 11:47:04 +01:00
parent 6f298a18e5
commit 3645389673
12 changed files with 296 additions and 183 deletions

View File

@ -7,6 +7,7 @@
#define _GNU_SOURCE
#endif
#include <endian.h>
#include <sys/syscall.h>
#include <unistd.h>
#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE)

View File

@ -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)

View File

@ -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

View File

@ -8,6 +8,7 @@ var commonHeaderLinux = `
#define _GNU_SOURCE
#endif
#include <endian.h>
#include <sys/syscall.h>
#include <unistd.h>
#if defined(SYZ_EXECUTOR) || defined(SYZ_THREADED) || defined(SYZ_COLLIDE)

View File

@ -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

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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{

View File

@ -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)
}
}
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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: