Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions compiler-rt/lib/hwasan/hwasan_platform_interceptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
110 changes: 110 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 **,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
56 changes: 56 additions & 0 deletions compiler-rt/test/msan/scandirat.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
34 changes: 34 additions & 0 deletions compiler-rt/test/msan/scandirat_null.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
28 changes: 28 additions & 0 deletions compiler-rt/test/sanitizer_common/TestCases/scandirat.c
Original file line number Diff line number Diff line change
@@ -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;
}