Source file src/runtime/libfuzzer.go

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build libfuzzer
     6  
     7  package runtime
     8  
     9  import "unsafe"
    10  
    11  func libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)
    12  func libfuzzerCallTraceIntCmp(fn *byte, arg0, arg1, fakePC uintptr)
    13  func libfuzzerCall4(fn *byte, fakePC uintptr, s1, s2 unsafe.Pointer, result uintptr)
    14  
    15  // Keep in sync with the definition of ret_sled in src/runtime/libfuzzer_amd64.s
    16  const retSledSize = 512
    17  
    18  // In libFuzzer mode, the compiler inserts calls to libfuzzerTraceCmpN and libfuzzerTraceConstCmpN
    19  // (where N can be 1, 2, 4, or 8) for encountered integer comparisons in the code to be instrumented.
    20  // This may result in these functions having callers that are nosplit. That is why they must be nosplit.
    21  //
    22  //go:nosplit
    23  func libfuzzerTraceCmp1(arg0, arg1 uint8, fakePC int) {
    24  	fakePC = fakePC % retSledSize
    25  	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp1, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
    26  }
    27  
    28  //go:nosplit
    29  func libfuzzerTraceCmp2(arg0, arg1 uint16, fakePC int) {
    30  	fakePC = fakePC % retSledSize
    31  	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp2, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
    32  }
    33  
    34  //go:nosplit
    35  func libfuzzerTraceCmp4(arg0, arg1 uint32, fakePC int) {
    36  	fakePC = fakePC % retSledSize
    37  	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp4, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
    38  }
    39  
    40  //go:nosplit
    41  func libfuzzerTraceCmp8(arg0, arg1 uint64, fakePC int) {
    42  	fakePC = fakePC % retSledSize
    43  	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_cmp8, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
    44  }
    45  
    46  //go:nosplit
    47  func libfuzzerTraceConstCmp1(arg0, arg1 uint8, fakePC int) {
    48  	fakePC = fakePC % retSledSize
    49  	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp1, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
    50  }
    51  
    52  //go:nosplit
    53  func libfuzzerTraceConstCmp2(arg0, arg1 uint16, fakePC int) {
    54  	fakePC = fakePC % retSledSize
    55  	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp2, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
    56  }
    57  
    58  //go:nosplit
    59  func libfuzzerTraceConstCmp4(arg0, arg1 uint32, fakePC int) {
    60  	fakePC = fakePC % retSledSize
    61  	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp4, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
    62  }
    63  
    64  //go:nosplit
    65  func libfuzzerTraceConstCmp8(arg0, arg1 uint64, fakePC int) {
    66  	fakePC = fakePC % retSledSize
    67  	libfuzzerCallTraceIntCmp(&__sanitizer_cov_trace_const_cmp8, uintptr(arg0), uintptr(arg1), uintptr(fakePC))
    68  }
    69  
    70  var pcTables []byte
    71  
    72  func init() {
    73  	libfuzzerCallWithTwoByteBuffers(&__sanitizer_cov_8bit_counters_init, &__start___sancov_cntrs, &__stop___sancov_cntrs)
    74  	start := unsafe.Pointer(&__start___sancov_cntrs)
    75  	end := unsafe.Pointer(&__stop___sancov_cntrs)
    76  
    77  	// PC tables are arrays of ptr-sized integers representing pairs [PC,PCFlags] for every instrumented block.
    78  	// The number of PCs and PCFlags is the same as the number of 8-bit counters. Each PC table entry has
    79  	// the size of two ptr-sized integers. We allocate one more byte than what we actually need so that we can
    80  	// get a pointer representing the end of the PC table array.
    81  	size := (uintptr(end)-uintptr(start))*unsafe.Sizeof(uintptr(0))*2 + 1
    82  	pcTables = make([]byte, size)
    83  	libfuzzerCallWithTwoByteBuffers(&__sanitizer_cov_pcs_init, &pcTables[0], &pcTables[size-1])
    84  }
    85  
    86  // We call libFuzzer's __sanitizer_weak_hook_strcmp function which takes the
    87  // following four arguments:
    88  //
    89  //  1. caller_pc: location of string comparison call site
    90  //  2. s1: first string used in the comparison
    91  //  3. s2: second string used in the comparison
    92  //  4. result: an integer representing the comparison result. 0 indicates
    93  //     equality (comparison will ignored by libfuzzer), non-zero indicates a
    94  //     difference (comparison will be taken into consideration).
    95  //
    96  //go:nosplit
    97  func libfuzzerHookStrCmp(s1, s2 string, fakePC int) {
    98  	if s1 != s2 {
    99  		libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))
   100  	}
   101  	// if s1 == s2 we could call the hook with a last argument of 0 but this is unnecessary since this case will be then
   102  	// ignored by libfuzzer
   103  }
   104  
   105  // This function has now the same implementation as libfuzzerHookStrCmp because we lack better checks
   106  // for case-insensitive string equality in the runtime package.
   107  //
   108  //go:nosplit
   109  func libfuzzerHookEqualFold(s1, s2 string, fakePC int) {
   110  	if s1 != s2 {
   111  		libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))
   112  	}
   113  }
   114  
   115  //go:linkname __sanitizer_cov_trace_cmp1 __sanitizer_cov_trace_cmp1
   116  //go:cgo_import_static __sanitizer_cov_trace_cmp1
   117  var __sanitizer_cov_trace_cmp1 byte
   118  
   119  //go:linkname __sanitizer_cov_trace_cmp2 __sanitizer_cov_trace_cmp2
   120  //go:cgo_import_static __sanitizer_cov_trace_cmp2
   121  var __sanitizer_cov_trace_cmp2 byte
   122  
   123  //go:linkname __sanitizer_cov_trace_cmp4 __sanitizer_cov_trace_cmp4
   124  //go:cgo_import_static __sanitizer_cov_trace_cmp4
   125  var __sanitizer_cov_trace_cmp4 byte
   126  
   127  //go:linkname __sanitizer_cov_trace_cmp8 __sanitizer_cov_trace_cmp8
   128  //go:cgo_import_static __sanitizer_cov_trace_cmp8
   129  var __sanitizer_cov_trace_cmp8 byte
   130  
   131  //go:linkname __sanitizer_cov_trace_const_cmp1 __sanitizer_cov_trace_const_cmp1
   132  //go:cgo_import_static __sanitizer_cov_trace_const_cmp1
   133  var __sanitizer_cov_trace_const_cmp1 byte
   134  
   135  //go:linkname __sanitizer_cov_trace_const_cmp2 __sanitizer_cov_trace_const_cmp2
   136  //go:cgo_import_static __sanitizer_cov_trace_const_cmp2
   137  var __sanitizer_cov_trace_const_cmp2 byte
   138  
   139  //go:linkname __sanitizer_cov_trace_const_cmp4 __sanitizer_cov_trace_const_cmp4
   140  //go:cgo_import_static __sanitizer_cov_trace_const_cmp4
   141  var __sanitizer_cov_trace_const_cmp4 byte
   142  
   143  //go:linkname __sanitizer_cov_trace_const_cmp8 __sanitizer_cov_trace_const_cmp8
   144  //go:cgo_import_static __sanitizer_cov_trace_const_cmp8
   145  var __sanitizer_cov_trace_const_cmp8 byte
   146  
   147  //go:linkname __sanitizer_cov_8bit_counters_init __sanitizer_cov_8bit_counters_init
   148  //go:cgo_import_static __sanitizer_cov_8bit_counters_init
   149  var __sanitizer_cov_8bit_counters_init byte
   150  
   151  //go:linkname __start___sancov_cntrs __start___sancov_cntrs
   152  //go:cgo_import_static __start___sancov_cntrs
   153  var __start___sancov_cntrs byte
   154  
   155  //go:linkname __stop___sancov_cntrs __stop___sancov_cntrs
   156  //go:cgo_import_static __stop___sancov_cntrs
   157  var __stop___sancov_cntrs byte
   158  
   159  //go:linkname __sanitizer_cov_pcs_init __sanitizer_cov_pcs_init
   160  //go:cgo_import_static __sanitizer_cov_pcs_init
   161  var __sanitizer_cov_pcs_init byte
   162  
   163  //go:linkname __sanitizer_weak_hook_strcmp __sanitizer_weak_hook_strcmp
   164  //go:cgo_import_static __sanitizer_weak_hook_strcmp
   165  var __sanitizer_weak_hook_strcmp byte
   166  

View as plain text