aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--executor/executor.h42
-rw-r--r--pkg/csource/csource.go94
-rw-r--r--prog/any_test.go2
-rw-r--r--prog/decodeexec.go38
-rw-r--r--prog/encodingexec.go1
-rw-r--r--prog/encodingexec_test.go2
-rw-r--r--prog/minimization_test.go4
-rw-r--r--prog/prog.go4
8 files changed, 98 insertions, 89 deletions
diff --git a/executor/executor.h b/executor/executor.h
index 5f4db5115..ee48981a9 100644
--- a/executor/executor.h
+++ b/executor/executor.h
@@ -76,11 +76,6 @@ bool collide;
ALIGNED(64 << 10)
char input_data[kMaxInput];
-// We use the default value instead of results of failed syscalls.
-// -1 is an invalid fd and an invalid address and deterministic,
-// so good enough for our purposes.
-const uint64 default_value = -1;
-
// Checksum kinds.
const uint64 arg_csum_inet = 0;
@@ -187,7 +182,7 @@ uint64 read_arg(uint64** input_posp);
uint64 read_const_arg(uint64** input_posp, uint64* size_p, uint64* bf_off_p, uint64* bf_len_p);
uint64 read_result(uint64** input_posp);
void copyin(char* addr, uint64 val, uint64 size, uint64 bf_off, uint64 bf_len);
-uint64 copyout(char* addr, uint64 size);
+bool copyout(char* addr, uint64 size, uint64* res);
void cover_open();
void cover_enable(thread_t* th);
void cover_reset(thread_t* th);
@@ -503,13 +498,15 @@ void handle_completion(thread_t* th)
switch (instr) {
case instr_copyout: {
uint64 index = read_input(&th->copyout_pos);
- char* addr = (char*)read_input(&th->copyout_pos);
- uint64 size = read_input(&th->copyout_pos);
- uint64 val = copyout(addr, size);
if (index >= kMaxCommands)
fail("result idx %lld overflows kMaxCommands", index);
- results[index].executed = true;
- results[index].val = val;
+ char* addr = (char*)read_input(&th->copyout_pos);
+ uint64 size = read_input(&th->copyout_pos);
+ uint64 val = 0;
+ if (copyout(addr, size, &val)) {
+ results[index].executed = true;
+ results[index].val = val;
+ }
debug("copyout 0x%llx from %p\n", val, addr);
break;
}
@@ -706,26 +703,29 @@ void copyin(char* addr, uint64 val, uint64 size, uint64 bf_off, uint64 bf_len)
});
}
-uint64 copyout(char* addr, uint64 size)
+bool copyout(char* addr, uint64 size, uint64* res)
{
- uint64 res = default_value;
- NONFAILING(switch (size) {
+ bool ok = false;
+ NONFAILING(
+ switch (size) {
case 1:
- res = *(uint8*)addr;
+ *res = *(uint8*)addr;
break;
case 2:
- res = *(uint16*)addr;
+ *res = *(uint16*)addr;
break;
case 4:
- res = *(uint32*)addr;
+ *res = *(uint32*)addr;
break;
case 8:
- res = *(uint64*)addr;
+ *res = *(uint64*)addr;
break;
default:
fail("copyout: bad argument size %llu", size);
- });
- return res;
+ }
+ __atomic_store_n(&ok, true, __ATOMIC_RELEASE);
+ );
+ return ok;
}
uint64 read_arg(uint64** input_posp)
@@ -778,9 +778,9 @@ uint64 read_result(uint64** input_posp)
uint64 idx = read_input(input_posp);
uint64 op_div = read_input(input_posp);
uint64 op_add = read_input(input_posp);
+ uint64 arg = read_input(input_posp);
if (idx >= kMaxCommands)
fail("command refers to bad result %lld", idx);
- uint64 arg = default_value;
if (results[idx].executed) {
arg = results[idx].val;
if (op_div != 0)
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index 5c1b0208e..904e0287e 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -27,7 +27,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
calls: make(map[string]uint64),
}
- calls, nvar, err := ctx.generateProgCalls(ctx.p)
+ calls, vars, err := ctx.generateProgCalls(ctx.p)
if err != nil {
return nil, err
}
@@ -53,15 +53,22 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
ctx.generateSyscallDefines()
- if nvar != 0 {
- ctx.printf("long r[%v];\n", nvar)
+ if len(vars) != 0 {
+ ctx.printf("uint64_t r[%v] = {", len(vars))
+ for i, v := range vars {
+ if i != 0 {
+ ctx.printf(", ")
+ }
+ ctx.printf("0x%x", v)
+ }
+ ctx.printf("};\n")
}
if opts.Procs > 1 {
ctx.printf("uint64_t procid;\n")
}
if !opts.Repeat {
- ctx.generateTestFunc(calls, nvar, "loop")
+ ctx.generateTestFunc(calls, len(vars) != 0, "loop")
ctx.print("int main()\n{\n")
for _, c := range mmapCalls {
@@ -85,7 +92,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
}
ctx.print("\treturn 0;\n}\n")
} else {
- ctx.generateTestFunc(calls, nvar, "test")
+ ctx.generateTestFunc(calls, len(vars) != 0, "test")
if opts.Procs <= 1 {
ctx.print("int main()\n{\n")
for _, c := range mmapCalls {
@@ -196,10 +203,13 @@ func (ctx *context) printf(str string, args ...interface{}) {
ctx.print(fmt.Sprintf(str, args...))
}
-func (ctx *context) generateTestFunc(calls []string, nvar uint64, name string) {
+func (ctx *context) generateTestFunc(calls []string, hasVars bool, name string) {
opts := ctx.opts
if !opts.Threaded && !opts.Collide {
ctx.printf("void %v()\n{\n", name)
+ if hasVars {
+ ctx.printf("\tlong res;")
+ }
if opts.Debug {
// Use debug to avoid: error: ‘debug’ defined but not used.
ctx.printf("\tdebug(\"%v\\n\");\n", name)
@@ -207,15 +217,15 @@ func (ctx *context) generateTestFunc(calls []string, nvar uint64, name string) {
if opts.Repro {
ctx.printf("\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
}
- if nvar != 0 {
- ctx.printf("\tmemset(r, -1, sizeof(r));\n")
- }
for _, c := range calls {
ctx.printf("%s", c)
}
ctx.printf("}\n\n")
} else {
ctx.printf("void execute_call(int call)\n{\n")
+ if hasVars {
+ ctx.printf("\tlong res;")
+ }
ctx.printf("\tswitch (call) {\n")
for i, c := range calls {
ctx.printf("\tcase %v:\n", i)
@@ -233,9 +243,6 @@ func (ctx *context) generateTestFunc(calls []string, nvar uint64, name string) {
if opts.Repro {
ctx.printf("\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
}
- if nvar != 0 {
- ctx.printf("\tmemset(r, -1, sizeof(r));\n")
- }
ctx.printf("\texecute(%v);\n", len(calls))
if opts.Collide {
ctx.printf("\tcollide = 1;\n")
@@ -265,21 +272,21 @@ func (ctx *context) generateSyscallDefines() {
ctx.printf("\n")
}
-func (ctx *context) generateProgCalls(p *prog.Prog) ([]string, uint64, error) {
+func (ctx *context) generateProgCalls(p *prog.Prog) ([]string, []uint64, error) {
exec := make([]byte, prog.ExecBufferSize)
progSize, err := p.SerializeForExec(exec)
if err != nil {
- return nil, 0, fmt.Errorf("failed to serialize program: %v", err)
+ return nil, nil, fmt.Errorf("failed to serialize program: %v", err)
}
decoded, err := ctx.target.DeserializeExec(exec[:progSize])
if err != nil {
- return nil, 0, err
+ return nil, nil, err
}
- calls, nvar := ctx.generateCalls(decoded)
- return calls, nvar, nil
+ calls, vars := ctx.generateCalls(decoded)
+ return calls, vars, nil
}
-func (ctx *context) generateCalls(p prog.ExecProg) ([]string, uint64) {
+func (ctx *context) generateCalls(p prog.ExecProg) ([]string, []uint64) {
var calls []string
csumSeq := 0
for ci, call := range p.Calls {
@@ -337,7 +344,6 @@ func (ctx *context) generateCalls(p prog.ExecProg) ([]string, uint64) {
callName := call.Meta.CallName
resCopyout := call.Index != prog.ExecNoCopyout
argCopyout := len(call.Copyout) != 0
- argCopyoutMultiple := len(call.Copyout) > 1
emitCall := ctx.opts.EnableTun || callName != "syz_emit_ethernet" &&
callName != "syz_extract_tcp_res"
// TODO: if we don't emit the call we must also not emit copyin, copyout and fault injection.
@@ -345,14 +351,8 @@ func (ctx *context) generateCalls(p prog.ExecProg) ([]string, uint64) {
if emitCall {
native := !strings.HasPrefix(callName, "syz_")
fmt.Fprintf(w, "\t")
- if argCopyout {
- fmt.Fprintf(w, "if (")
- if resCopyout {
- fmt.Fprintf(w, "(")
- }
- }
- if resCopyout {
- fmt.Fprintf(w, "r[%v] = ", call.Index)
+ if resCopyout || argCopyout {
+ fmt.Fprintf(w, "res = ")
}
if native {
fmt.Fprintf(w, "syscall(%v%v", ctx.sysTarget.SyscallPrefix, callName)
@@ -372,33 +372,31 @@ func (ctx *context) generateCalls(p prog.ExecProg) ([]string, uint64) {
panic(fmt.Sprintf("unknown arg type: %+v", arg))
}
}
- fmt.Fprintf(w, ")")
- if argCopyout {
- if resCopyout {
- fmt.Fprintf(w, ")")
- }
- fmt.Fprintf(w, " != -1)")
- if argCopyoutMultiple {
- fmt.Fprintf(w, " {")
- }
- } else {
- fmt.Fprintf(w, ";")
- }
- fmt.Fprintf(w, "\n")
+ fmt.Fprintf(w, ");\n")
}
// Copyout.
- for _, copyout := range call.Copyout {
- fmt.Fprintf(w, "\t\tNONFAILING(r[%v] = *(uint%v_t*)0x%x);\n",
- copyout.Index, copyout.Size*8, copyout.Addr)
- }
- if emitCall && argCopyoutMultiple {
- fmt.Fprintf(w, "\t}\n")
+ if resCopyout || argCopyout {
+ fmt.Fprintf(w, "\tif (res != -1)")
+ copyoutMultiple := len(call.Copyout) > 1 || resCopyout && len(call.Copyout) > 0
+ if copyoutMultiple {
+ fmt.Fprintf(w, " {")
+ }
+ fmt.Fprintf(w, "\n")
+ if resCopyout {
+ fmt.Fprintf(w, "\t\tr[%v] = res;\n", call.Index)
+ }
+ for _, copyout := range call.Copyout {
+ fmt.Fprintf(w, "\t\tNONFAILING(r[%v] = *(uint%v_t*)0x%x);\n",
+ copyout.Index, copyout.Size*8, copyout.Addr)
+ }
+ if copyoutMultiple {
+ fmt.Fprintf(w, "\t}\n")
+ }
}
-
calls = append(calls, w.String())
}
- return calls, p.NumVars
+ return calls, p.Vars
}
func (ctx *context) constArgToStr(arg prog.ExecArgConst) string {
diff --git a/prog/any_test.go b/prog/any_test.go
index eff50e946..104f77f9d 100644
--- a/prog/any_test.go
+++ b/prog/any_test.go
@@ -40,7 +40,7 @@ func TestSquash(t *testing.T) {
}{
{
`foo$any0(&(0x7f0000000000)={0x11, 0x11223344, 0x2233, 0x1122334455667788, [{0x0, @res32=0x0, 0x0, @i8=0x44, "aabb"}, {0x0, @res64=0x1, 0x0, @i32=0x11223344, "1122334455667788"}]})`,
- `foo$any0(&(0x7f0000000000)=ANY=[@ANYBLOB="1100000044332211223300000000000088776655443322110000000000000000", @ANYRES32, @ANYBLOB="00000000000000000000000044aabb000000000000000000", @ANYRES64=0x1, @ANYBLOB="0000000000000000443322111122334455667788"])`,
+ `foo$any0(&(0x7f0000000000)=ANY=[@ANYBLOB="1100000044332211223300000000000088776655443322110000000000000000", @ANYRES32=0x0, @ANYBLOB="00000000000000000000000044aabb000000000000000000", @ANYRES64=0x1, @ANYBLOB="0000000000000000443322111122334455667788"])`,
},
}
for i, test := range tests {
diff --git a/prog/decodeexec.go b/prog/decodeexec.go
index a16461782..f8c29a517 100644
--- a/prog/decodeexec.go
+++ b/prog/decodeexec.go
@@ -8,8 +8,8 @@ import (
)
type ExecProg struct {
- Calls []ExecCall
- NumVars uint64
+ Calls []ExecCall
+ Vars []uint64
}
type ExecCall struct {
@@ -43,10 +43,11 @@ type ExecArgConst struct {
}
type ExecArgResult struct {
- Size uint64
- Index uint64
- DivOp uint64
- AddOp uint64
+ Size uint64
+ Index uint64
+ DivOp uint64
+ AddOp uint64
+ Default uint64
}
type ExecArgData struct {
@@ -71,9 +72,13 @@ func (target *Target) DeserializeExec(exec []byte) (ExecProg, error) {
if dec.err != nil {
return ExecProg{}, dec.err
}
+ if uint64(len(dec.vars)) != dec.numVars {
+ return ExecProg{}, fmt.Errorf("mismatching number of vars: %v/%v",
+ len(dec.vars), dec.numVars)
+ }
p := ExecProg{
- Calls: dec.calls,
- NumVars: dec.numVars,
+ Calls: dec.calls,
+ Vars: dec.vars,
}
return p, nil
}
@@ -83,6 +88,7 @@ type execDecoder struct {
data []byte
err error
numVars uint64
+ vars []uint64
call ExecCall
calls []ExecCall
}
@@ -139,12 +145,18 @@ func (dec *execDecoder) readArg() ExecArg {
BigEndian: (meta & (1 << 8)) != 0,
}
case execArgResult:
- return ExecArgResult{
- Size: dec.read(),
- Index: dec.read(),
- DivOp: dec.read(),
- AddOp: dec.read(),
+ arg := ExecArgResult{
+ Size: dec.read(),
+ Index: dec.read(),
+ DivOp: dec.read(),
+ AddOp: dec.read(),
+ Default: dec.read(),
+ }
+ for uint64(len(dec.vars)) <= arg.Index {
+ dec.vars = append(dec.vars, 0)
}
+ dec.vars[arg.Index] = arg.Default
+ return arg
case execArgData:
return ExecArgData{
Data: dec.readBlob(dec.read()),
diff --git a/prog/encodingexec.go b/prog/encodingexec.go
index 8ecec3a03..ea01560d9 100644
--- a/prog/encodingexec.go
+++ b/prog/encodingexec.go
@@ -247,6 +247,7 @@ func (w *execContext) writeArg(arg Arg) {
w.write(info.Idx)
w.write(a.OpDiv)
w.write(a.OpAdd)
+ w.write(a.Type().(*ResourceType).Default())
}
case *PointerArg:
w.writeConstArg(a.Size(), w.target.PhysicalAddr(a), 0, 0, 0, false)
diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go
index 2ad19598e..1b3fb14b4 100644
--- a/prog/encodingexec_test.go
+++ b/prog/encodingexec_test.go
@@ -58,7 +58,6 @@ func TestSerializeForExec(t *testing.T) {
Index: ExecNoCopyout,
},
},
- NumVars: 0,
},
},
{
@@ -341,7 +340,6 @@ func TestSerializeForExec(t *testing.T) {
},
},
},
- NumVars: 0,
},
},
{
diff --git a/prog/minimization_test.go b/prog/minimization_test.go
index 5979ce7a2..70137fa65 100644
--- a/prog/minimization_test.go
+++ b/prog/minimization_test.go
@@ -20,7 +20,7 @@ func TestMinimize(t *testing.T) {
{
"mmap(&(0x7f0000000000/0x1000)=nil, 0x1000, 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
"sched_yield()\n" +
- "pipe2(&(0x7f0000000000)={0x0, 0x0}, 0x0)\n",
+ "pipe2(&(0x7f0000000000), 0x0)\n",
2,
func(p *Prog, callIndex int) bool {
if len(p.Calls) == 0 {
@@ -47,7 +47,7 @@ func TestMinimize(t *testing.T) {
return len(p.Calls) == 2 && p.Calls[0].Meta.Name == "mmap" && p.Calls[1].Meta.Name == "pipe2"
},
"mmap(&(0x7f0000000000/0x1000)=nil, 0x1000, 0x0, 0x0, 0xffffffffffffffff, 0x0)\n" +
- "pipe2(&(0x7f0000000000)={0xffffffffffffffff, 0xffffffffffffffff}, 0x0)\n",
+ "pipe2(&(0x7f0000000000), 0x0)\n",
1,
},
// Remove two dependent calls.
diff --git a/prog/prog.go b/prog/prog.go
index dadc02cd5..f9f088760 100644
--- a/prog/prog.go
+++ b/prog/prog.go
@@ -333,7 +333,7 @@ func (target *Target) defaultArg(t Type) Arg {
case *IntType, *ConstType, *FlagsType, *LenType, *ProcType, *CsumType:
return MakeConstArg(t, t.Default())
case *ResourceType:
- return MakeResultArg(t, nil, typ.Desc.Type.Default())
+ return MakeResultArg(t, nil, typ.Default())
case *BufferType:
if t.Dir() == DirOut {
var sz uint64
@@ -432,7 +432,7 @@ func (target *Target) isDefaultArg(arg Arg) bool {
case *ResultArg:
t := a.Type().(*ResourceType)
return a.Res == nil && a.OpDiv == 0 && a.OpAdd == 0 &&
- len(a.uses) == 0 && a.Val == t.Desc.Type.Default()
+ len(a.uses) == 0 && a.Val == t.Default()
}
return false
}