github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/csource/common.go (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 //go:generate go run gen.go 5 6 package csource 7 8 import ( 9 "bytes" 10 "fmt" 11 "regexp" 12 "runtime" 13 "sort" 14 "strings" 15 16 "github.com/google/syzkaller/executor" 17 "github.com/google/syzkaller/pkg/osutil" 18 "github.com/google/syzkaller/prog" 19 "github.com/google/syzkaller/sys/targets" 20 ) 21 22 const ( 23 sandboxNone = "none" 24 sandboxSetuid = "setuid" 25 sandboxNamespace = "namespace" 26 sandboxAndroid = "android" 27 ) 28 29 func createCommonHeader(p, mmapProg *prog.Prog, replacements map[string]string, opts Options) ([]byte, error) { 30 defines := defineList(p, mmapProg, opts) 31 sysTarget := targets.Get(p.Target.OS, p.Target.Arch) 32 // Note: -fdirectives-only isn't supported by clang. This code is relevant 33 // for producing C++ reproducers. Hence reproducers don't work when setting 34 // CPP in targets.go to clang++ at the moment. 35 cmd := osutil.Command(sysTarget.CPP, "-nostdinc", "-undef", "-fdirectives-only", "-dDI", "-E", "-P", "-CC", "-") 36 for _, def := range defines { 37 cmd.Args = append(cmd.Args, "-D"+def) 38 } 39 cmd.Stdin = bytes.NewReader(executor.CommonHeader) 40 stderr := new(bytes.Buffer) 41 stdout := new(bytes.Buffer) 42 cmd.Stderr = stderr 43 cmd.Stdout = stdout 44 // Note: we ignore error because we pass -nostdinc so there are lots of errors of the form: 45 // error: no include path in which to search for stdlib.h 46 // This is exactly what we want: we don't want these to be included into the C reproducer. 47 // But the downside is that we can miss some real errors, e.g.: 48 // error: missing binary operator before token "SYZ_SANDBOX_ANDROID" 49 // 3776 | #if not SYZ_SANDBOX_ANDROID 50 // Potentially we could analyze errors manually and ignore only the expected ones. 51 if err := cmd.Run(); len(stdout.Bytes()) == 0 { 52 return nil, fmt.Errorf("cpp failed: %v %v: %w\n%v\n%v", cmd.Path, cmd.Args, err, stdout.String(), stderr.String()) 53 } 54 55 src, err := removeSystemDefines(stdout.Bytes(), defines) 56 if err != nil { 57 return nil, err 58 } 59 60 for from, to := range replacements { 61 src = bytes.Replace(src, []byte("/*{{{"+from+"}}}*/"), []byte(to), -1) 62 } 63 64 for from, to := range map[string]string{ 65 "uint64": "uint64_t", 66 "uint32": "uint32_t", 67 "uint16": "uint16_t", 68 "uint8": "uint8_t", 69 } { 70 src = bytes.Replace(src, []byte(from), []byte(to), -1) 71 } 72 src = regexp.MustCompile("#define SYZ_HAVE_.*").ReplaceAll(src, nil) 73 74 return src, nil 75 } 76 77 func defineList(p, mmapProg *prog.Prog, opts Options) (defines []string) { 78 for def, ok := range commonDefines(p, opts) { 79 if ok { 80 defines = append(defines, def) 81 } 82 } 83 for _, c := range p.Calls { 84 defines = append(defines, "__NR_"+c.Meta.CallName) 85 } 86 for _, c := range mmapProg.Calls { 87 defines = append(defines, "__NR_"+c.Meta.CallName) 88 } 89 sort.Strings(defines) 90 return 91 } 92 93 func commonDefines(p *prog.Prog, opts Options) map[string]bool { 94 sysTarget := targets.Get(p.Target.OS, p.Target.Arch) 95 features := p.RequiredFeatures() 96 return map[string]bool{ 97 "GOOS_" + p.Target.OS: true, 98 "GOARCH_" + p.Target.Arch: true, 99 "HOSTGOOS_" + runtime.GOOS: true, 100 "SYZ_USE_BITMASKS": features.Bitmasks, 101 "SYZ_USE_CHECKSUMS": features.Csums, 102 "SYZ_SANDBOX_NONE": opts.Sandbox == sandboxNone, 103 "SYZ_SANDBOX_SETUID": opts.Sandbox == sandboxSetuid, 104 "SYZ_SANDBOX_NAMESPACE": opts.Sandbox == sandboxNamespace, 105 "SYZ_SANDBOX_ANDROID": opts.Sandbox == sandboxAndroid, 106 "SYZ_THREADED": opts.Threaded, 107 "SYZ_ASYNC": features.Async, 108 "SYZ_REPEAT": opts.Repeat, 109 "SYZ_REPEAT_TIMES": opts.RepeatTimes > 1, 110 "SYZ_MULTI_PROC": opts.Procs > 1, 111 "SYZ_FAULT": features.FaultInjection, 112 "SYZ_LEAK": opts.Leak, 113 "SYZ_NET_INJECTION": opts.NetInjection, 114 "SYZ_NET_DEVICES": opts.NetDevices, 115 "SYZ_NET_RESET": opts.NetReset, 116 "SYZ_CGROUPS": opts.Cgroups, 117 "SYZ_BINFMT_MISC": opts.BinfmtMisc, 118 "SYZ_CLOSE_FDS": opts.CloseFDs, 119 "SYZ_KCSAN": opts.KCSAN, 120 "SYZ_DEVLINK_PCI": opts.DevlinkPCI, 121 "SYZ_NIC_VF": opts.NicVF, 122 "SYZ_USB": opts.USB, 123 "SYZ_VHCI_INJECTION": opts.VhciInjection, 124 "SYZ_USE_TMP_DIR": opts.UseTmpDir, 125 "SYZ_HANDLE_SEGV": opts.HandleSegv, 126 "SYZ_TRACE": opts.Trace, 127 "SYZ_WIFI": opts.Wifi, 128 "SYZ_802154": opts.IEEE802154, 129 "SYZ_SYSCTL": opts.Sysctl, 130 "SYZ_SWAP": opts.Swap, 131 "SYZ_EXECUTOR_USES_SHMEM": sysTarget.ExecutorUsesShmem, 132 "SYZ_EXECUTOR_USES_FORK_SERVER": sysTarget.ExecutorUsesForkServer, 133 } 134 } 135 136 func removeSystemDefines(src []byte, defines []string) ([]byte, error) { 137 remove := map[string]string{ 138 "__STDC__": "1", 139 "__STDC_HOSTED__": "1", 140 "__STDC_UTF_16__": "1", 141 "__STDC_UTF_32__": "1", 142 } 143 for _, def := range defines { 144 eq := strings.IndexByte(def, '=') 145 if eq == -1 { 146 remove[def] = "1" 147 } else { 148 remove[def[:eq]] = def[eq+1:] 149 } 150 } 151 for def, val := range remove { 152 src = bytes.Replace(src, []byte("#define "+def+" "+val+"\n"), nil, -1) 153 } 154 // strip: #define __STDC_VERSION__ 201112L 155 for _, def := range []string{"__STDC_VERSION__"} { 156 pos := bytes.Index(src, []byte("#define "+def)) 157 if pos == -1 { 158 continue 159 } 160 end := bytes.IndexByte(src[pos:], '\n') 161 if end == -1 { 162 continue 163 } 164 src = bytes.Replace(src, src[pos:end+1], nil, -1) 165 } 166 return src, nil 167 }