diff options
-rw-r--r-- | lib/esan/esan_interceptors.cpp | 14 | ||||
-rw-r--r-- | lib/msan/msan_interceptors.cc | 8 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_common_interceptors.inc | 33 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_interceptors.h | 3 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_interceptors.cc | 18 | ||||
-rw-r--r-- | test/asan/TestCases/Posix/fread_fwrite.cc | 34 | ||||
-rw-r--r-- | test/msan/fread_fwrite.cc | 34 |
7 files changed, 104 insertions, 40 deletions
diff --git a/lib/esan/esan_interceptors.cpp b/lib/esan/esan_interceptors.cpp index 9ae5482a3..9740f4dae 100644 --- a/lib/esan/esan_interceptors.cpp +++ b/lib/esan/esan_interceptors.cpp @@ -304,20 +304,6 @@ INTERCEPTOR(int, unlink, char *path) { return REAL(unlink)(path); } -INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, f); - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size * nmemb); - return REAL(fread)(ptr, size, nmemb, f); -} - -INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, f); - COMMON_INTERCEPTOR_READ_RANGE(ctx, p, size * nmemb); - return REAL(fwrite)(p, size, nmemb, f); -} - INTERCEPTOR(int, puts, const char *s) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, puts, s); diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index f3d5f4a09..15543bd91 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -123,14 +123,6 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) { #define CHECK_UNPOISONED_STRING(x, n) \ CHECK_UNPOISONED_STRING_OF_LEN((x), internal_strlen(x), (n)) -INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { - ENSURE_MSAN_INITED(); - SIZE_T res = REAL(fread)(ptr, size, nmemb, file); - if (res > 0) - __msan_unpoison(ptr, res *size); - return res; -} - #if !SANITIZER_FREEBSD INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index b4148621d..7ecde2294 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -888,6 +888,23 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { #define INIT_READ #endif +#if SANITIZER_INTERCEPT_FREAD +INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) { + // libc file streams can call user-supplied functions, see fopencookie. + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, file); + // 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(fread)(ptr, size, nmemb, file); + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res * size); + return res; +} +#define INIT_FREAD COMMON_INTERCEPT_FUNCTION(fread) +#else +#define INIT_FREAD +#endif + #if SANITIZER_INTERCEPT_PREAD INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { void *ctx; @@ -988,6 +1005,20 @@ INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) { #define INIT_WRITE #endif +#if SANITIZER_INTERCEPT_FWRITE +INTERCEPTOR(SIZE_T, fwrite, const void *p, uptr size, uptr nmemb, void *file) { + // libc file streams can call user-supplied functions, see fopencookie. + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, file); + SIZE_T res = REAL(fwrite)(p, size, nmemb, file); + if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, p, res * size); + return res; +} +#define INIT_FWRITE COMMON_INTERCEPT_FUNCTION(fwrite) +#else +#define INIT_FWRITE +#endif + #if SANITIZER_INTERCEPT_PWRITE INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) { void *ctx; @@ -6142,12 +6173,14 @@ static void InitializeCommonInterceptors() { INIT_MEMRCHR; INIT_MEMMEM; INIT_READ; + INIT_FREAD; INIT_PREAD; INIT_PREAD64; INIT_READV; INIT_PREADV; INIT_PREADV64; INIT_WRITE; + INIT_FWRITE; INIT_PWRITE; INIT_PWRITE64; INIT_WRITEV; diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index e56557530..a583e989c 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -104,6 +104,9 @@ #define SANITIZER_INTERCEPT_WRITE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FREAD SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_FWRITE SI_NOT_WINDOWS + #define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 17a914371..bb2badbff 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -1648,24 +1648,6 @@ TSAN_INTERCEPTOR(void*, tmpfile64, int fake) { #define TSAN_MAYBE_INTERCEPT_TMPFILE64 #endif -TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) { - // libc file streams can call user-supplied functions, see fopencookie. - { - SCOPED_TSAN_INTERCEPTOR(fread, ptr, size, nmemb, f); - MemoryAccessRange(thr, pc, (uptr)ptr, size * nmemb, true); - } - return REAL(fread)(ptr, size, nmemb, f); -} - -TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) { - // libc file streams can call user-supplied functions, see fopencookie. - { - SCOPED_TSAN_INTERCEPTOR(fwrite, p, size, nmemb, f); - MemoryAccessRange(thr, pc, (uptr)p, size * nmemb, false); - } - return REAL(fwrite)(p, size, nmemb, f); -} - static void FlushStreams() { // Flushing all the streams here may freeze the process if a child thread is // performing file stream operations at the same time. diff --git a/test/asan/TestCases/Posix/fread_fwrite.cc b/test/asan/TestCases/Posix/fread_fwrite.cc new file mode 100644 index 000000000..97d44b752 --- /dev/null +++ b/test/asan/TestCases/Posix/fread_fwrite.cc @@ -0,0 +1,34 @@ +// RUN: %clangxx_asan -g %s -o %t +// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FWRITE +// RUN: not %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FREAD + +#include <stdio.h> +#include <stdlib.h> + +int test_fread() { + FILE *f = fopen("/dev/zero", "r"); + char buf[2]; + fread(buf, sizeof(buf), 2, f); // BOOM + fclose(f); + return 0; +} + +int test_fwrite() { + FILE *f = fopen("/dev/null", "w"); + char buf[2]; + fwrite(buf, sizeof(buf), 2, f); // BOOM + return fclose(f); +} + +int main(int argc, char *argv[]) { + if (argc > 1) + test_fread(); + else + test_fwrite(); + return 0; +} + +// CHECK-FREAD: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}} +// CHECK-FREAD: #{{.*}} in {{(wrap_|__interceptor_)?}}fread +// CHECK-FWRITE: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}} +// CHECK-FWRITE: #{{.*}} in {{(wrap_|__interceptor_)?}}fwrite diff --git a/test/msan/fread_fwrite.cc b/test/msan/fread_fwrite.cc new file mode 100644 index 000000000..3d500342a --- /dev/null +++ b/test/msan/fread_fwrite.cc @@ -0,0 +1,34 @@ +// RUN: %clangxx_msan -g %s -o %t +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %t 1 + +#include <stdio.h> +#include <stdlib.h> + +int test_fread() { + FILE *f = fopen("/dev/zero", "r"); + char c; + unsigned read = fread(&c, sizeof(c), 1, f); + fclose(f); + if (c == '1') // No error + return 1; + return 0; +} + +int test_fwrite() { + FILE *f = fopen("/dev/null", "w"); + char c; + if (fwrite(&c, sizeof(c), 1, f) != sizeof(c)) // BOOM + return 1; + return fclose(f); +} + +int main(int argc, char *argv[]) { + if (argc > 1) + test_fread(); + else + test_fwrite(); + return 0; +} + +// CHECK: Uninitialized bytes in __interceptor_fwrite at offset 0 inside |