aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/libfuzzer.go30
-rw-r--r--src/runtime/libfuzzer_amd64.s31
-rw-r--r--src/runtime/libfuzzer_arm64.s32
3 files changed, 90 insertions, 3 deletions
diff --git a/src/runtime/libfuzzer.go b/src/runtime/libfuzzer.go
index 920ac575f5..c136eaf5fe 100644
--- a/src/runtime/libfuzzer.go
+++ b/src/runtime/libfuzzer.go
@@ -9,6 +9,7 @@ package runtime
import "unsafe"
func libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)
+func libfuzzerCall4(fn *byte, fakePC uintptr, s1, s2 unsafe.Pointer, result uintptr)
func libfuzzerCall(fn *byte, arg0, arg1 uintptr)
func libfuzzerTraceCmp1(arg0, arg1 uint8) {
@@ -59,6 +60,31 @@ func init() {
libfuzzerCallWithTwoByteBuffers(&__sanitizer_cov_pcs_init, &pcTables[0], &pcTables[size-1])
}
+// We call libFuzzer's __sanitizer_weak_hook_strcmp function
+// which takes the following four arguments:
+// 1- caller_pc: location of string comparison call site
+// 2- s1: first string used in the comparison
+// 3- s2: second string used in the comparison
+// 4- result: an integer representing the comparison result. Libfuzzer only distinguishes between two cases:
+// - 0 means that the strings are equal and the comparison will be ignored by libfuzzer.
+// - Any other value means that strings are not equal and libfuzzer takes the comparison into consideration.
+// Here, we pass 1 when the strings are not equal.
+func libfuzzerHookStrCmp(s1, s2 string, fakePC int) {
+ if s1 != s2 {
+ libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))
+ }
+ // if s1 == s2 we could call the hook with a last argument of 0 but this is unnecessary since this case will be then
+ // ignored by libfuzzer
+}
+
+// This function has now the same implementation as libfuzzerHookStrCmp because we lack better checks
+// for case-insensitive string equality in the runtime package.
+func libfuzzerHookEqualFold(s1, s2 string, fakePC int) {
+ if s1 != s2 {
+ libfuzzerCall4(&__sanitizer_weak_hook_strcmp, uintptr(fakePC), cstring(s1), cstring(s2), uintptr(1))
+ }
+}
+
//go:linkname __sanitizer_cov_trace_cmp1 __sanitizer_cov_trace_cmp1
//go:cgo_import_static __sanitizer_cov_trace_cmp1
var __sanitizer_cov_trace_cmp1 byte
@@ -106,3 +132,7 @@ var __stop___sancov_cntrs byte
//go:linkname __sanitizer_cov_pcs_init __sanitizer_cov_pcs_init
//go:cgo_import_static __sanitizer_cov_pcs_init
var __sanitizer_cov_pcs_init byte
+
+//go:linkname __sanitizer_weak_hook_strcmp __sanitizer_weak_hook_strcmp
+//go:cgo_import_static __sanitizer_weak_hook_strcmp
+var __sanitizer_weak_hook_strcmp byte
diff --git a/src/runtime/libfuzzer_amd64.s b/src/runtime/libfuzzer_amd64.s
index 5ea77f59de..032821fbbc 100644
--- a/src/runtime/libfuzzer_amd64.s
+++ b/src/runtime/libfuzzer_amd64.s
@@ -13,12 +13,41 @@
#ifdef GOOS_windows
#define RARG0 CX
#define RARG1 DX
+#define RARG0 R8
+#define RARG1 R9
#else
#define RARG0 DI
#define RARG1 SI
+#define RARG2 DX
+#define RARG3 CX
#endif
-// void runtime·libfuzzerCall(fn, arg0, arg1 uintptr)
+// void runtime·libfuzzerCall4(fn, hookId int, s1, s2 unsafe.Pointer, result uintptr)
+// Calls C function fn from libFuzzer and passes 4 arguments to it.
+TEXT runtime·libfuzzerCall4(SB), NOSPLIT, $0-40
+ MOVQ fn+0(FP), AX
+ MOVQ hookId+8(FP), RARG0
+ MOVQ s1+16(FP), RARG1
+ MOVQ s2+24(FP), RARG2
+ MOVQ result+32(FP), RARG3
+
+ get_tls(R12)
+ MOVQ g(R12), R14
+ MOVQ g_m(R14), R13
+
+ // Switch to g0 stack.
+ MOVQ SP, R12 // callee-saved, preserved across the CALL
+ MOVQ m_g0(R13), R10
+ CMPQ R10, R14
+ JE call // already on g0
+ MOVQ (g_sched+gobuf_sp)(R10), SP
+call:
+ ANDQ $~15, SP // alignment for gcc ABI
+ CALL AX
+ MOVQ R12, SP
+ RET
+
+// void runtime·libfuzzerCallTraceInit(fn, start, end *byte)
// Calls C function fn from libFuzzer and passes 2 arguments to it.
TEXT runtime·libfuzzerCall(SB), NOSPLIT, $0-24
MOVQ fn+0(FP), AX
diff --git a/src/runtime/libfuzzer_arm64.s b/src/runtime/libfuzzer_arm64.s
index b0146682a2..f9b67913e2 100644
--- a/src/runtime/libfuzzer_arm64.s
+++ b/src/runtime/libfuzzer_arm64.s
@@ -9,12 +9,40 @@
// Based on race_arm64.s; see commentary there.
+#define RARG0 R0
+#define RARG1 R1
+#define RARG2 R2
+#define RARG3 R3
+
+// void runtime·libfuzzerCall4(fn, hookId int, s1, s2 unsafe.Pointer, result uintptr)
+// Calls C function fn from libFuzzer and passes 4 arguments to it.
+TEXT runtime·libfuzzerCall4(SB), NOSPLIT, $0-40
+ MOVD fn+0(FP), R9
+ MOVD hookId+8(FP), RARG0
+ MOVD s1+16(FP), RARG1
+ MOVD s2+24(FP), RARG2
+ MOVD result+32(FP), RARG3
+
+ MOVD g_m(g), R10
+
+ // Switch to g0 stack.
+ MOVD RSP, R19 // callee-saved, preserved across the CALL
+ MOVD m_g0(R10), R11
+ CMP R11, g
+ BEQ call // already on g0
+ MOVD (g_sched+gobuf_sp)(R11), R12
+ MOVD R12, RSP
+call:
+ BL R9
+ MOVD R19, RSP
+ RET
+
// func runtime·libfuzzerCall(fn, arg0, arg1 uintptr)
// Calls C function fn from libFuzzer and passes 2 arguments to it.
TEXT runtime·libfuzzerCall(SB), NOSPLIT, $0-24
MOVD fn+0(FP), R9
- MOVD arg0+8(FP), R0
- MOVD arg1+16(FP), R1
+ MOVD arg0+8(FP), RARG0
+ MOVD arg1+16(FP), RARG1
MOVD g_m(g), R10