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-10-15 09:15:27 +00:00
|
|
|
|
// Package csource generates [almost] equivalent C programs from syzkaller programs.
|
2015-12-23 12:38:31 +00:00
|
|
|
|
package csource
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
2017-06-06 11:52:57 +00:00
|
|
|
|
"regexp"
|
2015-12-23 12:50:02 +00:00
|
|
|
|
"strings"
|
2015-12-23 12:38:31 +00:00
|
|
|
|
|
|
|
|
|
"github.com/google/syzkaller/prog"
|
2017-09-15 13:56:48 +00:00
|
|
|
|
"github.com/google/syzkaller/sys/targets"
|
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-08-09 10:57:23 +00:00
|
|
|
|
if err := opts.Check(); err != nil {
|
|
|
|
|
return nil, fmt.Errorf("csource: invalid opts: %v", err)
|
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx := &context{
|
|
|
|
|
p: p,
|
|
|
|
|
opts: opts,
|
|
|
|
|
target: p.Target,
|
|
|
|
|
sysTarget: targets.List[p.Target.OS][p.Target.Arch],
|
|
|
|
|
w: new(bytes.Buffer),
|
|
|
|
|
calls: make(map[string]uint64),
|
2017-01-20 22:55:25 +00:00
|
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
|
for _, c := range p.Calls {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.calls[c.Meta.CallName] = c.Meta.NR
|
2016-08-28 14:33:32 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
|
|
|
|
|
ctx.print("// autogenerated by syzkaller (http://github.com/google/syzkaller)\n\n")
|
|
|
|
|
|
2017-12-15 10:25:19 +00:00
|
|
|
|
hdr, err := createCommonHeader(p, opts)
|
2016-10-18 19:07:40 +00:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2017-12-15 10:25:19 +00:00
|
|
|
|
ctx.w.Write(hdr)
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("\n")
|
2016-08-28 14:33:32 +00:00
|
|
|
|
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.generateSyscallDefines()
|
2017-09-14 19:27:56 +00:00
|
|
|
|
|
2017-10-15 09:15:27 +00:00
|
|
|
|
exec := make([]byte, prog.ExecBufferSize)
|
|
|
|
|
progSize, err := ctx.p.SerializeForExec(exec, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("failed to serialize program: %v", err)
|
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
decoded, err := ctx.target.DeserializeExec(exec[:progSize])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
calls, nvar := ctx.generateCalls(decoded)
|
2017-12-16 11:38:49 +00:00
|
|
|
|
if nvar != 0 {
|
|
|
|
|
ctx.printf("long r[%v];\n", nvar)
|
|
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
|
|
2016-10-18 19:07:40 +00:00
|
|
|
|
if !opts.Repeat {
|
2017-12-16 11:38:49 +00:00
|
|
|
|
ctx.generateTestFunc(calls, nvar, "loop")
|
2016-10-18 19:07:40 +00:00
|
|
|
|
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("int main()\n{\n")
|
2017-05-18 12:54:02 +00:00
|
|
|
|
if opts.HandleSegv {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tinstall_segv_handler();\n")
|
2017-05-18 12:54:02 +00:00
|
|
|
|
}
|
2017-05-18 12:26:02 +00:00
|
|
|
|
if opts.UseTmpDir {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tuse_temporary_dir();\n")
|
2017-05-18 12:26:02 +00:00
|
|
|
|
}
|
2017-05-18 15:03:02 +00:00
|
|
|
|
if opts.Sandbox != "" {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun)
|
|
|
|
|
ctx.print("\tint status = 0;\n")
|
|
|
|
|
ctx.print("\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
|
2017-05-18 15:03:02 +00:00
|
|
|
|
} else {
|
|
|
|
|
if opts.EnableTun {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tsetup_tun(0, %v);\n", opts.EnableTun)
|
2017-05-18 15:03:02 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("\tloop();\n")
|
2017-05-18 15:03:02 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("\treturn 0;\n}\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
|
} else {
|
2017-12-16 11:38:49 +00:00
|
|
|
|
ctx.generateTestFunc(calls, nvar, "test")
|
2016-10-18 19:07:40 +00:00
|
|
|
|
if opts.Procs <= 1 {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("int main()\n{\n")
|
2017-05-18 12:54:02 +00:00
|
|
|
|
if opts.HandleSegv {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tinstall_segv_handler();\n")
|
2017-05-18 12:54:02 +00:00
|
|
|
|
}
|
2017-05-18 12:26:02 +00:00
|
|
|
|
if opts.UseTmpDir {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tuse_temporary_dir();\n")
|
2017-05-18 12:26:02 +00:00
|
|
|
|
}
|
2017-05-18 15:03:02 +00:00
|
|
|
|
if opts.Sandbox != "" {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tint pid = do_sandbox_%v(0, %v);\n", opts.Sandbox, opts.EnableTun)
|
|
|
|
|
ctx.print("\tint status = 0;\n")
|
|
|
|
|
ctx.print("\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
|
2017-05-18 15:03:02 +00:00
|
|
|
|
} else {
|
|
|
|
|
if opts.EnableTun {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tsetup_tun(0, %v);\n", opts.EnableTun)
|
2017-05-18 15:03:02 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("\tloop();\n")
|
2017-05-18 15:03:02 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("\treturn 0;\n}\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
|
} else {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("int main()\n{\n")
|
|
|
|
|
ctx.print("\tint i;")
|
|
|
|
|
ctx.printf("\tfor (i = 0; i < %v; i++) {\n", opts.Procs)
|
|
|
|
|
ctx.print("\t\tif (fork() == 0) {\n")
|
2017-05-18 12:54:02 +00:00
|
|
|
|
if opts.HandleSegv {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\t\t\tinstall_segv_handler();\n")
|
2017-05-18 12:54:02 +00:00
|
|
|
|
}
|
2017-05-18 12:26:02 +00:00
|
|
|
|
if opts.UseTmpDir {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\t\t\tuse_temporary_dir();\n")
|
2017-05-18 12:26:02 +00:00
|
|
|
|
}
|
2017-05-18 15:03:02 +00:00
|
|
|
|
if opts.Sandbox != "" {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\t\t\tint pid = do_sandbox_%v(i, %v);\n", opts.Sandbox, opts.EnableTun)
|
|
|
|
|
ctx.print("\t\t\tint status = 0;\n")
|
|
|
|
|
ctx.print("\t\t\twhile (waitpid(pid, &status, __WALL) != pid) {}\n")
|
2017-05-18 15:03:02 +00:00
|
|
|
|
} else {
|
|
|
|
|
if opts.EnableTun {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\t\t\tsetup_tun(i, %v);\n", opts.EnableTun)
|
2017-05-18 15:03:02 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("\t\t\tloop();\n")
|
2017-05-18 15:03:02 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.print("\t\t\treturn 0;\n")
|
|
|
|
|
ctx.print("\t\t}\n")
|
|
|
|
|
ctx.print("\t}\n")
|
|
|
|
|
ctx.print("\tsleep(1000000);\n")
|
|
|
|
|
ctx.print("\treturn 0;\n}\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-06 11:52:57 +00:00
|
|
|
|
|
|
|
|
|
// Remove NONFAILING and debug calls.
|
2017-10-15 09:15:27 +00:00
|
|
|
|
out0 := ctx.w.String()
|
2017-06-06 11:52:57 +00:00
|
|
|
|
if !opts.HandleSegv {
|
|
|
|
|
re := regexp.MustCompile(`\t*NONFAILING\((.*)\);\n`)
|
|
|
|
|
out0 = re.ReplaceAllString(out0, "$1;\n")
|
|
|
|
|
}
|
|
|
|
|
if !opts.Debug {
|
|
|
|
|
re := regexp.MustCompile(`\t*debug\(.*\);\n`)
|
|
|
|
|
out0 = re.ReplaceAllString(out0, "")
|
|
|
|
|
re = regexp.MustCompile(`\t*debug_dump_data\(.*\);\n`)
|
|
|
|
|
out0 = re.ReplaceAllString(out0, "")
|
|
|
|
|
}
|
2017-10-16 10:18:50 +00:00
|
|
|
|
out0 = strings.Replace(out0, "NORETURN", "", -1)
|
2017-06-06 11:52:57 +00:00
|
|
|
|
|
2016-10-18 19:07:40 +00:00
|
|
|
|
// Remove duplicate new lines.
|
2017-06-06 11:52:57 +00:00
|
|
|
|
out1 := []byte(out0)
|
2016-10-18 19:07:40 +00:00
|
|
|
|
for {
|
2017-06-06 11:52:57 +00:00
|
|
|
|
out2 := bytes.Replace(out1, []byte{'\n', '\n', '\n'}, []byte{'\n', '\n'}, -1)
|
|
|
|
|
if len(out1) == len(out2) {
|
2016-10-18 19:07:40 +00:00
|
|
|
|
break
|
|
|
|
|
}
|
2017-06-06 11:52:57 +00:00
|
|
|
|
out1 = out2
|
2016-10-18 19:07:40 +00:00
|
|
|
|
}
|
2017-06-06 11:52:57 +00:00
|
|
|
|
|
|
|
|
|
return out1, nil
|
2016-10-18 19:07:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-15 09:15:27 +00:00
|
|
|
|
type context struct {
|
|
|
|
|
p *prog.Prog
|
|
|
|
|
opts Options
|
|
|
|
|
target *prog.Target
|
|
|
|
|
sysTarget *targets.Target
|
|
|
|
|
w *bytes.Buffer
|
|
|
|
|
calls map[string]uint64 // CallName -> NR
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ctx *context) print(str string) {
|
|
|
|
|
ctx.w.WriteString(str)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ctx *context) printf(str string, args ...interface{}) {
|
|
|
|
|
ctx.print(fmt.Sprintf(str, args...))
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-16 11:38:49 +00:00
|
|
|
|
func (ctx *context) generateTestFunc(calls []string, nvar uint64, name string) {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
opts := ctx.opts
|
2015-12-23 12:38:31 +00:00
|
|
|
|
if !opts.Threaded && !opts.Collide {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("void %v()\n{\n", name)
|
2017-06-13 15:21:33 +00:00
|
|
|
|
if opts.Debug {
|
|
|
|
|
// Use debug to avoid: error: ‘debug’ defined but not used.
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tdebug(\"%v\\n\");\n", name)
|
2017-06-13 15:21:33 +00:00
|
|
|
|
}
|
2016-10-18 19:07:40 +00:00
|
|
|
|
if opts.Repro {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
|
}
|
2017-12-16 11:38:49 +00:00
|
|
|
|
if nvar != 0 {
|
|
|
|
|
ctx.printf("\tmemset(r, -1, sizeof(r));\n")
|
|
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
|
for _, c := range calls {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("%s", c)
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("}\n\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
|
} else {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("void *thr(void *arg)\n{\n")
|
|
|
|
|
ctx.printf("\tswitch ((long)arg) {\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
|
for i, c := range calls {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tcase %v:\n", i)
|
|
|
|
|
ctx.printf("%s", strings.Replace(c, "\t", "\t\t", -1))
|
|
|
|
|
ctx.printf("\t\tbreak;\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\t}\n")
|
|
|
|
|
ctx.printf("\treturn 0;\n}\n\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
|
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("void %v()\n{\n", name)
|
|
|
|
|
ctx.printf("\tlong i;\n")
|
|
|
|
|
ctx.printf("\tpthread_t th[%v];\n", 2*len(calls))
|
2017-12-21 14:01:12 +00:00
|
|
|
|
ctx.printf("\tpthread_attr_t attr;\n")
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\n")
|
2017-06-13 15:21:33 +00:00
|
|
|
|
if opts.Debug {
|
|
|
|
|
// Use debug to avoid: error: ‘debug’ defined but not used.
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tdebug(\"%v\\n\");\n", name)
|
2017-06-13 15:21:33 +00:00
|
|
|
|
}
|
2016-10-18 19:07:40 +00:00
|
|
|
|
if opts.Repro {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tsyscall(SYS_write, 1, \"executing program\\n\", strlen(\"executing program\\n\"));\n")
|
2016-10-18 19:07:40 +00:00
|
|
|
|
}
|
2017-12-16 11:38:49 +00:00
|
|
|
|
if nvar != 0 {
|
|
|
|
|
ctx.printf("\tmemset(r, -1, sizeof(r));\n")
|
|
|
|
|
}
|
2017-05-29 13:15:39 +00:00
|
|
|
|
if opts.Collide {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tsrand(getpid());\n")
|
2017-05-29 13:15:39 +00:00
|
|
|
|
}
|
2017-12-21 14:01:12 +00:00
|
|
|
|
ctx.printf("\tpthread_attr_init(&attr);\n")
|
|
|
|
|
ctx.printf("\tpthread_attr_setstacksize(&attr, 128 << 10);\n")
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tfor (i = 0; i < %v; i++) {\n", len(calls))
|
2017-12-21 14:01:12 +00:00
|
|
|
|
ctx.printf("\t\tpthread_create(&th[i], &attr, thr, (void*)i);\n")
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\t\tusleep(rand()%%10000);\n")
|
|
|
|
|
ctx.printf("\t}\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
|
if opts.Collide {
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tfor (i = 0; i < %v; i++) {\n", len(calls))
|
2017-12-21 14:01:12 +00:00
|
|
|
|
ctx.printf("\t\tpthread_create(&th[%v+i], &attr, thr, (void*)i);\n", len(calls))
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\t\tif (rand()%%2)\n")
|
|
|
|
|
ctx.printf("\t\t\tusleep(rand()%%10000);\n")
|
|
|
|
|
ctx.printf("\t}\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("\tusleep(rand()%%100000);\n")
|
|
|
|
|
ctx.printf("}\n\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-15 09:15:27 +00:00
|
|
|
|
func (ctx *context) generateSyscallDefines() {
|
|
|
|
|
prefix := ctx.sysTarget.SyscallPrefix
|
|
|
|
|
for name, nr := range ctx.calls {
|
|
|
|
|
if strings.HasPrefix(name, "syz_") || !ctx.sysTarget.NeedSyscallDefine(nr) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
ctx.printf("#ifndef %v%v\n", prefix, name)
|
|
|
|
|
ctx.printf("#define %v%v %v\n", prefix, name, nr)
|
|
|
|
|
ctx.printf("#endif\n")
|
|
|
|
|
}
|
|
|
|
|
if ctx.target.OS == "linux" && ctx.target.PtrSize == 4 {
|
|
|
|
|
// This is a dirty hack.
|
|
|
|
|
// On 32-bit linux mmap translated to old_mmap syscall which has a different signature.
|
2017-11-23 07:51:04 +00:00
|
|
|
|
// mmap2 has the right signature. syz-extract translates mmap to mmap2, do the same here.
|
2017-10-15 09:15:27 +00:00
|
|
|
|
ctx.printf("#undef __NR_mmap\n")
|
|
|
|
|
ctx.printf("#define __NR_mmap __NR_mmap2\n")
|
|
|
|
|
}
|
|
|
|
|
ctx.printf("\n")
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-15 12:42:28 +00:00
|
|
|
|
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)
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
if arg.AddOp != 0 {
|
|
|
|
|
res = fmt.Sprintf("%v+%v", res, arg.AddOp)
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
var calls []string
|
2017-12-15 12:42:28 +00:00
|
|
|
|
csumSeq := 0
|
|
|
|
|
for ci, call := range p.Calls {
|
|
|
|
|
w := new(bytes.Buffer)
|
|
|
|
|
// Copyin.
|
|
|
|
|
for _, copyin := range call.Copyin {
|
|
|
|
|
switch arg := copyin.Arg.(type) {
|
2015-12-23 12:38:31 +00:00
|
|
|
|
case prog.ExecArgConst:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
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)
|
2017-01-10 15:45:52 +00:00
|
|
|
|
} else {
|
2017-12-15 12:42:28 +00:00
|
|
|
|
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)
|
2017-01-10 15:45:52 +00:00
|
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
|
case prog.ExecArgResult:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
fmt.Fprintf(w, "\tNONFAILING(*(uint%v_t*)0x%x = %v);\n",
|
|
|
|
|
arg.Size*8, copyin.Addr, resultRef(arg))
|
2015-12-23 12:38:31 +00:00
|
|
|
|
case prog.ExecArgData:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
fmt.Fprintf(w, "\tNONFAILING(memcpy((void*)0x%x, \"%s\", %v));\n",
|
2017-12-17 09:55:35 +00:00
|
|
|
|
copyin.Addr, toCString(arg.Data), len(arg.Data))
|
2017-04-27 18:31:00 +00:00
|
|
|
|
case prog.ExecArgCsum:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
switch arg.Kind {
|
2017-04-27 18:31:00 +00:00
|
|
|
|
case prog.ExecArgCsumInet:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
csumSeq++
|
|
|
|
|
fmt.Fprintf(w, "\tstruct csum_inet csum_%d;\n", csumSeq)
|
|
|
|
|
fmt.Fprintf(w, "\tcsum_inet_init(&csum_%d);\n", csumSeq)
|
|
|
|
|
for i, chunk := range arg.Chunks {
|
|
|
|
|
switch chunk.Kind {
|
2017-04-27 18:31:00 +00:00
|
|
|
|
case prog.ExecArgCsumChunkData:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
fmt.Fprintf(w, "\tNONFAILING(csum_inet_update(&csum_%d, (const uint8_t*)0x%x, %d));\n", csumSeq, chunk.Value, chunk.Size)
|
2017-04-27 18:31:00 +00:00
|
|
|
|
case prog.ExecArgCsumChunkConst:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
fmt.Fprintf(w, "\tuint%d_t csum_%d_chunk_%d = 0x%x;\n", chunk.Size*8, csumSeq, i, chunk.Value)
|
|
|
|
|
fmt.Fprintf(w, "\tcsum_inet_update(&csum_%d, (const uint8_t*)&csum_%d_chunk_%d, %d);\n", csumSeq, csumSeq, i, chunk.Size)
|
2017-04-27 18:31:00 +00:00
|
|
|
|
default:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
panic(fmt.Sprintf("unknown checksum chunk kind %v", chunk.Kind))
|
2017-04-27 18:31:00 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
fmt.Fprintf(w, "\tNONFAILING(*(uint16_t*)0x%x = csum_inet_digest(&csum_%d));\n", copyin.Addr, csumSeq)
|
2017-04-27 18:31:00 +00:00
|
|
|
|
default:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
panic(fmt.Sprintf("unknown csum kind %v", arg.Kind))
|
2017-04-27 18:31:00 +00:00
|
|
|
|
}
|
2015-12-23 12:38:31 +00:00
|
|
|
|
default:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
panic(fmt.Sprintf("bad argument type: %+v", arg))
|
2017-05-19 13:53:19 +00:00
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Call itself.
|
|
|
|
|
if ctx.opts.Fault && ctx.opts.FaultCall == ci {
|
|
|
|
|
fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/failslab/ignore-gfp-wait\", \"N\");\n")
|
|
|
|
|
fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_futex/ignore-private\", \"N\");\n")
|
|
|
|
|
fmt.Fprintf(w, "\tinject_fault(%v);\n", ctx.opts.FaultNth)
|
|
|
|
|
}
|
|
|
|
|
callName := call.Meta.CallName
|
2017-12-16 11:38:49 +00:00
|
|
|
|
resCopyout := call.Index != prog.ExecNoCopyout
|
|
|
|
|
argCopyout := len(call.Copyout) != 0
|
|
|
|
|
emitCall := ctx.opts.EnableTun || callName != "syz_emit_ethernet" &&
|
|
|
|
|
callName != "syz_extract_tcp_res"
|
2017-12-15 12:42:28 +00:00
|
|
|
|
// TODO: if we don't emit the call we must also not emit copyin, copyout and fault injection.
|
|
|
|
|
// However, simply skipping whole iteration breaks tests due to unused static functions.
|
2017-12-16 11:38:49 +00:00
|
|
|
|
if emitCall {
|
2017-12-15 12:42:28 +00:00
|
|
|
|
native := !strings.HasPrefix(callName, "syz_")
|
2017-12-16 11:38:49 +00:00
|
|
|
|
fmt.Fprintf(w, "\t")
|
|
|
|
|
if argCopyout {
|
|
|
|
|
fmt.Fprintf(w, "if (")
|
|
|
|
|
if resCopyout {
|
|
|
|
|
fmt.Fprintf(w, "(")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if resCopyout {
|
|
|
|
|
fmt.Fprintf(w, "r[%v] = ", call.Index)
|
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
if native {
|
2017-12-16 11:38:49 +00:00
|
|
|
|
fmt.Fprintf(w, "syscall(%v%v", ctx.sysTarget.SyscallPrefix, callName)
|
2017-12-15 12:42:28 +00:00
|
|
|
|
} else {
|
2017-12-16 11:38:49 +00:00
|
|
|
|
fmt.Fprintf(w, "%v(", callName)
|
2017-05-19 13:53:19 +00:00
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
for ai, arg := range call.Args {
|
|
|
|
|
if native || ai > 0 {
|
2017-05-19 13:53:19 +00:00
|
|
|
|
fmt.Fprintf(w, ", ")
|
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
switch arg := arg.(type) {
|
2015-12-23 12:38:31 +00:00
|
|
|
|
case prog.ExecArgConst:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
fmt.Fprintf(w, "0x%xul", arg.Value)
|
2015-12-23 12:38:31 +00:00
|
|
|
|
case prog.ExecArgResult:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
fmt.Fprintf(w, "%v", resultRef(arg))
|
2015-12-23 12:38:31 +00:00
|
|
|
|
default:
|
2017-12-15 12:42:28 +00:00
|
|
|
|
panic(fmt.Sprintf("unknown arg type: %+v", arg))
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-16 11:38:49 +00:00
|
|
|
|
fmt.Fprintf(w, ")")
|
|
|
|
|
if argCopyout {
|
|
|
|
|
if resCopyout {
|
|
|
|
|
fmt.Fprintf(w, ")")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(w, " != -1) {")
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(w, ";")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(w, "\n")
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
}
|
2017-12-16 11:38:49 +00:00
|
|
|
|
if emitCall && argCopyout {
|
|
|
|
|
fmt.Fprintf(w, "\t}\n")
|
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
|
|
|
|
|
calls = append(calls, w.String())
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
2017-12-15 12:42:28 +00:00
|
|
|
|
return calls, p.NumVars
|
2015-12-23 12:38:31 +00:00
|
|
|
|
}
|
2017-12-17 09:55:35 +00:00
|
|
|
|
|
|
|
|
|
func toCString(data []byte) []byte {
|
|
|
|
|
if len(data) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
readable := true
|
|
|
|
|
for i, v := range data {
|
|
|
|
|
// Allow 0 only as last byte.
|
|
|
|
|
if !isReadable(v) && (i != len(data)-1 || v != 0) {
|
|
|
|
|
readable = false
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !readable {
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
for _, v := range data {
|
|
|
|
|
buf.Write([]byte{'\\', 'x', toHex(v >> 4), toHex(v << 4 >> 4)})
|
|
|
|
|
}
|
|
|
|
|
return buf.Bytes()
|
|
|
|
|
}
|
|
|
|
|
if data[len(data)-1] == 0 {
|
|
|
|
|
// Don't serialize last 0, C strings are 0-terminated anyway.
|
|
|
|
|
data = data[:len(data)-1]
|
|
|
|
|
}
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
for _, v := range data {
|
|
|
|
|
switch v {
|
|
|
|
|
case '\t':
|
|
|
|
|
buf.Write([]byte{'\\', 't'})
|
|
|
|
|
case '\r':
|
|
|
|
|
buf.Write([]byte{'\\', 'r'})
|
|
|
|
|
case '\n':
|
|
|
|
|
buf.Write([]byte{'\\', 'n'})
|
|
|
|
|
case '\\':
|
|
|
|
|
buf.Write([]byte{'\\', '\\'})
|
2017-12-22 10:59:09 +00:00
|
|
|
|
case '"':
|
|
|
|
|
buf.Write([]byte{'\\', '"'})
|
2017-12-17 09:55:35 +00:00
|
|
|
|
default:
|
|
|
|
|
if v < 0x20 || v >= 0x7f {
|
|
|
|
|
panic("unexpected char during data serialization")
|
|
|
|
|
}
|
|
|
|
|
buf.WriteByte(v)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return buf.Bytes()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func isReadable(v byte) bool {
|
|
|
|
|
return v >= 0x20 && v < 0x7f || v == '\t' || v == '\r' || v == '\n'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func toHex(v byte) byte {
|
|
|
|
|
if v < 10 {
|
|
|
|
|
return '0' + v
|
|
|
|
|
}
|
|
|
|
|
return 'a' + v - 10
|
|
|
|
|
}
|