2015-12-23 12:38:31 +00:00
|
|
|
// Copyright 2015 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.
|
|
|
|
|
2017-01-08 16:20:32 +00:00
|
|
|
// I heard you like shell...
|
2017-01-12 10:57:17 +00:00
|
|
|
//go:generate bash -c "echo -e '// AUTOGENERATED FROM executor/common.h\npackage csource\nvar commonHeader = `' > common.go; cat ../executor/common.h | sed -e '/#include \"common_kvm_amd64.h\"/ {' -e 'r ../executor/common_kvm_amd64.h' -e 'd' -e '}' - | sed -e '/#include \"common_kvm_arm64.h\"/ {' -e 'r ../executor/common_kvm_arm64.h' -e 'd' -e '}' - | sed -e '/#include \"kvm.h\"/ {' -e 'r ../executor/kvm.h' -e 'd' -e '}' - | sed -e '/#include \"kvm.S.h\"/ {' -e 'r ../executor/kvm.S.h' -e 'd' -e '}' - | egrep -v '^[ ]*//' | sed '/^[ ]*\\/\\/.*/d' | sed 's#[ ]*//.*##g' >> common.go; echo '`' >> common.go"
|
2017-02-01 09:16:19 +00:00
|
|
|
//go:generate go fmt common.go
|
2016-08-28 12:59:48 +00:00
|
|
|
|
2015-12-23 12:38:31 +00:00
|
|
|
package csource
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2016-10-18 19:07:40 +00:00
|
|
|
"io"
|
2015-12-23 12:38:31 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2015-12-23 12:50:02 +00:00
|
|
|
"strings"
|
2015-12-23 12:38:31 +00:00
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
"github.com/google/syzkaller/prog"
|
|
|
|
"github.com/google/syzkaller/sys"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Options struct {
|
2017-05-17 18:20:23 +00:00
|
|
|
Threaded bool
|
|
|
|
Collide bool
|
|
|
|
Repeat bool
|
|
|
|
Procs int
|
|
|
|
Sandbox string
|
|
|
|
|
2017-05-25 14:07:10 +00:00
|
|
|
Fault bool // inject fault into FaultCall/FaultNth
|
|
|
|
FaultCall int
|
|
|
|
FaultNth int
|
2017-05-17 18:20:23 +00:00
|
|
|
|
|
|
|
// These options allow for a more fine-tuned control over the generated C code.
|
|
|
|
EnableTun bool
|
2017-05-18 12:26:02 +00:00
|
|
|
UseTmpDir bool
|
2017-05-17 18:20:23 +00:00
|
|
|
|
|
|
|
// Generate code for use with repro package to prints log messages,
|
|
|
|
// which allows to distinguish between a hang and an absent crash.
|
|
|
|
Repro bool
|
2015-12-23 12:38:31 +00:00
|
|
|
}
|
|
|
|
|
2016-10-18 19:07:40 +00:00
|
|
|
func Write(p *prog.Prog, opts Options) ([]byte, error) {
|
2017-01-20 22:55:25 +00:00
|
|
|
exec := make([]byte, prog.ExecBufferSize)
|
|
|
|
if err := p.SerializeForExec(exec, 0); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to serialize program: %v", err)
|
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
w := new(bytes.Buffer)
|
|
|
|
|
2016-08-28 14:33:32 +00:00
|
|
|
fmt.Fprint(w, "// autogenerated by syzkaller (http://github.com/google/syzkaller)\n\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
|
2016-08-28 14:33:32 +00:00
|
|
|
handled := make(map[string]int)
|
2015-12-23 12:38:31 +00:00
|
|
|
for _, c := range p.Calls {
|
2016-08-28 14:33:32 +00:00
|
|
|
handled[c.Meta.CallName] = c.Meta.NR
|
|
|
|
}
|
|
|
|
for name, nr := range handled {
|
|
|
|
fmt.Fprintf(w, "#ifndef __NR_%v\n", name)
|
|
|
|
fmt.Fprintf(w, "#define __NR_%v %v\n", name, nr)
|
2015-12-23 12:38:31 +00:00
|
|
|
fmt.Fprintf(w, "#endif\n")
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
|
2016-11-29 17:40:58 +00:00
|
|
|
hdr, err := preprocessCommonHeader(opts, handled)
|
2016-10-18 19:07:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
fmt.Fprint(w, hdr)
|
2016-08-28 14:33:32 +00:00
|
|
|
fmt.Fprint(w, "\n")
|
|
|
|
|
2017-05-25 14:07:10 +00:00
|
|
|
calls, nvar := generateCalls(exec, opts)
|
2016-08-28 10:24:39 +00:00
|
|
|
fmt.Fprintf(w, "long r[%v];\n", nvar)
|
2015-12-23 12:38:31 +00:00
|
|
|
|
2016-10-18 19:07:40 +00:00
|
|
|
if !opts.Repeat {
|
|
|
|
generateTestFunc(w, opts, calls, "loop")
|
|
|
|
|
|
|
|
fmt.Fprint(w, "int main()\n{\n")
|
2017-05-17 18:35:50 +00:00
|
|
|
fmt.Fprintf(w, "\tinstall_segv_handler();\n")
|
2017-05-18 12:26:02 +00:00
|
|
|
if opts.UseTmpDir {
|
|
|
|
fmt.Fprintf(w, "\tuse_temporary_dir();\n")
|
|
|
|
}
|
2017-05-17 18:20:23 +00:00
|
|
|
fmt.Fprintf(w, "\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun)
|
2016-10-18 19:07:40 +00:00
|
|
|
fmt.Fprint(w, "\tint status = 0;\n")
|
|
|
|
fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
|
|
|
|
fmt.Fprint(w, "\treturn 0;\n}\n")
|
|
|
|
} else {
|
|
|
|
generateTestFunc(w, opts, calls, "test")
|
|
|
|
if opts.Procs <= 1 {
|
|
|
|
fmt.Fprint(w, "int main()\n{\n")
|
2017-05-17 18:35:50 +00:00
|
|
|
fmt.Fprintf(w, "\tinstall_segv_handler();\n")
|
2017-05-18 12:26:02 +00:00
|
|
|
if opts.UseTmpDir {
|
|
|
|
fmt.Fprintf(w, "\tuse_temporary_dir();\n")
|
|
|
|
}
|
2017-05-17 18:20:23 +00:00
|
|
|
fmt.Fprintf(w, "\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun)
|
2016-10-18 19:07:40 +00:00
|
|
|
fmt.Fprint(w, "\tint status = 0;\n")
|
|
|
|
fmt.Fprint(w, "\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
|
|
|
|
fmt.Fprint(w, "\treturn 0;\n}\n")
|
|
|
|
} else {
|
|
|
|
fmt.Fprint(w, "int main()\n{\n")
|
2016-11-26 15:37:46 +00:00
|
|
|
fmt.Fprint(w, "\tint i;")
|
|
|
|
fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", opts.Procs)
|
2016-10-18 19:07:40 +00:00
|
|
|
fmt.Fprint(w, "\t\tif (fork() == 0) {\n")
|
2017-05-17 18:35:50 +00:00
|
|
|
fmt.Fprintf(w, "\t\t\tinstall_segv_handler();\n")
|
2017-05-18 12:26:02 +00:00
|
|
|
if opts.UseTmpDir {
|
|
|
|
fmt.Fprintf(w, "\t\t\tuse_temporary_dir();\n")
|
|
|
|
}
|
2017-05-17 18:20:23 +00:00
|
|
|
fmt.Fprintf(w, "\t\t\tint pid = do_sandbox_%v(i, %v);\n", opts.Sandbox, opts.EnableTun)
|
2017-02-02 19:18:20 +00:00
|
|
|
fmt.Fprint(w, "\t\t\tint status = 0;\n")
|
|
|
|
fmt.Fprint(w, "\t\t\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
|
2017-01-05 11:40:10 +00:00
|
|
|
fmt.Fprint(w, "\t\t\treturn 0;\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
fmt.Fprint(w, "\t\t}\n")
|
|
|
|
fmt.Fprint(w, "\t}\n")
|
|
|
|
fmt.Fprint(w, "\tsleep(1000000);\n")
|
|
|
|
fmt.Fprint(w, "\treturn 0;\n}\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Remove duplicate new lines.
|
|
|
|
out := w.Bytes()
|
|
|
|
for {
|
|
|
|
out1 := bytes.Replace(out, []byte{'\n', '\n', '\n'}, []byte{'\n', '\n'}, -1)
|
|
|
|
if len(out) == len(out1) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
out = out1
|
|
|
|
}
|
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func generateTestFunc(w io.Writer, opts Options, calls []string, name string) {
|
2015-12-23 12:38:31 +00:00
|
|
|
if !opts.Threaded && !opts.Collide {
|
2016-10-18 19:07:40 +00:00
|
|
|
fmt.Fprintf(w, "void %v()\n{\n", name)
|
|
|
|
if opts.Repro {
|
2017-01-08 14:28:38 +00:00
|
|
|
fmt.Fprintf(w, "\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\tmemset(r, -1, sizeof(r));\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
for _, c := range calls {
|
|
|
|
fmt.Fprintf(w, "%s", c)
|
|
|
|
}
|
2016-10-18 19:07:40 +00:00
|
|
|
fmt.Fprintf(w, "}\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, "void *thr(void *arg)\n{\n")
|
|
|
|
fmt.Fprintf(w, "\tswitch ((long)arg) {\n")
|
|
|
|
for i, c := range calls {
|
|
|
|
fmt.Fprintf(w, "\tcase %v:\n", i)
|
|
|
|
fmt.Fprintf(w, "%s", strings.Replace(c, "\t", "\t\t", -1))
|
|
|
|
fmt.Fprintf(w, "\t\tbreak;\n")
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\t}\n")
|
|
|
|
fmt.Fprintf(w, "\treturn 0;\n}\n\n")
|
|
|
|
|
2016-10-18 19:07:40 +00:00
|
|
|
fmt.Fprintf(w, "void %v()\n{\n", name)
|
2015-12-23 12:38:31 +00:00
|
|
|
fmt.Fprintf(w, "\tlong i;\n")
|
2016-08-28 14:37:24 +00:00
|
|
|
fmt.Fprintf(w, "\tpthread_t th[%v];\n", 2*len(calls))
|
2015-12-23 12:38:31 +00:00
|
|
|
fmt.Fprintf(w, "\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
if opts.Repro {
|
2017-01-08 14:28:38 +00:00
|
|
|
fmt.Fprintf(w, "\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
fmt.Fprintf(w, "\tmemset(r, -1, sizeof(r));\n")
|
2016-08-28 14:37:24 +00:00
|
|
|
fmt.Fprintf(w, "\tsrand(getpid());\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", len(calls))
|
|
|
|
fmt.Fprintf(w, "\t\tpthread_create(&th[i], 0, thr, (void*)i);\n")
|
|
|
|
fmt.Fprintf(w, "\t\tusleep(10000);\n")
|
|
|
|
fmt.Fprintf(w, "\t}\n")
|
|
|
|
if opts.Collide {
|
2015-12-23 12:50:02 +00:00
|
|
|
fmt.Fprintf(w, "\tfor (i = 0; i < %v; i++) {\n", len(calls))
|
2016-08-28 14:37:24 +00:00
|
|
|
fmt.Fprintf(w, "\t\tpthread_create(&th[%v+i], 0, thr, (void*)i);\n", len(calls))
|
|
|
|
fmt.Fprintf(w, "\t\tif (rand()%%2)\n")
|
|
|
|
fmt.Fprintf(w, "\t\t\tusleep(rand()%%10000);\n")
|
2015-12-23 12:50:02 +00:00
|
|
|
fmt.Fprintf(w, "\t}\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\tusleep(100000);\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
fmt.Fprintf(w, "}\n\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-25 14:07:10 +00:00
|
|
|
func generateCalls(exec []byte, opts Options) ([]string, int) {
|
2015-12-23 12:38:31 +00:00
|
|
|
read := func() uintptr {
|
|
|
|
if len(exec) < 8 {
|
|
|
|
panic("exec program overflow")
|
|
|
|
}
|
|
|
|
v := *(*uint64)(unsafe.Pointer(&exec[0]))
|
|
|
|
exec = exec[8:]
|
|
|
|
return uintptr(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)
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
lastCall := 0
|
|
|
|
seenCall := false
|
|
|
|
var calls []string
|
|
|
|
w := new(bytes.Buffer)
|
|
|
|
newCall := func() {
|
2015-12-23 12:50:02 +00:00
|
|
|
if seenCall {
|
|
|
|
seenCall = false
|
|
|
|
calls = append(calls, w.String())
|
|
|
|
w = new(bytes.Buffer)
|
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
}
|
|
|
|
n := 0
|
|
|
|
loop:
|
2015-12-23 12:50:02 +00:00
|
|
|
for ; ; n++ {
|
2015-12-23 12:38:31 +00:00
|
|
|
switch instr := read(); instr {
|
|
|
|
case prog.ExecInstrEOF:
|
|
|
|
break loop
|
|
|
|
case prog.ExecInstrCopyin:
|
|
|
|
newCall()
|
|
|
|
addr := read()
|
|
|
|
typ := read()
|
|
|
|
size := read()
|
|
|
|
switch typ {
|
|
|
|
case prog.ExecArgConst:
|
|
|
|
arg := read()
|
2017-01-10 15:45:52 +00:00
|
|
|
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)
|
|
|
|
} else {
|
2017-01-23 15:40:03 +00:00
|
|
|
fmt.Fprintf(w, "\tNONFAILING(STORE_BY_BITMASK(uint%v_t, 0x%x, 0x%x, %v, %v));\n", size*8, addr, arg, bfOff, bfLen)
|
2017-01-10 15:45:52 +00:00
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
case prog.ExecArgResult:
|
2016-08-28 10:24:39 +00:00
|
|
|
fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = %v);\n", size*8, addr, resultRef())
|
2015-12-23 12:38:31 +00:00
|
|
|
case prog.ExecArgData:
|
|
|
|
data := exec[:size]
|
|
|
|
exec = exec[(size+7)/8*8:]
|
|
|
|
var esc []byte
|
|
|
|
for _, v := range data {
|
|
|
|
hex := func(v byte) byte {
|
|
|
|
if v < 10 {
|
|
|
|
return '0' + v
|
|
|
|
}
|
|
|
|
return 'a' + v - 10
|
|
|
|
}
|
|
|
|
esc = append(esc, '\\', 'x', hex(v>>4), hex(v<<4>>4))
|
|
|
|
}
|
2016-08-28 10:24:39 +00:00
|
|
|
fmt.Fprintf(w, "\tNONFAILING(memcpy((void*)0x%x, \"%s\", %v));\n", addr, esc, size)
|
2017-04-27 18:31:00 +00:00
|
|
|
case prog.ExecArgCsum:
|
|
|
|
csum_kind := read()
|
|
|
|
switch csum_kind {
|
|
|
|
case prog.ExecArgCsumInet:
|
|
|
|
fmt.Fprintf(w, "\tstruct csum_inet csum_%d;\n", n)
|
|
|
|
fmt.Fprintf(w, "\tcsum_inet_init(&csum_%d);\n", n)
|
|
|
|
csum_chunks_num := read()
|
|
|
|
for i := uintptr(0); i < csum_chunks_num; i++ {
|
|
|
|
chunk_kind := read()
|
|
|
|
chunk_value := read()
|
|
|
|
chunk_size := read()
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
default:
|
|
|
|
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)
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("unknown csum kind %v", csum_kind))
|
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
default:
|
2017-04-27 18:31:00 +00:00
|
|
|
panic(fmt.Sprintf("bad argument type %v", instr))
|
2015-12-23 12:38:31 +00:00
|
|
|
}
|
|
|
|
case prog.ExecInstrCopyout:
|
|
|
|
addr := read()
|
|
|
|
size := read()
|
|
|
|
fmt.Fprintf(w, "\tif (r[%v] != -1)\n", lastCall)
|
2016-08-28 10:24:39 +00:00
|
|
|
fmt.Fprintf(w, "\t\tNONFAILING(r[%v] = *(uint%v_t*)0x%x);\n", n, size*8, addr)
|
2015-12-23 12:38:31 +00:00
|
|
|
default:
|
|
|
|
// Normal syscall.
|
|
|
|
newCall()
|
2017-05-25 14:07:10 +00:00
|
|
|
if opts.Fault && 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", opts.FaultNth)
|
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
meta := sys.Calls[instr]
|
2016-08-28 14:33:32 +00:00
|
|
|
fmt.Fprintf(w, "\tr[%v] = execute_syscall(__NR_%v", n, meta.CallName)
|
2015-12-23 12:38:31 +00:00
|
|
|
nargs := read()
|
|
|
|
for i := uintptr(0); i < nargs; i++ {
|
|
|
|
typ := read()
|
|
|
|
size := read()
|
|
|
|
_ = size
|
|
|
|
switch typ {
|
|
|
|
case prog.ExecArgConst:
|
|
|
|
fmt.Fprintf(w, ", 0x%xul", read())
|
2017-01-10 15:45:52 +00:00
|
|
|
// Bitfields can't be args of a normal syscall, so just ignore them.
|
|
|
|
read() // bit field offset
|
|
|
|
read() // bit field length
|
2015-12-23 12:38:31 +00:00
|
|
|
case prog.ExecArgResult:
|
|
|
|
fmt.Fprintf(w, ", %v", resultRef())
|
|
|
|
default:
|
sys, executor: extract tcp sequence numbers from /dev/net/tun
This commit adds a new pseudo syscall syz_extract_tcp_res, that reads
a packet from /dev/net/tun and extracts tcp sequence numbers to be used
in subsequent packets.
As a result this syzkaller program:
mmap(&(0x7f0000000000/0x10000)=nil, (0x10000), 0x3, 0x32, 0xffffffffffffffff, 0x0)
r0 = socket$inet_tcp(0x2, 0x1, 0x0)
bind$inet(r0, &(0x7f0000001000)={0x2, 0x0, @empty=0x0, [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]}, 0x10)
listen(r0, 0x5)
syz_emit_ethernet(0x36, &(0x7f0000002000)={@local={[0xaa, 0xaa, 0xaa, 0xaa, 0xaa], 0x0}, @random="4c6112cc15d8", [], {{0x800, @ipv4={{0x5, 0x4, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x6, 0x0, @remote={0xac, 0x14, 0x0, 0xbb}, @local={0xac, 0x14, 0x0, 0xaa}, {[]}}, @tcp={{0x1, 0x0, 0x42424242, 0x42424242, 0x0, 0x0, 0x5, 0x2, 0x0, 0x0, 0x0, {[]}}, {""}}}}}})
syz_extract_tcp_res(&(0x7f0000003000)={<r1=>0x42424242, <r2=>0x42424242}, 0x1, 0x0)
syz_emit_ethernet(0x38, &(0x7f0000004000)={@local={[0xaa, 0xaa, 0xaa, 0xaa, 0xaa], 0x0}, @remote={[0xbb, 0xbb, 0xbb, 0xbb, 0xbb], 0x0}, [], {{0x800, @ipv4={{0x5, 0x4, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x6, 0x0, @remote={0xac, 0x14, 0x0, 0xbb}, @local={0xac, 0x14, 0x0, 0xaa}, {[]}}, @tcp={{0x1, 0x0, r2, r1, 0x0, 0x0, 0x5, 0x10, 0x0, 0x0, 0x0, {[]}}, {"0c10"}}}}}})
r3 = accept$inet(r0, &(0x7f0000005000)={0x0, 0x0, @multicast1=0x0, [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]}, &(0x7f0000006000)=0x10)
established a TCP connection:
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:20000 0.0.0.0:* LISTEN 5477/a.out
tcp 2 0 172.20.0.170:20000 172.20.0.187:20001 ESTABLISHED 5477/a.out
Similar program for IPv6:
mmap(&(0x7f0000000000/0x10000)=nil, (0x10000), 0x3, 0x32, 0xffffffffffffffff, 0x0)
r0 = socket$inet6_tcp(0xa, 0x1, 0x0)
bind$inet6(r0, &(0x7f0000000000)={0xa, 0x1, 0x0, @empty={[0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]}, 0x0}, 0x1c)
listen(r0, 0x5)
syz_emit_ethernet(0x4a, &(0x7f0000001000)={@local={[0xaa, 0xaa, 0xaa, 0xaa, 0xaa], 0x0}, @random="de895db1468d", [], {{0x86dd, @ipv6={0x0, 0x6, "a228af", 0x14, 0x6, 0x0, @remote={0xfe, 0x80, [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0], 0x0, 0xbb}, @local={0xfe, 0x80, [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0], 0x0, 0xaa}, {[], @tcp={{0x0, 0x1, 0x42424242, 0x42424242, 0x0, 0x0, 0x5, 0x2, 0x0, 0x0, 0x0, {[]}}, {""}}}}}}})
syz_extract_tcp_res(&(0x7f0000002000)={<r1=>0x42424242, <r2=>0x42424242}, 0x1, 0x0)
syz_emit_ethernet(0x4a, &(0x7f0000003000)={@local={[0xaa, 0xaa, 0xaa, 0xaa, 0xaa], 0x0}, @random="de895db1468d", [], {{0x86dd, @ipv6={0x0, 0x6, "a228af", 0x14, 0x6, 0x0, @remote={0xfe, 0x80, [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0], 0x0, 0xbb}, @local={0xfe, 0x80, [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0], 0x0, 0xaa}, {[], @tcp={{0x0, 0x1, r2, r1, 0x0, 0x0, 0x5, 0x10, 0x0, 0x0, 0x0, {[]}}, {""}}}}}}})
r3 = accept$inet6(r0, &(0x7f0000004000)={0x0, 0x0, 0x0, @empty={[0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]}, 0x0}, &(0x7f0000005000)=0x1c)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp6 0 0 :::20001 :::* LISTEN 5527/a.out
tcp6 0 0 fe80::aa:20001 fe80::bb:20000 ESTABLISHED 5527/a.out
2017-05-16 14:14:58 +00:00
|
|
|
panic(fmt.Sprintf("unknown arg type %v", typ))
|
2015-12-23 12:38:31 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-28 14:33:32 +00:00
|
|
|
for i := nargs; i < 9; i++ {
|
2015-12-23 12:38:31 +00:00
|
|
|
fmt.Fprintf(w, ", 0")
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, ");\n")
|
|
|
|
lastCall = n
|
|
|
|
seenCall = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
newCall()
|
|
|
|
return calls, n
|
|
|
|
}
|
|
|
|
|
2016-11-29 17:40:58 +00:00
|
|
|
func preprocessCommonHeader(opts Options, handled map[string]int) (string, error) {
|
2017-01-05 11:39:35 +00:00
|
|
|
var defines []string
|
2016-10-18 19:07:40 +00:00
|
|
|
switch opts.Sandbox {
|
|
|
|
case "none":
|
2017-01-05 11:39:35 +00:00
|
|
|
defines = append(defines, "SYZ_SANDBOX_NONE")
|
2016-10-18 19:07:40 +00:00
|
|
|
case "setuid":
|
2017-01-05 11:39:35 +00:00
|
|
|
defines = append(defines, "SYZ_SANDBOX_SETUID")
|
2016-10-18 19:07:40 +00:00
|
|
|
case "namespace":
|
2017-01-05 11:39:35 +00:00
|
|
|
defines = append(defines, "SYZ_SANDBOX_NAMESPACE")
|
2016-10-18 19:07:40 +00:00
|
|
|
default:
|
|
|
|
return "", fmt.Errorf("unknown sandbox mode: %v", opts.Sandbox)
|
|
|
|
}
|
|
|
|
if opts.Repeat {
|
2017-01-05 11:39:35 +00:00
|
|
|
defines = append(defines, "SYZ_REPEAT")
|
2016-10-18 19:07:40 +00:00
|
|
|
}
|
2017-05-25 14:07:10 +00:00
|
|
|
if opts.Fault {
|
|
|
|
defines = append(defines, "SYZ_FAULT_INJECTION")
|
|
|
|
}
|
2017-05-17 18:20:23 +00:00
|
|
|
if opts.EnableTun {
|
|
|
|
defines = append(defines, "SYZ_TUN_ENABLE")
|
|
|
|
}
|
2017-05-18 12:26:02 +00:00
|
|
|
if opts.UseTmpDir {
|
|
|
|
defines = append(defines, "SYZ_USE_TMP_DIR")
|
|
|
|
}
|
2016-11-29 17:40:58 +00:00
|
|
|
for name, _ := range handled {
|
2017-01-05 11:39:35 +00:00
|
|
|
defines = append(defines, "__NR_"+name)
|
|
|
|
}
|
2017-01-12 10:57:17 +00:00
|
|
|
// TODO: need to know target arch + do cross-compilation
|
|
|
|
defines = append(defines, "__x86_64__")
|
2017-01-05 11:39:35 +00:00
|
|
|
|
|
|
|
cmd := exec.Command("cpp", "-nostdinc", "-undef", "-fdirectives-only", "-dDI", "-E", "-P", "-")
|
|
|
|
for _, def := range defines {
|
|
|
|
cmd.Args = append(cmd.Args, "-D"+def)
|
2016-11-29 17:40:58 +00:00
|
|
|
}
|
2016-10-18 19:07:40 +00:00
|
|
|
cmd.Stdin = strings.NewReader(commonHeader)
|
|
|
|
stderr := new(bytes.Buffer)
|
|
|
|
stdout := new(bytes.Buffer)
|
|
|
|
cmd.Stderr = stderr
|
|
|
|
cmd.Stdout = stdout
|
|
|
|
if err := cmd.Run(); len(stdout.Bytes()) == 0 {
|
|
|
|
return "", fmt.Errorf("cpp failed: %v\n%v\n%v\n", err, stdout.String(), stderr.String())
|
|
|
|
}
|
2017-01-05 11:39:35 +00:00
|
|
|
remove := append(defines, []string{
|
|
|
|
"__STDC__",
|
|
|
|
"__STDC_HOSTED__",
|
|
|
|
"__STDC_UTF_16__",
|
|
|
|
"__STDC_UTF_32__",
|
|
|
|
}...)
|
|
|
|
out := stdout.String()
|
|
|
|
for _, def := range remove {
|
|
|
|
out = strings.Replace(out, "#define "+def+" 1\n", "", -1)
|
2016-11-29 17:40:58 +00:00
|
|
|
}
|
2017-05-06 22:29:18 +00:00
|
|
|
// strip: #define __STDC_VERSION__ 201112L
|
|
|
|
for _, def := range []string{"__STDC_VERSION__"} {
|
|
|
|
pos := strings.Index(out, "#define "+def)
|
|
|
|
if pos == -1 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
end := strings.IndexByte(out[pos:], '\n')
|
|
|
|
if end == -1 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
out = strings.Replace(out, out[pos:end+1], "", -1)
|
|
|
|
}
|
2016-10-18 19:07:40 +00:00
|
|
|
return out, nil
|
|
|
|
}
|
|
|
|
|
2017-01-08 14:28:38 +00:00
|
|
|
// Build builds a C/C++ program from source src and returns name of the resulting binary.
|
|
|
|
// lang can be "c" or "c++".
|
|
|
|
func Build(lang, src string) (string, error) {
|
2015-12-23 12:38:31 +00:00
|
|
|
bin, err := ioutil.TempFile("", "syzkaller")
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("failed to create temp file: %v", err)
|
|
|
|
}
|
|
|
|
bin.Close()
|
2017-01-08 14:28:38 +00:00
|
|
|
out, err := exec.Command("gcc", "-x", lang, "-Wall", "-Werror", src, "-o", bin.Name(), "-pthread", "-static", "-O1", "-g").CombinedOutput()
|
2016-02-19 09:28:10 +00:00
|
|
|
if err != nil {
|
|
|
|
// Some distributions don't have static libraries.
|
2017-01-08 14:28:38 +00:00
|
|
|
out, err = exec.Command("gcc", "-x", lang, "-Wall", "-Werror", src, "-o", bin.Name(), "-pthread", "-O1", "-g").CombinedOutput()
|
2016-02-19 09:28:10 +00:00
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
if err != nil {
|
|
|
|
os.Remove(bin.Name())
|
|
|
|
data, _ := ioutil.ReadFile(src)
|
2017-01-12 10:57:17 +00:00
|
|
|
return "", fmt.Errorf("failed to build program:\n%s\n%s", data, out)
|
2015-12-23 12:38:31 +00:00
|
|
|
}
|
|
|
|
return bin.Name(), nil
|
|
|
|
}
|
2016-01-15 19:32:32 +00:00
|
|
|
|
|
|
|
// Format reformats C source using clang-format.
|
|
|
|
func Format(src []byte) ([]byte, error) {
|
|
|
|
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
|
|
|
|
cmd := exec.Command("clang-format", "-assume-filename=/src.c", "-style", style)
|
|
|
|
cmd.Stdin = bytes.NewReader(src)
|
|
|
|
cmd.Stdout = stdout
|
|
|
|
cmd.Stderr = stderr
|
|
|
|
if err := cmd.Run(); err != nil {
|
2016-08-28 10:24:39 +00:00
|
|
|
return src, fmt.Errorf("failed to format source: %v\n%v", err, stderr.String())
|
2016-01-15 19:32:32 +00:00
|
|
|
}
|
|
|
|
return stdout.Bytes(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Something acceptable for kernel developers and email-friendly.
|
|
|
|
var style = `{
|
|
|
|
BasedOnStyle: LLVM,
|
|
|
|
IndentWidth: 2,
|
|
|
|
UseTab: Never,
|
|
|
|
BreakBeforeBraces: Linux,
|
|
|
|
IndentCaseLabels: false,
|
|
|
|
DerivePointerAlignment: false,
|
|
|
|
PointerAlignment: Left,
|
|
|
|
AlignTrailingComments: true,
|
|
|
|
AllowShortBlocksOnASingleLine: false,
|
|
|
|
AllowShortCaseLabelsOnASingleLine: false,
|
|
|
|
AllowShortFunctionsOnASingleLine: false,
|
|
|
|
AllowShortIfStatementsOnASingleLine: false,
|
|
|
|
AllowShortLoopsOnASingleLine: false,
|
|
|
|
ColumnLimit: 72,
|
|
|
|
}`
|