[compiler-rt] r185998 - Fix a bug in the readdir_r interceptor: when we reach the end of the

Chandler Carruth chandlerc at gmail.com
Wed Jul 10 02:50:30 PDT 2013


Author: chandlerc
Date: Wed Jul 10 04:50:29 2013
New Revision: 185998

URL: http://llvm.org/viewvc/llvm-project?rev=185998&view=rev
Log:
Fix a bug in the readdir_r interceptor: when we reach the end of the
directory stream, the entry is not written to, instead *result is set to
NULL and the entry is not written to at all.

I'm still somewhat suspicious of the correct instrumention here --
I feel like it should be marking the written range as the pointer in
*result and the length (*result)->d_reclen in case the implementation
decides not to use the passed-in entry (if that's even allowed).
Finally, the definition of 'struct dirent' analog used in the
interceptor is wrong in 32-bit mode with _FILE_OFFSET_BITS=64 as it hard
codes the use of a pointer-sized offset.

I've added a somewhat goofy test for the bug I fixed via ASan --
suggestions on how to better test the interceptor logic itself welcome.

Added:
    compiler-rt/trunk/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
Modified:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc

Added: compiler-rt/trunk/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc?rev=185998&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc (added)
+++ compiler-rt/trunk/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc Wed Jul 10 04:50:29 2013
@@ -0,0 +1,30 @@
+// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+
+
+int main() {
+  // Ensure the readdir_r interceptor doesn't erroneously mark the entire dirent
+  // as written when the end of the directory pointer is reached.
+  fputs("reading the " TEMP_DIR " directory...\n", stderr);
+  DIR *d = opendir(TEMP_DIR);
+  struct dirent entry, *result;
+  unsigned count = 0;
+  do {
+    // Stamp the entry struct to try to trick the interceptor.
+    entry.d_reclen = 9999;
+    if (readdir_r(d, &entry, &result) != 0)
+      abort();
+    ++count;
+  } while (result != NULL);
+  fprintf(stderr, "read %d entries\n", count);
+  // CHECK: reading the {{.*}} directory...
+  // CHECK-NOT: stack-buffer-overflow
+  // CHECK: read {{.*}} entries
+}

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc?rev=185998&r1=185997&r2=185998&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc Wed Jul 10 04:50:29 2013
@@ -1374,7 +1374,7 @@ INTERCEPTOR(int, readdir_r, void *dirp,
   if (!res) {
     if (result)
       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result));
-    if (entry)
+    if (entry && *result)
       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, entry, entry->d_reclen);
   }
   return res;





More information about the llvm-commits mailing list