Index: lib/msan/msan_interceptors.cc =================================================================== --- lib/msan/msan_interceptors.cc +++ lib/msan/msan_interceptors.cc @@ -147,6 +147,16 @@ return res; } +INTERCEPTOR(SSIZE_T, readlinkat, int dirfd, const char *path, char *buf, + SIZE_T bufsiz) { + ENSURE_MSAN_INITED(); + CHECK_UNPOISONED_STRING(path, 0); + SSIZE_T res = REAL(readlinkat)(dirfd, 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; @@ -1028,6 +1038,32 @@ return res; } +#if SANITIZER_LINUX +INTERCEPTOR(int, name_to_handle_at, int dirfd, const char *pathname, + struct file_handle *handle, int *mount_id, int flags) { + ENSURE_MSAN_INITED(); + int res = REAL(name_to_handle_at)(dirfd, pathname, handle, mount_id, flags); + __sanitizer_file_handle *sanitizer_handle = + reinterpret_cast<__sanitizer_file_handle*>(handle); + if (!res) { + __msan_unpoison( + &sanitizer_handle->handle_bytes, + sizeof(sanitizer_handle->handle_bytes)); + __msan_unpoison( + &sanitizer_handle->handle_type, sizeof(sanitizer_handle->handle_type)); + __msan_unpoison( + &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes); + __msan_unpoison(mount_id, sizeof(*mount_id)); + } + return errno; +} + +#define MSAN_MAYBE_INTERCEPT_NAME_TO_HANDLE_AT \ + INTERCEPT_FUNCTION(name_to_handle_at) +#else +#define MSAN_MAYBE_INTERCEPT_NAME_TO_HANDLE_AT +#endif + class SignalHandlerScope { public: SignalHandlerScope() { @@ -1588,6 +1624,7 @@ INTERCEPT_FUNCTION(fread); MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED; INTERCEPT_FUNCTION(readlink); + INTERCEPT_FUNCTION(readlinkat); INTERCEPT_FUNCTION(memccpy); MSAN_MAYBE_INTERCEPT_MEMPCPY; INTERCEPT_FUNCTION(bcopy); @@ -1687,6 +1724,7 @@ INTERCEPT_FUNCTION(fork); INTERCEPT_FUNCTION(openpty); INTERCEPT_FUNCTION(forkpty); + MSAN_MAYBE_INTERCEPT_NAME_TO_HANDLE_AT; inited = 1; } Index: lib/msan/tests/msan_test.cc =================================================================== --- lib/msan/tests/msan_test.cc +++ lib/msan/tests/msan_test.cc @@ -717,6 +717,13 @@ 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); Index: lib/sanitizer_common/sanitizer_platform_limits_linux.cc =================================================================== --- lib/sanitizer_common/sanitizer_platform_limits_linux.cc +++ lib/sanitizer_common/sanitizer_platform_limits_linux.cc @@ -56,6 +56,8 @@ #include #endif +#include + using namespace __sanitizer; namespace __sanitizer { @@ -106,4 +108,9 @@ CHECK_SIZE_AND_OFFSET(iocb, aio_nbytes); CHECK_SIZE_AND_OFFSET(iocb, aio_offset); +CHECK_SIZE_AND_OFFSET(file_handle, handle_bytes); +CHECK_SIZE_AND_OFFSET(file_handle, handle_type); +COMPILER_CHECK(offsetof(__sanitizer_file_handle, f_handle) == + offsetof(struct file_handle, f_handle)); + #endif // SANITIZER_LINUX Index: lib/sanitizer_common/sanitizer_platform_limits_posix.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -460,6 +460,12 @@ int mnt_freq; int mnt_passno; }; + + struct __sanitizer_file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[]; + }; #endif #if SANITIZER_MAC || SANITIZER_FREEBSD Index: test/msan/name_to_handle_at.cc =================================================================== --- /dev/null +++ test/msan/name_to_handle_at.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_msan -std=c++11 -O0 -g %s -o %t && %run %t +// REQUIRES: x86_64-linux + +#include +#include +#include + +#include +#include +#include + +int main(void) { + struct file_handle* handle = reinterpret_cast( + 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); + return 0; +}