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