[ASan] Add FORTIFY_SOURCE interceptors 80/162380/5
authorDenis Khalikov <d.khalikov@partner.samsung.com>
Wed, 29 Nov 2017 11:21:07 +0000 (14:21 +0300)
committerDongkyun Son <dongkyun.s@samsung.com>
Thu, 19 Jul 2018 09:13:04 +0000 (09:13 +0000)
List of interceptors:
__strcat_chk,
__strncat_chk,
__strcpy_chk,
__strncpy_chk.
__poll_chk,
__ppoll_chk,
__read_chk,
__recv_chk,
__recvfrom_chk,
__pread_chk,
__pread64_chk.
__getgroups_chk,
__getcwd_chk,
__realpath_chk,
__confstr_chk.
__mbstowcs_chk,
__mbsrtowcs_chk,
__mbsnrtowcs_chk,
__wcstombs_chk,
__wcsrtombs_chk,
__wcsnrtombs_chk,
__wcrtomb_chk,
__ttyname_r_chk.

Change-Id: I16ef4d2d80089b96e5c51ea5160b706b35f9ce18

16 files changed:
gcc/testsuite/c-c++-common/asan/strcat-overflow-fortify-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/strcpy-overflow-fortify-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/strncat-overflow-fortify-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/asan/strncpy-overflow-fortify-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/asan/confstr-fortify-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/asan/getcwd-fortify-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/asan/mbsrtowcs-fortify-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/asan/mbstowcs-fortify-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/asan/realpath-fortify-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/asan/wcrtomb-fortify-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/asan/wcsrtombs-fortify-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/asan/wcstombs-fortify-1.c [new file with mode: 0644]
libsanitizer/asan/asan_interceptors.cc
libsanitizer/asan/asan_interceptors.h
libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h

diff --git a/gcc/testsuite/c-c++-common/asan/strcat-overflow-fortify-1.c b/gcc/testsuite/c-c++-common/asan/strcat-overflow-fortify-1.c
new file mode 100644 (file)
index 0000000..06e8f47
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *hello = (char*)malloc(6);
+  strcpy(hello, "hello");
+  hello[5] = '\0';
+  strcat(hello, "world");  /* BOOM */
+  return hello[0];
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__strcat_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/c-c++-common/asan/strcpy-overflow-fortify-1.c b/gcc/testsuite/c-c++-common/asan/strcpy-overflow-fortify-1.c
new file mode 100644 (file)
index 0000000..e26ecf5
--- /dev/null
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *short_buffer = (char*)malloc(3);
+  strcpy(short_buffer, "hello");  /* BOOM */
+  return short_buffer[0];
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__strcpy_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/c-c++-common/asan/strncat-overflow-fortify-1.c b/gcc/testsuite/c-c++-common/asan/strncat-overflow-fortify-1.c
new file mode 100644 (file)
index 0000000..601b701
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *hello = (char*)malloc(6);
+  strcpy(hello, "hello");
+  strncat(hello, "world", 10);  /* BOOM */
+  return hello[0];
+}
+// Compiler could optimize strncat under -O1 or above level of optimization but
+// FORTIFY_SOURCE option enables only on that level.
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__str*cat_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/c-c++-common/asan/strncpy-overflow-fortify-1.c b/gcc/testsuite/c-c++-common/asan/strncpy-overflow-fortify-1.c
new file mode 100644 (file)
index 0000000..c02ba8d
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *hello = (char*)malloc(6);
+  strcpy(hello, "hello");
+  char *short_buffer = (char*)malloc(9);
+  strncpy(short_buffer, hello, 10);  /* BOOM */
+  return short_buffer[0];
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__strncpy_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/gcc.dg/asan/confstr-fortify-1.c b/gcc/testsuite/gcc.dg/asan/confstr-fortify-1.c
new file mode 100644 (file)
index 0000000..5ec3099
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *short_buffer = (char*)malloc(3);
+  confstr (_CS_PATH, short_buffer, 10);
+  return short_buffer[0];
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__confstr_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/gcc.dg/asan/getcwd-fortify-1.c b/gcc/testsuite/gcc.dg/asan/getcwd-fortify-1.c
new file mode 100644 (file)
index 0000000..b6b9973
--- /dev/null
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *short_buffer = (char*)malloc(3);
+  getcwd (short_buffer, 4096);
+  return short_buffer[0];
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__getcwd_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/gcc.dg/asan/mbsrtowcs-fortify-1.c b/gcc/testsuite/gcc.dg/asan/mbsrtowcs-fortify-1.c
new file mode 100644 (file)
index 0000000..224f360
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  wchar_t *short_buffer = (wchar_t *)malloc(sizeof (wchar_t));
+  mbstate_t ps;
+  const char *string = "long string";
+  memset (&ps, 0, sizeof (mbstate_t));
+  mbsrtowcs (short_buffer, &string, 10, &ps);
+  return short_buffer[0];
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__mbsrtowcs_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/gcc.dg/asan/mbstowcs-fortify-1.c b/gcc/testsuite/gcc.dg/asan/mbstowcs-fortify-1.c
new file mode 100644 (file)
index 0000000..a43c7f2
--- /dev/null
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  wchar_t *short_buffer = (wchar_t *)malloc(sizeof (wchar_t));
+  mbstowcs (short_buffer, "long string ", 10);
+  return short_buffer[0];
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__mbstowcs_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/gcc.dg/asan/realpath-fortify-1.c b/gcc/testsuite/gcc.dg/asan/realpath-fortify-1.c
new file mode 100644 (file)
index 0000000..e70e0df
--- /dev/null
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *short_buffer = (char*)malloc(3);
+  realpath ("../", short_buffer);
+  return short_buffer[0];
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__realpath_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/gcc.dg/asan/wcrtomb-fortify-1.c b/gcc/testsuite/gcc.dg/asan/wcrtomb-fortify-1.c
new file mode 100644 (file)
index 0000000..8a34466
--- /dev/null
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <locale.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *short_buffer = (char *) malloc (sizeof (char));
+  mbstate_t ps;
+  memset (&ps, 0, sizeof (ps));
+  const wchar_t *string = L"ABC";
+  setlocale(LC_ALL, "en_US.UTF-8");
+  size_t result = wcrtomb (short_buffer, 0xff40, &ps);
+  return result;
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__wcrtomb_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/gcc.dg/asan/wcsrtombs-fortify-1.c b/gcc/testsuite/gcc.dg/asan/wcsrtombs-fortify-1.c
new file mode 100644 (file)
index 0000000..77e60a9
--- /dev/null
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <locale.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *short_buffer = (char *) malloc (sizeof (char));
+  const wchar_t *string = L"ABC";
+  mbstate_t ps;
+  memset (&ps, 0, sizeof (mbstate_t));
+  setlocale(LC_ALL, "en_US.UTF-8");
+  size_t result = wcsrtombs (short_buffer, &string, 4096, &ps);
+  return result;
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__wcsrtombs_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
diff --git a/gcc/testsuite/gcc.dg/asan/wcstombs-fortify-1.c b/gcc/testsuite/gcc.dg/asan/wcstombs-fortify-1.c
new file mode 100644 (file)
index 0000000..d50e5fa
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "-D_FORTIFY_SOURCE=1 -w" } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O1" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <locale.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *
+__asan_default_options () {
+  return "fast_unwind_on_malloc=false";
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+int main(int argc, char **argv) {
+  char *short_buffer = (char *) malloc (sizeof (char));
+  const wchar_t *string = L"ABC";
+  setlocale(LC_ALL, "en_US.UTF-8");
+  size_t result = wcstombs (short_buffer, string, 4096);
+  return result;
+}
+/* { dg-output "    #0 0x\[0-9a-f\]+ +(in _*(interceptor_|wrap_|)__wcstombs_chk|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
index 49c9fef..1678372 100644 (file)
@@ -611,6 +611,85 @@ INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
   return REAL(strncpy)(to, from, size);
 }
 
+#if ASAN_INTERCEPT__FORTIFY_SOURCE
+INTERCEPTOR(char*, __strcpy_chk, char *to, const char *from,
+            uptr to_size) {  // NOLINT
+  void *ctx;
+  ASAN_INTERCEPTOR_ENTER(ctx, __strcpy_chk);  // NOLINT
+#if SANITIZER_MAC
+  if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from);  // NOLINT
+#endif
+  // strcpy is called from malloc_default_purgeable_zone()
+  // in __asan::ReplaceSystemAlloc() on Mac.
+  if (asan_init_is_running) {
+    return REAL(strcpy)(to, from);  // NOLINT
+  }
+  ENSURE_ASAN_INITED();
+  if (flags()->replace_str) {
+    uptr from_size = REAL(strlen)(from) + 1;
+    CHECK_RANGES_OVERLAP("__strcpy_chk", to, to_size, from, from_size);
+    ASAN_READ_RANGE(ctx, from, from_size);
+    ASAN_WRITE_RANGE(ctx, to, from_size);
+  }
+  return REAL(strcpy)(to, from);  // NOLINT
+}
+
+INTERCEPTOR(char*, __strncpy_chk, char *to, const char *from, uptr size,
+            uptr to_size) {
+  void *ctx;
+  ASAN_INTERCEPTOR_ENTER(ctx, __strncpy_chk);
+  ENSURE_ASAN_INITED();
+  if (flags()->replace_str) {
+    uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
+    CHECK_RANGES_OVERLAP("__strncpy_chk", to, to_size, from, from_size);
+    ASAN_READ_RANGE(ctx, from, from_size);
+    ASAN_WRITE_RANGE(ctx, to, size);
+  }
+  return REAL(strncpy)(to, from, size);
+}
+
+INTERCEPTOR(char*, __strcat_chk, char *to, const char *from, uptr to_size) {
+  void *ctx;
+  ASAN_INTERCEPTOR_ENTER(ctx, __strcat_chk);  // NOLINT
+  ENSURE_ASAN_INITED();
+  if (flags()->replace_str) {
+    uptr from_length = REAL(strlen)(from);
+    ASAN_READ_RANGE(ctx, from, from_length + 1);
+    uptr to_length = REAL(strlen)(to);
+    ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
+    ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
+    // If the copying actually happens, the |from| string should not overlap
+    // with the resulting string starting at |to|, which has a length of
+    // to_length + from_length + 1.
+    if (from_length > 0) {
+      CHECK_RANGES_OVERLAP("__strcat_chk", to, to_size,
+                           from, from_length + 1);
+    }
+  }
+  return REAL(strcat)(to, from);  // NOLINT
+}
+
+INTERCEPTOR(char*, __strncat_chk, char *to, const char *from, uptr size,
+            uptr to_size) {
+  void *ctx;
+  ASAN_INTERCEPTOR_ENTER(ctx, __strncat_chk);
+  ENSURE_ASAN_INITED();
+  if (flags()->replace_str) {
+    uptr from_length = MaybeRealStrnlen(from, size);
+    uptr copy_length = Min(size, from_length + 1);
+    ASAN_READ_RANGE(ctx, from, copy_length);
+    uptr to_length = REAL(strlen)(to);
+    ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
+    ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
+    if (from_length > 0) {
+      CHECK_RANGES_OVERLAP("__strncat_chk", to, to_size,
+                           from, copy_length);
+    }
+  }
+  return REAL(strncat)(to, from, size);
+}
+#endif //ASAN_INTERCEPT__FORTIFY_SOURCE
+
 INTERCEPTOR(long, strtol, const char *nptr,  // NOLINT
             char **endptr, int base) {
   void *ctx;
@@ -747,6 +826,14 @@ void InitializeAsanInterceptors() {
   ASAN_INTERCEPT_FUNC(strncat);
   ASAN_INTERCEPT_FUNC(strncpy);
   ASAN_INTERCEPT_FUNC(strdup);
+
+#if ASAN_INTERCEPT__FORTIFY_SOURCE
+  ASAN_INTERCEPT_FUNC(__strcat_chk);
+  ASAN_INTERCEPT_FUNC(__strncat_chk);
+  ASAN_INTERCEPT_FUNC(__strcpy_chk);
+  ASAN_INTERCEPT_FUNC(__strncpy_chk);
+#endif
+
 #if ASAN_INTERCEPT___STRDUP
   ASAN_INTERCEPT_FUNC(__strdup);
 #endif
index 565a632..706729c 100644 (file)
 # define ASAN_INTERCEPT___LONGJMP_CHK 0
 #endif
 
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+# define ASAN_INTERCEPT__FORTIFY_SOURCE 1
+#else
+# define ASAN_INTERCEPT__FORTIFY_SOURCE 0
+#endif
+
 // Android bug: https://code.google.com/p/android/issues/detail?id=61799
 #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
     !(SANITIZER_ANDROID && defined(__i386))
index c6f1ae0..19879b6 100644 (file)
@@ -778,6 +778,25 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
 #define INIT_READ
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SSIZE_T, __read_chk, int fd, void *ptr, SIZE_T count,
+            SIZE_T bufflen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __read_chk, fd, ptr, count, bufflen);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SSIZE_T res = REAL(read)(fd, ptr, count);
+  if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+  if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  return res;
+}
+#define INIT___READ_CHK COMMON_INTERCEPT_FUNCTION(__read_chk)
+#else
+#define INIT___READ_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_PREAD
 INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
   void *ctx;
@@ -796,6 +815,25 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
 #define INIT_PREAD
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SSIZE_T, __pread_chk, int fd, void *ptr, SIZE_T count,
+            OFF_T offset, SIZE_T buflen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __pread_chk, fd, ptr, count, offset, buflen);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
+  if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+  if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  return res;
+}
+#define INIT___PREAD_CHK COMMON_INTERCEPT_FUNCTION(__pread_chk)
+#else
+#define INIT___PREAD_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_PREAD64
 INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
   void *ctx;
@@ -814,6 +852,26 @@ INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
 #define INIT_PREAD64
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SSIZE_T, __pread64_chk, int fd, void *ptr, SIZE_T count,
+            OFF64_T offset, SIZE_T buflen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __pread64_chk, fd, ptr, count, offset,
+                          buflen);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
+  if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
+  if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  return res;
+}
+#define INIT___PREAD64_CHK COMMON_INTERCEPT_FUNCTION(__pread64_chk)
+#else
+#define INIT___PREAD64_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_READV
 INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov,
                         int iovcnt) {
@@ -2876,6 +2934,22 @@ INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) {
 #define INIT_GETCWD
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(char *, __getcwd_chk, char *buf, SIZE_T size, SIZE_T buflen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __getcwd_chk, buf, size, buflen);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  char *res = REAL(getcwd)(buf, size);
+  if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+#define INIT___GETCWD_CHK COMMON_INTERCEPT_FUNCTION(__getcwd_chk);
+#else
+#define INIT___GETCWD_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME
 INTERCEPTOR(char *, get_current_dir_name, int fake) {
   void *ctx;
@@ -2998,6 +3072,48 @@ INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len,
 #define INIT_MBSTOWCS
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SIZE_T, __mbstowcs_chk, wchar_t *dest, const char *src,
+            SIZE_T len, SIZE_T destlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __mbstowcs_chk, dest, src, len, destlen);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SIZE_T res = REAL(mbstowcs)(dest, src, len);
+  if (res != (SIZE_T) - 1 && dest) {
+    SIZE_T write_cnt = res + (res < len);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+  }
+  return res;
+}
+
+INTERCEPTOR(SIZE_T, __mbsrtowcs_chk, wchar_t *dest, const char **src,
+            SIZE_T len, void *ps, SIZE_T destlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __mbsrtowcs_chk, dest, src, len, ps, destlen);
+  if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+  if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps);
+  if (res != (SIZE_T)(-1) && dest && src) {
+    // This function, and several others, may or may not write the terminating
+    // \0 character. They write it iff they clear *src.
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+  }
+  return res;
+}
+
+#define INIT___MBSTOWCS_CHK                    \
+  COMMON_INTERCEPT_FUNCTION(__mbstowcs_chk); \
+  COMMON_INTERCEPT_FUNCTION(__mbsrtowcs_chk);
+#else
+#define INIT___MBSTOWCS_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_MBSNRTOWCS
 INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
             SIZE_T len, void *ps) {
@@ -3024,6 +3140,33 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms,
 #define INIT_MBSNRTOWCS
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SIZE_T, __mbsnrtowcs_chk, wchar_t *dest, const char **src,
+            SIZE_T nms, SIZE_T len, void *ps, SIZE_T destlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __mbsnrtowcs_chk, dest, src, nms, len, ps,
+                           destlen);
+  if (src) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+    if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+  }
+  if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps);
+  if (res != (SIZE_T)(-1) && dest && src) {
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt * sizeof(wchar_t));
+  }
+  return res;
+}
+
+#define INIT___MBSNRTOWCS_CHK COMMON_INTERCEPT_FUNCTION(__mbsnrtowcs_chk);
+#else
+#define INIT___MBSNRTOWCS_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_WCSTOMBS
 INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) {
   void *ctx;
@@ -3063,6 +3206,47 @@ INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len,
 #define INIT_WCSTOMBS
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SIZE_T, __wcstombs_chk, char *dest, const wchar_t *src,
+            SIZE_T len, SIZE_T destlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __wcstombs_chk, dest, src, len, destlen);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SIZE_T res = REAL(wcstombs)(dest, src, len);
+  if (res != (SIZE_T) - 1 && dest) {
+    SIZE_T write_cnt = res + (res < len);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
+  return res;
+}
+
+INTERCEPTOR(SIZE_T, __wcsrtombs_chk, char *dest, const wchar_t **src,
+            SIZE_T len, void *ps, SIZE_T destlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __wcsrtombs_chk, dest, src, len, ps,
+                           destlen);
+  if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+  if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps);
+  if (res != (SIZE_T) - 1 && dest && src) {
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
+  return res;
+}
+
+#define INIT___WCSTOMBS_CHK                    \
+  COMMON_INTERCEPT_FUNCTION(__wcstombs_chk); \
+  COMMON_INTERCEPT_FUNCTION(__wcsrtombs_chk);
+#else
+#define INIT___WCSTOMBS_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_WCSNRTOMBS
 INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
             SIZE_T len, void *ps) {
@@ -3089,6 +3273,32 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms,
 #define INIT_WCSNRTOMBS
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SIZE_T, __wcsnrtombs_chk, char *dest, const wchar_t **src,
+            SIZE_T nms, SIZE_T len, void *ps, SIZE_T destlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __wcsnrtombs_chk, dest, src, nms, len, ps,
+                           destlen);
+  if (src) {
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+    if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, nms);
+  }
+  if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps);
+  if (res != ((SIZE_T)-1) && dest && src) {
+    SIZE_T write_cnt = res + !*src;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
+  return res;
+}
+
+#define INIT___WCSNRTOMBS_CHK COMMON_INTERCEPT_FUNCTION(__wcsnrtombs_chk);
+#else
+#define INIT___WCSNRTOMBS_CHK
+#endif
 
 #if SANITIZER_INTERCEPT_WCRTOMB
 INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) {
@@ -3111,6 +3321,28 @@ INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) {
 #define INIT_WCRTOMB
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SIZE_T, __wcrtomb_chk, char *dest, wchar_t src, void *ps,
+            SIZE_T destlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __wcrtomb_chk, dest, src, ps, destlen);
+  if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SIZE_T res = REAL(wcrtomb)(dest, src, ps);
+  if (res != ((SIZE_T)-1) && dest) {
+    SIZE_T write_cnt = res;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt);
+  }
+  return res;
+}
+
+#define INIT___WCRTOMB_CHK COMMON_INTERCEPT_FUNCTION(__wcrtomb_chk);
+#else
+#define INIT___WCRTOMB_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_TCGETATTR
 INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) {
   void *ctx;
@@ -3153,6 +3385,32 @@ INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) {
 #define INIT_REALPATH
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(char *, __realpath_chk, const char *path, char *resolved_path,
+            SIZE_T resolvedlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __realpath_chk, path, resolved_path,
+                           resolvedlen);
+  if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+
+  // Workaround a bug in glibc where dlsym(RTLD_NEXT, ...) returns the oldest
+  // version of a versioned symbol. For realpath(), this gives us something
+  // (called __old_realpath) that does not handle NULL in the second argument.
+  // Handle it as part of the interceptor.
+  char *allocated_path = nullptr;
+  if (!resolved_path)
+    allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1);
+
+  char *res = REAL(realpath)(path, resolved_path);
+  if (allocated_path && !res) WRAP(free)(allocated_path);
+  if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
+  return res;
+}
+#define INIT___REALPATH_CHK COMMON_INTERCEPT_FUNCTION(__realpath_chk);
+#else
+#define INIT___REALPATH_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME
 INTERCEPTOR(char *, canonicalize_file_name, const char *path) {
   void *ctx;
@@ -3185,6 +3443,24 @@ INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) {
 #define INIT_CONFSTR
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SIZE_T, __confstr_chk, int name, char *buf, SIZE_T len,
+            SIZE_T bufflen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __confstr_chk, name, buf, len, bufflen);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  SIZE_T res = REAL(confstr)(name, buf, len);
+  if (buf && res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len);
+  return res;
+}
+#define INIT___CONFSTR_CHK COMMON_INTERCEPT_FUNCTION(__confstr_chk);
+#else
+#define INIT___CONFSTR_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_SCHED_GETAFFINITY
 INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) {
   void *ctx;
@@ -3399,6 +3675,23 @@ INTERCEPTOR(int, getgroups, int size, u32 *lst) {
 #define INIT_GETGROUPS
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(int, __getgroups_chk, int size, u32 *lst, SIZE_T lstsize) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __getgroups_chk, size, lst, lstsize);
+  // FIXME: under ASan the call below may write to freed memory and corrupt
+  // its metadata. See
+  // https://github.com/google/sanitizers/issues/321.
+  int res = REAL(getgroups)(size, lst);
+  if (res >= 0 && lst && size > 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst));
+  return res;
+}
+#define INIT___GETGROUPS_CHK COMMON_INTERCEPT_FUNCTION(__getgroups_chk);
+#else
+#define INIT___GETGROUPS_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_POLL
 static void read_pollfd(void *ctx, __sanitizer_pollfd *fds,
                         __sanitizer_nfds_t nfds) {
@@ -3448,6 +3741,42 @@ INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
 #define INIT_PPOLL
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(int, __poll_chk, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
+            int timeout, SIZE_T fdslen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __poll_chk, fds, nfds, timeout, fdslen);
+  if (fds && nfds) read_pollfd(ctx, fds, nfds);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(poll)(fds, nfds, timeout);
+  if (fds && nfds) write_pollfd(ctx, fds, nfds);
+  return res;
+}
+#define INIT___POLL_CHK COMMON_INTERCEPT_FUNCTION(__poll_chk);
+#else
+#define INIT___POLL_CHK
+#endif
+
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(int, __ppoll_chk, __sanitizer_pollfd *fds,
+            __sanitizer_nfds_t nfds, void *timeout_ts,
+            __sanitizer_sigset_t *sigmask, SIZE_T fdslen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __ppoll_chk, fds, nfds, timeout_ts,
+                           sigmask, fdslen);
+  if (fds && nfds) read_pollfd(ctx, fds, nfds);
+  if (timeout_ts)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz);
+  // FIXME: read sigmask when all of sigemptyset, etc are intercepted.
+  int res =
+      COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask);
+  if (fds && nfds) write_pollfd(ctx, fds, nfds);
+  return res;
+}
+#define INIT___PPOLL_CHK COMMON_INTERCEPT_FUNCTION(__ppoll_chk);
+#else
+#define INIT___PPOLL_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_WORDEXP
 INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) {
   void *ctx;
@@ -4236,6 +4565,21 @@ INTERCEPTOR(int, ttyname_r, int fd, char *name, SIZE_T namesize) {
 #define INIT_TTYNAME_R
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(int, __ttyname_r_chk, int fd, char *name, SIZE_T namesize,
+            SIZE_T namelen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __ttyname_r_chk, fd, name, namesize, namelen);
+  int res = REAL(ttyname_r)(fd, name, namesize);
+  if (res == 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, namelen + 1);
+  return res;
+}
+#define INIT___TTYNAME_R_CHK COMMON_INTERCEPT_FUNCTION(__ttyname_r_chk);
+#else
+#define INIT___TTYNAME_R_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_TEMPNAM
 INTERCEPTOR(char *, tempnam, char *dir, char *pfx) {
   void *ctx;
@@ -5771,6 +6115,45 @@ INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
 #define INIT_RECV_RECVFROM
 #endif
 
+#if SANITIZER_INTERCEPT_FORTIFY_SOURCE
+INTERCEPTOR(SSIZE_T, __recv_chk, int fd, void *buf, SIZE_T len, SIZE_T buflen,
+            int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __recv_chk, fd, buf, len, buflen, flags);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+  SSIZE_T res = REAL(recv)(fd, buf, len, flags);
+  if (res > 0) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
+  }
+  if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  return res;
+}
+
+INTERCEPTOR(SSIZE_T, __recvfrom_chk, int fd, void *buf, SIZE_T len,
+            SIZE_T buflen, int flags, void *srcaddr, int *addrlen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, __recvfrom_chk, fd, buf, len, buflen, flags,
+                           srcaddr, addrlen);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+  SIZE_T srcaddr_sz;
+  if (srcaddr) srcaddr_sz = *addrlen;
+  (void)srcaddr_sz;  // prevent "set but not used" warning
+  SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
+  if (res > 0) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
+    if (srcaddr)
+      COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr,
+                                          Min((SIZE_T)*addrlen, srcaddr_sz));
+  }
+  return res;
+}
+#define INIT___RECV_RECVFROM_CHK            \
+  COMMON_INTERCEPT_FUNCTION(__recv_chk);  \
+  COMMON_INTERCEPT_FUNCTION(__recvfrom_chk);
+#else
+#define INIT___RECV_RECVFROM_CHK
+#endif
+
 #if SANITIZER_INTERCEPT_SEND_SENDTO
 INTERCEPTOR(SSIZE_T, send, int fd, void *buf, SIZE_T len, int flags) {
   void *ctx;
@@ -6133,7 +6516,22 @@ static void InitializeCommonInterceptors() {
   INIT___XSTAT64;
   INIT___LXSTAT;
   INIT___LXSTAT64;
-  // FIXME: add other *stat interceptors.
+  INIT___READ_CHK;
+  INIT___POLL_CHK;
+  INIT___PPOLL_CHK;
+  INIT___RECV_RECVFROM_CHK;
+  INIT___PREAD_CHK;
+  INIT___PREAD64_CHK;
+  INIT___CONFSTR_CHK;
+  INIT___GETCWD_CHK;
+  INIT___GETGROUPS_CHK;
+  INIT___REALPATH_CHK;
+  INIT___MBSTOWCS_CHK;
+  INIT___MBSNRTOWCS_CHK;
+  INIT___WCSTOMBS_CHK;
+  INIT___WCSNRTOMBS_CHK;
+  INIT___WCRTOMB_CHK;
+  INIT___TTYNAME_R_CHK;
   INIT___PRINTF_CHK;
   INIT_MCHECK;
   INIT_MCHECK_PEDANTIC;
index 0ee5ec2..f165110 100644 (file)
 #define SANITIZER_INTERCEPT___PRINTF_CHK \
   (SANITIZER_INTERCEPT_PRINTF && SI_LINUX_NOT_ANDROID)
 
+#define SANITIZER_INTERCEPT_FORTIFY_SOURCE SI_LINUX_NOT_ANDROID
+
 #define SANITIZER_INTERCEPT_FREXP 1
 #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS