diff options
author | Vitaly Buka <vitalybuka@google.com> | 2018-01-30 22:22:12 +0000 |
---|---|---|
committer | Vitaly Buka <vitalybuka@google.com> | 2018-01-30 22:22:12 +0000 |
commit | 4ec0d9c1b7e221524a834d9ddfb5f47b36e2ecb8 (patch) | |
tree | 702f90bf6e2f2b88c6ad281e76b3a2359b5671cd /compiler-rt | |
parent | 5d9844f48aeb3e32fa9526a69bbc36d61acee013 (diff) | |
download | bcm5719-llvm-4ec0d9c1b7e221524a834d9ddfb5f47b36e2ecb8.tar.gz bcm5719-llvm-4ec0d9c1b7e221524a834d9ddfb5f47b36e2ecb8.zip |
[sanitizer] Add interceptors for readlinkat, name_to_handle_at, open_by_handle_at
Summary:
Also move existing readlink msan interceptor to sanitizer_common.
Fixes google/sanitizers#908
Patch by Oliver Chang
Reviewers: vitalybuka, eugenis
Reviewed By: vitalybuka
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D42630
llvm-svn: 323825
Diffstat (limited to 'compiler-rt')
9 files changed, 221 insertions, 10 deletions
diff --git a/compiler-rt/lib/msan/msan_interceptors.cc b/compiler-rt/lib/msan/msan_interceptors.cc index 02b41efdaca..1084fa8f67c 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cc +++ b/compiler-rt/lib/msan/msan_interceptors.cc @@ -138,15 +138,6 @@ INTERCEPTOR(SIZE_T, fread_unlocked, void *ptr, SIZE_T size, SIZE_T nmemb, #define MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED #endif -INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) { - ENSURE_MSAN_INITED(); - CHECK_UNPOISONED_STRING(path, 0); - SSIZE_T res = REAL(readlink)(path, buf, bufsiz); - if (res > 0) - __msan_unpoison(buf, res); - return res; -} - #if !SANITIZER_NETBSD INTERCEPTOR(void *, mempcpy, void *dest, const void *src, SIZE_T n) { return (char *)__msan_memcpy(dest, src, n) + n; @@ -1587,7 +1578,6 @@ void InitializeInterceptors() { MSAN_MAYBE_INTERCEPT_MALLOC_STATS; INTERCEPT_FUNCTION(fread); MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED; - INTERCEPT_FUNCTION(readlink); INTERCEPT_FUNCTION(memccpy); MSAN_MAYBE_INTERCEPT_MEMPCPY; INTERCEPT_FUNCTION(bcopy); diff --git a/compiler-rt/lib/msan/tests/msan_test.cc b/compiler-rt/lib/msan/tests/msan_test.cc index 074a2f609ed..7a582c935b7 100644 --- a/compiler-rt/lib/msan/tests/msan_test.cc +++ b/compiler-rt/lib/msan/tests/msan_test.cc @@ -717,6 +717,13 @@ TEST(MemorySanitizer, readlink) { delete [] x; } +TEST(MemorySanitizer, readlinkat) { + char *x = new char[1000]; + readlinkat(AT_FDCWD, SYMLINK_TO_READ, x, 1000); + EXPECT_NOT_POISONED(x[0]); + delete[] x; +} + TEST(MemorySanitizer, stat) { struct stat* st = new struct stat; int res = stat(FILE_TO_READ, st); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 7aa95458007..14c486a9445 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -6632,6 +6632,98 @@ INTERCEPTOR(int, getgroupmembership, const char *name, u32 basegid, u32 *groups, #define INIT_GETGROUPLIST #endif +#if SANITIZER_INTERCEPT_READLINK +INTERCEPTOR(SSIZE_T, readlink, const char *path, char *buf, SIZE_T bufsiz) { + void* ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readlink, path, buf, bufsiz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + SSIZE_T res = REAL(readlink)(path, buf, bufsiz); + if (res > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res); + return res; +} + +#define INIT_READLINK COMMON_INTERCEPT_FUNCTION(readlink) +#else +#define INIT_READLINK +#endif + +#if SANITIZER_INTERCEPT_READLINKAT +INTERCEPTOR(SSIZE_T, readlinkat, int dirfd, const char *path, char *buf, + SIZE_T bufsiz) { + void* ctx; + COMMON_INTERCEPTOR_ENTER(ctx, readlinkat, dirfd, path, buf, bufsiz); + COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + SSIZE_T res = REAL(readlinkat)(dirfd, path, buf, bufsiz); + if (res > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res); + return res; +} + +#define INIT_READLINKAT COMMON_INTERCEPT_FUNCTION(readlinkat) +#else +#define INIT_READLINKAT +#endif + +#if SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT +INTERCEPTOR(int, name_to_handle_at, int dirfd, const char *pathname, + struct file_handle *handle, int *mount_id, int flags) { + void* ctx; + COMMON_INTERCEPTOR_ENTER(ctx, name_to_handle_at, dirfd, pathname, handle, + mount_id, flags); + COMMON_INTERCEPTOR_READ_RANGE(ctx, pathname, REAL(strlen)(pathname) + 1); + + __sanitizer_file_handle *sanitizer_handle = + reinterpret_cast<__sanitizer_file_handle*>(handle); + COMMON_INTERCEPTOR_READ_RANGE( + ctx, &sanitizer_handle->handle_bytes, + sizeof(sanitizer_handle->handle_bytes)); + + int res = REAL(name_to_handle_at)(dirfd, pathname, handle, mount_id, flags); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, &sanitizer_handle->handle_bytes, + sizeof(sanitizer_handle->handle_bytes)); + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, &sanitizer_handle->handle_type, + sizeof(sanitizer_handle->handle_type)); + COMMON_INTERCEPTOR_WRITE_RANGE( + ctx, &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mount_id, sizeof(*mount_id)); + } + return res; +} + +#define INIT_NAME_TO_HANDLE_AT COMMON_INTERCEPT_FUNCTION(name_to_handle_at) +#else +#define INIT_NAME_TO_HANDLE_AT +#endif + +#if SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT +INTERCEPTOR(int, open_by_handle_at, int mount_fd, struct file_handle* handle, + int flags) { + void* ctx; + COMMON_INTERCEPTOR_ENTER(ctx, open_by_handle_at, mount_fd, handle, flags); + + __sanitizer_file_handle *sanitizer_handle = + reinterpret_cast<__sanitizer_file_handle*>(handle); + COMMON_INTERCEPTOR_READ_RANGE( + ctx, &sanitizer_handle->handle_bytes, + sizeof(sanitizer_handle->handle_bytes)); + COMMON_INTERCEPTOR_READ_RANGE( + ctx, &sanitizer_handle->handle_type, + sizeof(sanitizer_handle->handle_type)); + COMMON_INTERCEPTOR_READ_RANGE( + ctx, &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes); + + return REAL(open_by_handle_at)(mount_fd, handle, flags); +} + +#define INIT_OPEN_BY_HANDLE_AT COMMON_INTERCEPT_FUNCTION(open_by_handle_at) +#else +#define INIT_OPEN_BY_HANDLE_AT +#endif + static void InitializeCommonInterceptors() { static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); @@ -6852,6 +6944,11 @@ static void InitializeCommonInterceptors() { INIT_ACCESS; INIT_FACCESSAT; INIT_GETGROUPLIST; + INIT_READLINK; + INIT_READLINKAT; + + INIT_NAME_TO_HANDLE_AT; + INIT_OPEN_BY_HANDLE_AT; #if SANITIZER_NETBSD COMMON_INTERCEPT_FUNCTION(__libc_mutex_lock); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index cb578624005..42641c0b347 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -442,4 +442,10 @@ #define SANITIZER_INTERCEPT_FACCESSAT SI_NETBSD #define SANITIZER_INTERCEPT_GETGROUPLIST SI_NETBSD +#define SANITIZER_INTERCEPT_NAME_TO_HANDLE_AT SI_LINUX +#define SANITIZER_INTERCEPT_OPEN_BY_HANDLE_AT SI_LINUX + +#define SANITIZER_INTERCEPT_READLINK SI_POSIX +#define SANITIZER_INTERCEPT_READLINKAT SI_POSIX + #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 9167b3cdef6..2ed8afb2801 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -460,6 +460,12 @@ namespace __sanitizer { int mnt_freq; int mnt_passno; }; + + struct __sanitizer_file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[1]; // variable sized + }; #endif #if SANITIZER_MAC || SANITIZER_FREEBSD diff --git a/compiler-rt/test/msan/Linux/name_to_handle_at.cc b/compiler-rt/test/msan/Linux/name_to_handle_at.cc new file mode 100644 index 00000000000..0ff8d982f4f --- /dev/null +++ b/compiler-rt/test/msan/Linux/name_to_handle_at.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t + +#include <assert.h> +#include <fcntl.h> +#include <sanitizer/msan_interface.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +int main(void) { + struct file_handle *handle = reinterpret_cast<struct file_handle *>( + malloc(sizeof(*handle) + MAX_HANDLE_SZ)); + handle->handle_bytes = MAX_HANDLE_SZ; + + int mount_id; + int res = name_to_handle_at(AT_FDCWD, "/bin/cat", handle, &mount_id, 0); + assert(!res); + __msan_check_mem_is_initialized(&mount_id, sizeof(mount_id)); + __msan_check_mem_is_initialized(&handle->handle_bytes, + sizeof(handle->handle_bytes)); + __msan_check_mem_is_initialized(&handle->handle_type, + sizeof(handle->handle_type)); + __msan_check_mem_is_initialized(&handle->f_handle, handle->handle_bytes); + + free(handle); + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/name_to_handle_at.cc b/compiler-rt/test/sanitizer_common/TestCases/Linux/name_to_handle_at.cc new file mode 100644 index 00000000000..79c807848c3 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/name_to_handle_at.cc @@ -0,0 +1,20 @@ +// RUN: %clangxx -O0 %s -o %t && %run %t + +#include <assert.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> + +int main(int argc, char **argv) { + int mount_id; + struct file_handle *handle = reinterpret_cast<struct file_handle *>( + malloc(sizeof(*handle) + MAX_HANDLE_SZ)); + + handle->handle_bytes = MAX_HANDLE_SZ; + int res = name_to_handle_at(AT_FDCWD, argv[0], handle, &mount_id, 0); + assert(!res); + + free(handle); + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/readlinkat.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/readlinkat.c new file mode 100644 index 00000000000..9368f986a4e --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/readlinkat.c @@ -0,0 +1,25 @@ +// RUN: %clang -O0 %s -o %t && %run %t + +#include <assert.h> +#include <fcntl.h> +#include <linux/limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +int main(int argc, char **argv) { + char symlink_path[PATH_MAX]; + snprintf(symlink_path, sizeof(symlink_path), "%s_%d.symlink", argv[0], + getpid()); + int res = symlink(argv[0], symlink_path); + assert(!res); + + char readlinkat_path[PATH_MAX]; + int res2 = readlinkat(AT_FDCWD, symlink_path, readlinkat_path, + sizeof(readlinkat_path)); + assert(res2 >= 0); + readlinkat_path[res2] = '\0'; + assert(!strcmp(readlinkat_path, argv[0])); + + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/readlink.c b/compiler-rt/test/sanitizer_common/TestCases/Posix/readlink.c new file mode 100644 index 00000000000..d9f39e699a7 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/readlink.c @@ -0,0 +1,32 @@ +// RUN: %clang -O0 %s -o %t && %run %t + +#include <assert.h> +#include <fcntl.h> +#include <linux/limits.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +int main(int argc, char **argv) { + char symlink_path[PATH_MAX]; + snprintf(symlink_path, sizeof(symlink_path), "%s_%d.symlink", argv[0], + getpid()); + int res = symlink(argv[0], symlink_path); + assert(!res); + + char readlink_path[PATH_MAX]; + ssize_t res2 = readlink(symlink_path, readlink_path, sizeof(readlink_path)); + assert(res2 >= 0); + readlink_path[res2] = '\0'; + assert(!strcmp(readlink_path, argv[0])); + + char readlinkat_path[PATH_MAX]; + res2 = readlinkat(AT_FDCWD, symlink_path, readlinkat_path, + sizeof(readlink_path)); + assert(res2 >= 0); + readlinkat_path[res2] = '\0'; + assert(!strcmp(readlinkat_path, argv[0])); + + return 0; +} |