[compiler-rt] [compiler-rt][asan] intercept bsd's strtoq. (PR #78097)

David CARLIER via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 14 07:54:37 PST 2024


https://github.com/devnexen updated https://github.com/llvm/llvm-project/pull/78097

>From 8bd4a5613f86903b5331d5f98842ab613bb0b9c5 Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen at gmail.com>
Date: Sun, 14 Jan 2024 14:17:52 +0000
Subject: [PATCH] [compiler-rt][asan] intercept bsd's strtoq.

---
 compiler-rt/lib/asan/asan_interceptors.cpp    |   4 +
 .../asan/TestCases/FreeBSD/strtoq_strict.c    | 116 ++++++++++++++++++
 2 files changed, 120 insertions(+)
 create mode 100644 compiler-rt/test/asan/TestCases/FreeBSD/strtoq_strict.c

diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp
index 4de2fa356374a6..eeb475bc5c03db 100644
--- a/compiler-rt/lib/asan/asan_interceptors.cpp
+++ b/compiler-rt/lib/asan/asan_interceptors.cpp
@@ -635,6 +635,10 @@ INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol)
 INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)
 #  endif
 
+#  if SANITIZER_FREEBSD || SANITIZER_NETBSD
+INTERCEPTOR_STRTO_BASE(u64, strtoq)
+#  endif
+
 INTERCEPTOR(int, atoi, const char *nptr) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, atoi);
diff --git a/compiler-rt/test/asan/TestCases/FreeBSD/strtoq_strict.c b/compiler-rt/test/asan/TestCases/FreeBSD/strtoq_strict.c
new file mode 100644
index 00000000000000..d12bae17f7c1c7
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/FreeBSD/strtoq_strict.c
@@ -0,0 +1,116 @@
+// Test strict_string_checks option in strtoq function
+// RUN: %clang_asan %s -o %t
+// RUN: %run %t test1 2>&1
+// RUN: %env_asan_opts=strict_string_checks=false %run %t test1 2>&1
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test1 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %run %t test2 2>&1
+// RUN: %env_asan_opts=strict_string_checks=false %run %t test2 2>&1
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test2 2>&1 | FileCheck %s --check-prefix=CHECK2
+// RUN: %run %t test3 2>&1
+// RUN: %env_asan_opts=strict_string_checks=false %run %t test3 2>&1
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test3 2>&1 | FileCheck %s --check-prefix=CHECK3
+// RUN: %run %t test4 2>&1
+// RUN: %env_asan_opts=strict_string_checks=false %run %t test4 2>&1
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test4 2>&1 | FileCheck %s --check-prefix=CHECK4
+// RUN: %run %t test5 2>&1
+// RUN: %env_asan_opts=strict_string_checks=false %run %t test5 2>&1
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test5 2>&1 | FileCheck %s --check-prefix=CHECK5
+// RUN: %run %t test6 2>&1
+// RUN: %env_asan_opts=strict_string_checks=false %run %t test6 2>&1
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test6 2>&1 | FileCheck %s --check-prefix=CHECK6
+// RUN: %run %t test7 2>&1
+// RUN: %env_asan_opts=strict_string_checks=false %run %t test7 2>&1
+// RUN: %env_asan_opts=strict_string_checks=true not %run %t test7 2>&1 | FileCheck %s --check-prefix=CHECK7
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sanitizer/asan_interface.h>
+
+void test1(char *array, char *endptr) {
+  // Buffer overflow if there is no terminating null (depends on base)
+  quad_t r = strtoq(array, &endptr, 3);
+  assert(array + 2 == endptr);
+  assert(r == 5);
+}
+
+void test2(char *array, char *endptr) {
+  // Buffer overflow if there is no terminating null (depends on base)
+  array[2] = 'z';
+  quad_t r = strtoq(array, &endptr, 35);
+  assert(array + 2 == endptr);
+  assert(r == 37);
+}
+
+void test3(char *array, char *endptr) {
+  // Buffer overflow if base is invalid.
+  memset(array, 0, 8);
+  ASAN_POISON_MEMORY_REGION(array, 8);
+  quad_t r = strtoq(array + 1, NULL, -1);
+  assert(r == 0);
+  ASAN_UNPOISON_MEMORY_REGION(array, 8);
+}
+
+void test4(char *array, char *endptr) {
+  // Buffer overflow if base is invalid.
+  quad_t r = strtoq(array + 3, NULL, 1);
+  assert(r == 0);
+}
+
+void test5(char *array, char *endptr) {
+  // Overflow if no digits are found.
+  array[0] = ' ';
+  array[1] = '+';
+  array[2] = '-';
+  quad_t r = strtoq(array, NULL, 0);
+  assert(r == 0);
+}
+
+void test6(char *array, char *endptr) {
+  // Overflow if no digits are found.
+  array[0] = ' ';
+  array[1] = array[2] = 'z';
+  quad_t r = strtoq(array, &endptr, 0);
+  assert(array == endptr);
+  assert(r == 0);
+}
+
+void test7(char *array, char *endptr) {
+  // Overflow if no digits are found.
+  array[2] = 'z';
+  quad_t r = strtoq(array + 2, NULL, 0);
+  assert(r == 0);
+}
+
+int main(int argc, char **argv) {
+  char *array0 = (char*)malloc(11);
+  char* array = array0 + 8;
+  char *endptr = NULL;
+  array[0] = '1';
+  array[1] = '2';
+  array[2] = '3';
+  if (argc != 2) return 1;
+  if (!strcmp(argv[1], "test1")) test1(array, endptr);
+  // CHECK1: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK1: READ of size 4
+  if (!strcmp(argv[1], "test2")) test2(array, endptr);
+  // CHECK2: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK2: READ of size 4
+  if (!strcmp(argv[1], "test3")) test3(array0, endptr);
+  // CHECK3: {{.*ERROR: AddressSanitizer: use-after-poison on address}}
+  // CHECK3: READ of size 1
+  if (!strcmp(argv[1], "test4")) test4(array, endptr);
+  // CHECK4: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK4: READ of size 1
+  if (!strcmp(argv[1], "test5")) test5(array, endptr);
+  // CHECK5: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK5: READ of size 4
+  if (!strcmp(argv[1], "test6")) test6(array, endptr);
+  // CHECK6: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK6: READ of size 4
+  if (!strcmp(argv[1], "test7")) test7(array, endptr);
+  // CHECK7: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}}
+  // CHECK7: READ of size 2
+  free(array0);
+  return 0;
+}



More information about the llvm-commits mailing list