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  }