-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[sanitizer] Intercept scandirat/scandirat64 #163924
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-compiler-rt-sanitizer Author: None (alxchk) ChangesFixes #163923 Full diff: https://github.com/llvm/llvm-project/pull/163924.diff 6 Files Affected:
diff --git a/compiler-rt/lib/hwasan/hwasan_platform_interceptors.h b/compiler-rt/lib/hwasan/hwasan_platform_interceptors.h
index 8a653d83dec65..71bbad2d38f3b 100644
--- a/compiler-rt/lib/hwasan/hwasan_platform_interceptors.h
+++ b/compiler-rt/lib/hwasan/hwasan_platform_interceptors.h
@@ -389,9 +389,15 @@
#undef SANITIZER_INTERCEPT_SCANDIR
#define SANITIZER_INTERCEPT_SCANDIR 0
+#undef SANITIZER_INTERCEPT_SCANDIRAT
+#define SANITIZER_INTERCEPT_SCANDIRAT 0
+
#undef SANITIZER_INTERCEPT_SCANDIR64
#define SANITIZER_INTERCEPT_SCANDIR64 0
+#undef SANITIZER_INTERCEPT_SCANDIRAT64
+#define SANITIZER_INTERCEPT_SCANDIRAT64 0
+
#undef SANITIZER_INTERCEPT_GETGROUPS
#define SANITIZER_INTERCEPT_GETGROUPS 0
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index b10ce7fa44afc..0d1455e124f1b 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -106,6 +106,7 @@
#define readdir __readdir30
#define readdir_r __readdir_r30
#define scandir __scandir30
+#define scandirat __scandirat30
#define setitimer __setitimer50
#define setlocale __setlocale50
#define shmctl __shmctl50
@@ -4227,6 +4228,59 @@ INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist,
#define INIT_SCANDIR
#endif
+#if SANITIZER_INTERCEPT_SCANDIRAT
+typedef int (*scandirat_filter_f)(const struct __sanitizer_dirent *);
+typedef int (*scandirat_compar_f)(const struct __sanitizer_dirent **,
+ const struct __sanitizer_dirent **);
+
+static THREADLOCAL scandirat_filter_f scandirat_filter;
+static THREADLOCAL scandirat_compar_f scandirat_compar;
+
+static int wrapped_scandirat_filter(const struct __sanitizer_dirent *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, __sanitizer_dirsiz(dir));
+ return scandirat_filter(dir);
+}
+
+static int wrapped_scandirat_compar(const struct __sanitizer_dirent **a,
+ const struct __sanitizer_dirent **b) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, __sanitizer_dirsiz(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, __sanitizer_dirsiz(*b));
+ return scandirat_compar(a, b);
+}
+
+INTERCEPTOR(int, scandirat, int dirfd, char *dirp, __sanitizer_dirent ***namelist,
+ scandirat_filter_f filter, scandirat_compar_f compar) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, scandirat, dirfd, dirp, namelist, filter, compar);
+ if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, internal_strlen(dirp) + 1);
+ scandirat_filter = filter;
+ scandirat_compar = compar;
+ // 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(scandirat)(dirfd, dirp, namelist,
+ filter ? wrapped_scandirat_filter : nullptr,
+ compar ? wrapped_scandirat_compar : nullptr);
+ scandirat_filter = nullptr;
+ scandirat_compar = nullptr;
+ if (namelist && res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
+ for (int i = 0; i < res; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i],
+ __sanitizer_dirsiz((*namelist)[i]));
+ }
+ return res;
+}
+#define INIT_SCANDIRAT COMMON_INTERCEPT_FUNCTION(scandirat);
+#else
+#define INIT_SCANDIRAT
+#endif
+
#if SANITIZER_INTERCEPT_SCANDIR64
typedef int (*scandir64_filter_f)(const struct __sanitizer_dirent64 *);
typedef int (*scandir64_compar_f)(const struct __sanitizer_dirent64 **,
@@ -4281,6 +4335,60 @@ INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist,
#define INIT_SCANDIR64
#endif
+#if SANITIZER_INTERCEPT_SCANDIRAT64
+typedef int (*scandirat64_filter_f)(const struct __sanitizer_dirent64 *);
+typedef int (*scandirat64_compar_f)(const struct __sanitizer_dirent64 **,
+ const struct __sanitizer_dirent64 **);
+
+static THREADLOCAL scandirat64_filter_f scandirat64_filter;
+static THREADLOCAL scandirat64_compar_f scandirat64_compar;
+
+static int wrapped_scandirat64_filter(const struct __sanitizer_dirent64 *dir) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(1);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(dir, __sanitizer_dirsiz(dir));
+ return scandirat64_filter(dir);
+}
+
+static int wrapped_scandirat64_compar(const struct __sanitizer_dirent64 **a,
+ const struct __sanitizer_dirent64 **b) {
+ COMMON_INTERCEPTOR_UNPOISON_PARAM(2);
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, sizeof(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*a, __sanitizer_dirsiz(*a));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, sizeof(*b));
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(*b, __sanitizer_dirsiz(*b));
+ return scandirat64_compar(a, b);
+}
+
+INTERCEPTOR(int, scandirat64, int dirfd, char *dirp, __sanitizer_dirent64 ***namelist,
+ scandirat64_filter_f filter, scandirat64_compar_f compar) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, scandirat64, dirfd, dirp, namelist, filter, compar);
+ if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, internal_strlen(dirp) + 1);
+ scandirat64_filter = filter;
+ scandirat64_compar = compar;
+ // 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(scandirat64)(dirfd, dirp, namelist,
+ filter ? wrapped_scandirat64_filter : nullptr,
+ compar ? wrapped_scandirat64_compar : nullptr);
+ scandirat64_filter = nullptr;
+ scandirat64_compar = nullptr;
+ if (namelist && res > 0) {
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res);
+ for (int i = 0; i < res; ++i)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (*namelist)[i],
+ __sanitizer_dirsiz((*namelist)[i]));
+ }
+ return res;
+}
+#define INIT_SCANDIRAT64 COMMON_INTERCEPT_FUNCTION(scandirat64);
+#else
+#define INIT_SCANDIRAT64
+#endif
+
#if SANITIZER_INTERCEPT_GETGROUPS
INTERCEPTOR(int, getgroups, int size, u32 *lst) {
void *ctx;
@@ -10526,7 +10634,9 @@ static void InitializeCommonInterceptors() {
INIT_STRERROR_R;
INIT_XPG_STRERROR_R;
INIT_SCANDIR;
+ INIT_SCANDIRAT;
INIT_SCANDIR64;
+ INIT_SCANDIRAT64;
INIT_GETGROUPS;
INIT_POLL;
INIT_PPOLL;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 88ecd7e16306a..dfe518609c673 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -356,7 +356,9 @@ SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
#define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SCANDIR \
(SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+#define SANITIZER_INTERCEPT_SCANDIRAT SI_GLIBC
#define SANITIZER_INTERCEPT_SCANDIR64 SI_GLIBC || SI_SOLARIS32
+#define SANITIZER_INTERCEPT_SCANDIRAT64 SI_GLIBC
#define SANITIZER_INTERCEPT_GETGROUPS SI_POSIX
#define SANITIZER_INTERCEPT_POLL SI_POSIX
#define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID || SI_SOLARIS
diff --git a/compiler-rt/test/msan/scandirat.cpp b/compiler-rt/test/msan/scandirat.cpp
new file mode 100644
index 0000000000000..d538de1057b04
--- /dev/null
+++ b/compiler-rt/test/msan/scandirat.cpp
@@ -0,0 +1,56 @@
+// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+
+static int my_filter(const struct dirent *a) {
+ assert(__msan_test_shadow(&a, sizeof(a)) == (size_t)-1);
+ printf("%s\n", a->d_name);
+ __msan_print_shadow(a, a->d_reclen);
+ assert(__msan_test_shadow(a, a->d_reclen) == (size_t)-1);
+ printf("%s\n", a->d_name);
+ return strlen(a->d_name) == 3 && a->d_name[2] == 'b';
+}
+
+static int my_compar(const struct dirent **a, const struct dirent **b) {
+ assert(__msan_test_shadow(a, sizeof(*a)) == (size_t)-1);
+ assert(__msan_test_shadow(*a, (*a)->d_reclen) == (size_t)-1);
+ assert(__msan_test_shadow(b, sizeof(*b)) == (size_t)-1);
+ assert(__msan_test_shadow(*b, (*b)->d_reclen) == (size_t)-1);
+ if ((*a)->d_name[1] == (*b)->d_name[1])
+ return 0;
+ return ((*a)->d_name[1] < (*b)->d_name[1]) ? 1 : -1;
+}
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "scandir_test_root/");
+
+ struct dirent **d;
+ int res = scandirat(AT_FDCWD, buf, &d, my_filter, my_compar);
+ assert(res == 2);
+ assert(__msan_test_shadow(&d, sizeof(*d)) == (size_t)-1);
+ for (int i = 0; i < res; ++i) {
+ assert(__msan_test_shadow(&d[i], sizeof(d[i])) == (size_t)-1);
+ assert(__msan_test_shadow(d[i], d[i]->d_reclen) == (size_t)-1);
+ }
+
+ assert(strcmp(d[0]->d_name, "bbb") == 0);
+ assert(strcmp(d[1]->d_name, "aab") == 0);
+ return 0;
+}
diff --git a/compiler-rt/test/msan/scandirat_null.cpp b/compiler-rt/test/msan/scandirat_null.cpp
new file mode 100644
index 0000000000000..ced2041417347
--- /dev/null
+++ b/compiler-rt/test/msan/scandirat_null.cpp
@@ -0,0 +1,34 @@
+// RUN: %clangxx_msan -O0 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p
+// RUN: %clangxx_msan -O3 %s -o %t && %run %t %p
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <sanitizer/msan_interface.h>
+
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ char buf[1024];
+ snprintf(buf, sizeof(buf), "%s/%s", argv[1], "scandir_test_root/");
+
+ struct dirent **d;
+ int res = scandirat(AT_FDCWD, buf, &d, NULL, NULL);
+ assert(res >= 3);
+ assert(__msan_test_shadow(&d, sizeof(*d)) == (size_t)-1);
+ for (int i = 0; i < res; ++i) {
+ assert(__msan_test_shadow(&d[i], sizeof(d[i])) == (size_t)-1);
+ assert(__msan_test_shadow(d[i], d[i]->d_reclen) == (size_t)-1);
+ }
+ return 0;
+}
diff --git a/compiler-rt/test/sanitizer_common/TestCases/scandirat.c b/compiler-rt/test/sanitizer_common/TestCases/scandirat.c
new file mode 100644
index 0000000000000..6d889cfe212be
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/scandirat.c
@@ -0,0 +1,28 @@
+// REQUIRES: (linux && !android) || freebsd
+
+// RUN: rm -rf %t-dir
+// RUN: mkdir -p %t-dir
+// RUN: touch %t-dir/a %t-dir/b %t-dir/c
+
+// RUN: %clang %s -DTEMP_DIR='"'"%t-dir"'"' -o %t && %run %t 2>&1
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ struct dirent **dirpp = NULL;
+ int count = scandir(AT_FDCWD, TEMP_DIR, &dirpp, NULL, NULL);
+ fprintf(stderr, "count is %d\n", count);
+ if (count >= 0) {
+ for (int i = 0; i < count; ++i) {
+ fprintf(stderr, "found %s\n", dirpp[i]->d_name);
+ free(dirpp[i]);
+ }
+ free(dirpp);
+ }
+ return 0;
+}
|
Fixes #163923