forked from OSchip/llvm-project
[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
This commit is contained in:
parent
5d9844f48a
commit
4ec0d9c1b7
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue