[sanitizer] Syscall hooks.

Pre- and post- hooks for linux syscalls. Not wired into anything, but exposed
through public interface.

llvm-svn: 179288
This commit is contained in:
Evgeniy Stepanov 2013-04-11 14:37:04 +00:00
parent 6728fc11bc
commit f5523116e9
5 changed files with 435 additions and 1 deletions

View File

@ -0,0 +1,275 @@
//===-- linux_syscall_hooks.h ---------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of public sanitizer interface.
//
// System call handlers.
//
// Interface methods declared in this header implement pre- and post- syscall
// actions for the active sanitizer.
// Usage:
// __sanitizer_syscall_pre_getfoo(...args...);
// int res = syscall(__NR_getfoo, ...args...);
// __sanitizer_syscall_post_getfoo(res, ...args...);
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_LINUX_SYSCALL_HOOKS_H
#define SANITIZER_LINUX_SYSCALL_HOOKS_H
#ifdef __cplusplus
extern "C" {
#endif
void __sanitizer_syscall_pre_rt_sigpending(void *p, size_t s);
void __sanitizer_syscall_pre_getdents(int fd, void *dirp, int count);
void __sanitizer_syscall_pre_getdents64(int fd, void *dirp, int count);
void __sanitizer_syscall_pre_recvmsg(int sockfd, void *msg, int flags);
void __sanitizer_syscall_post_rt_sigpending(int res, void *p, size_t s);
void __sanitizer_syscall_post_getdents(int res, int fd, void *dirp, int count);
void __sanitizer_syscall_post_getdents64(int res, int fd, void *dirp, int count);
void __sanitizer_syscall_post_recvmsg(int res, int sockfd, void *msg, int flags);
// And now a few syscalls we don't handle yet.
#define __sanitizer_syscall_pre__gettid()
#define __sanitizer_syscall_pre_fork()
#define __sanitizer_syscall_pre_getegid()
#define __sanitizer_syscall_pre_geteuid()
#define __sanitizer_syscall_pre_getpgrp()
#define __sanitizer_syscall_pre_getpid()
#define __sanitizer_syscall_pre_getppid()
#define __sanitizer_syscall_pre_sched_yield()
#define __sanitizer_syscall_pre_setsid()
#define __sanitizer_syscall_pre__exit(a)
#define __sanitizer_syscall_pre_brk(a)
#define __sanitizer_syscall_pre_chdir(a)
#define __sanitizer_syscall_pre_chroot(a)
#define __sanitizer_syscall_pre_close(a)
#define __sanitizer_syscall_pre_dup(a)
#define __sanitizer_syscall_pre_exit_group(a)
#define __sanitizer_syscall_pre_getsid(a)
#define __sanitizer_syscall_pre_io_destroy(a)
#define __sanitizer_syscall_pre_pipe(a)
#define __sanitizer_syscall_pre_rt_sigreturn(a)
#define __sanitizer_syscall_pre_set_tid_address(a)
#define __sanitizer_syscall_pre_setfsgid(a)
#define __sanitizer_syscall_pre_setfsuid(a)
#define __sanitizer_syscall_pre_setgid(a)
#define __sanitizer_syscall_pre_setuid(a)
#define __sanitizer_syscall_pre_umask(a)
#define __sanitizer_syscall_pre_unlink(a)
#define __sanitizer_syscall_pre_unshare(a)
#define __sanitizer_syscall_pre_arch_prctl(a, b)
#define __sanitizer_syscall_pre_capset(a, b)
#define __sanitizer_syscall_pre_clock_getres(a, b)
#define __sanitizer_syscall_pre_clock_gettime(a, b)
#define __sanitizer_syscall_pre_dup2(a, b)
#define __sanitizer_syscall_pre_fstat(a, b)
#define __sanitizer_syscall_pre_fstatfs(a, b)
#define __sanitizer_syscall_pre_ftruncate(a, b)
#define __sanitizer_syscall_pre_getpriority(a, b)
#define __sanitizer_syscall_pre_getrlimit(a, b)
#define __sanitizer_syscall_pre_gettimeofday(a, b)
#define __sanitizer_syscall_pre_io_setup(a, b)
#define __sanitizer_syscall_pre_ioprio_get(a, b)
#define __sanitizer_syscall_pre_kill(a, b)
#define __sanitizer_syscall_pre_munmap(a, b)
#define __sanitizer_syscall_pre_prctl(a, b)
#define __sanitizer_syscall_pre_rt_sigsuspend(a, b)
#define __sanitizer_syscall_pre_setgroups(a, b)
#define __sanitizer_syscall_pre_setns(a, b)
#define __sanitizer_syscall_pre_setpgid(a, b)
#define __sanitizer_syscall_pre_setrlimit(a, b)
#define __sanitizer_syscall_pre_shutdown(a, b)
#define __sanitizer_syscall_pre_sigaltstack(a, b)
#define __sanitizer_syscall_pre_stat(a, b)
#define __sanitizer_syscall_pre_statfs(a, b)
#define __sanitizer_syscall_pre_tkill(a, b)
#define __sanitizer_syscall_pre_execve(a, b, c)
#define __sanitizer_syscall_pre_fcntl(a, b, c)
#define __sanitizer_syscall_pre_getcpu(a, b, c)
#define __sanitizer_syscall_pre_getresgid(a, b, c)
#define __sanitizer_syscall_pre_getresuid(a, b, c)
#define __sanitizer_syscall_pre_io_cancel(a, b, c)
#define __sanitizer_syscall_pre_io_submit(a, b, c)
#define __sanitizer_syscall_pre_ioctl(a, b, c)
#define __sanitizer_syscall_pre_ioprio_set(a, b, c)
#define __sanitizer_syscall_pre_listxattr(a, b, c)
#define __sanitizer_syscall_pre_llistxattr(a, b, c)
#define __sanitizer_syscall_pre_lseek(a, b, c)
#define __sanitizer_syscall_pre_mprotect(a, b, c)
#define __sanitizer_syscall_pre_open(a, b, c)
#define __sanitizer_syscall_pre_poll(a, b, c)
#define __sanitizer_syscall_pre_read(a, b, c)
#define __sanitizer_syscall_pre_readahead(a, b, c)
#define __sanitizer_syscall_pre_readlink(a, b, c)
#define __sanitizer_syscall_pre_sched_getaffinity(a, b, c)
#define __sanitizer_syscall_pre_sched_setaffinity(a, b, c)
#define __sanitizer_syscall_pre_sendmsg(a, b, c)
#define __sanitizer_syscall_pre_setpriority(a, b, c)
#define __sanitizer_syscall_pre_setresgid(a, b, c)
#define __sanitizer_syscall_pre_setresuid(a, b, c)
#define __sanitizer_syscall_pre_socket(a, b, c)
#define __sanitizer_syscall_pre_tgkill(a, b, c)
#define __sanitizer_syscall_pre_unlinkat(a, b, c)
#define __sanitizer_syscall_pre_write(a, b, c)
#define __sanitizer_syscall_pre_writev(a, b, c)
#define __sanitizer_syscall_pre_fadvise64(a, b, c, d)
#define __sanitizer_syscall_pre_fallocate(a, b, c, d)
#define __sanitizer_syscall_pre_futex(a, b, c, d)
#define __sanitizer_syscall_pre_getxattr(a, b, c, d)
#define __sanitizer_syscall_pre_lgetxattr(a, b, c, d)
#define __sanitizer_syscall_pre_newfstatat(a, b, c, d)
#define __sanitizer_syscall_pre_openat(a, b, c, d)
#define __sanitizer_syscall_pre_pread64(a, b, c, d)
#define __sanitizer_syscall_pre_ptrace(a, b, c, d)
#define __sanitizer_syscall_pre_pwrite64(a, b, c, d)
#define __sanitizer_syscall_pre_quotactl(a, b, c, d)
#define __sanitizer_syscall_pre_rt_sigaction(a, b, c, d)
#define __sanitizer_syscall_pre_rt_sigprocmask(a, b, c, d)
#define __sanitizer_syscall_pre_socketpair(a, b, c, d)
#define __sanitizer_syscall_pre_wait4(a, b, c, d)
#define __sanitizer_syscall_pre__mremap(a, b, c, d, e)
#define __sanitizer_syscall_pre_io_getevents(a, b, c, d, e)
#define __sanitizer_syscall_pre_lsetxattr(a, b, c, d, e)
#define __sanitizer_syscall_pre_mount(a, b, c, d, e)
#define __sanitizer_syscall_pre_preadv(a, b, c, d, e)
#define __sanitizer_syscall_pre_pwritev(a, b, c, d, e)
#define __sanitizer_syscall_pre_setxattr(a, b, c, d, e)
#define __sanitizer_syscall_pre_mmap(a, b, c, d, e, f)
#define __sanitizer_syscall_pre_move_pages(a, b, c, d, e, f)
#define __sanitizer_syscall_pre_sendto(a, b, c, d, e, f)
#define __sanitizer_syscall_post__gettid(res)
#define __sanitizer_syscall_post_fork(res)
#define __sanitizer_syscall_post_getegid(res)
#define __sanitizer_syscall_post_geteuid(res)
#define __sanitizer_syscall_post_getpgrp(res)
#define __sanitizer_syscall_post_getpid(res)
#define __sanitizer_syscall_post_getppid(res)
#define __sanitizer_syscall_post_sched_yield(res)
#define __sanitizer_syscall_post_setsid(res)
#define __sanitizer_syscall_post__exit(res, a)
#define __sanitizer_syscall_post_brk(res, a)
#define __sanitizer_syscall_post_chdir(res, a)
#define __sanitizer_syscall_post_chroot(res, a)
#define __sanitizer_syscall_post_close(res, a)
#define __sanitizer_syscall_post_dup(res, a)
#define __sanitizer_syscall_post_exit_group(res, a)
#define __sanitizer_syscall_post_getsid(res, a)
#define __sanitizer_syscall_post_io_destroy(res, a)
#define __sanitizer_syscall_post_pipe(res, a)
#define __sanitizer_syscall_post_rt_sigreturn(res, a)
#define __sanitizer_syscall_post_set_tid_address(res, a)
#define __sanitizer_syscall_post_setfsgid(res, a)
#define __sanitizer_syscall_post_setfsuid(res, a)
#define __sanitizer_syscall_post_setgid(res, a)
#define __sanitizer_syscall_post_setuid(res, a)
#define __sanitizer_syscall_post_umask(res, a)
#define __sanitizer_syscall_post_unlink(res, a)
#define __sanitizer_syscall_post_unshare(res, a)
#define __sanitizer_syscall_post_arch_prctl(res, a, b)
#define __sanitizer_syscall_post_capset(res, a, b)
#define __sanitizer_syscall_post_clock_getres(res, a, b)
#define __sanitizer_syscall_post_clock_gettime(res, a, b)
#define __sanitizer_syscall_post_dup2(res, a, b)
#define __sanitizer_syscall_post_fstat(res, a, b)
#define __sanitizer_syscall_post_fstatfs(res, a, b)
#define __sanitizer_syscall_post_ftruncate(res, a, b)
#define __sanitizer_syscall_post_getpriority(res, a, b)
#define __sanitizer_syscall_post_getrlimit(res, a, b)
#define __sanitizer_syscall_post_gettimeofday(res, a, b)
#define __sanitizer_syscall_post_io_setup(res, a, b)
#define __sanitizer_syscall_post_ioprio_get(res, a, b)
#define __sanitizer_syscall_post_kill(res, a, b)
#define __sanitizer_syscall_post_munmap(res, a, b)
#define __sanitizer_syscall_post_prctl(res, a, b)
#define __sanitizer_syscall_post_rt_sigsuspend(res, a, b)
#define __sanitizer_syscall_post_setgroups(res, a, b)
#define __sanitizer_syscall_post_setns(res, a, b)
#define __sanitizer_syscall_post_setpgid(res, a, b)
#define __sanitizer_syscall_post_setrlimit(res, a, b)
#define __sanitizer_syscall_post_shutdown(res, a, b)
#define __sanitizer_syscall_post_sigaltstack(res, a, b)
#define __sanitizer_syscall_post_stat(res, a, b)
#define __sanitizer_syscall_post_statfs(res, a, b)
#define __sanitizer_syscall_post_tkill(res, a, b)
#define __sanitizer_syscall_post_execve(res, a, b, c)
#define __sanitizer_syscall_post_fcntl(res, a, b, c)
#define __sanitizer_syscall_post_getcpu(res, a, b, c)
#define __sanitizer_syscall_post_getresgid(res, a, b, c)
#define __sanitizer_syscall_post_getresuid(res, a, b, c)
#define __sanitizer_syscall_post_io_cancel(res, a, b, c)
#define __sanitizer_syscall_post_io_submit(res, a, b, c)
#define __sanitizer_syscall_post_ioctl(res, a, b, c)
#define __sanitizer_syscall_post_ioprio_set(res, a, b, c)
#define __sanitizer_syscall_post_listxattr(res, a, b, c)
#define __sanitizer_syscall_post_llistxattr(res, a, b, c)
#define __sanitizer_syscall_post_lseek(res, a, b, c)
#define __sanitizer_syscall_post_mprotect(res, a, b, c)
#define __sanitizer_syscall_post_open(res, a, b, c)
#define __sanitizer_syscall_post_poll(res, a, b, c)
#define __sanitizer_syscall_post_read(res, a, b, c)
#define __sanitizer_syscall_post_readahead(res, a, b, c)
#define __sanitizer_syscall_post_readlink(res, a, b, c)
#define __sanitizer_syscall_post_sched_getaffinity(res, a, b, c)
#define __sanitizer_syscall_post_sched_setaffinity(res, a, b, c)
#define __sanitizer_syscall_post_sendmsg(res, a, b, c)
#define __sanitizer_syscall_post_setpriority(res, a, b, c)
#define __sanitizer_syscall_post_setresgid(res, a, b, c)
#define __sanitizer_syscall_post_setresuid(res, a, b, c)
#define __sanitizer_syscall_post_socket(res, a, b, c)
#define __sanitizer_syscall_post_tgkill(res, a, b, c)
#define __sanitizer_syscall_post_unlinkat(res, a, b, c)
#define __sanitizer_syscall_post_write(res, a, b, c)
#define __sanitizer_syscall_post_writev(res, a, b, c)
#define __sanitizer_syscall_post_fadvise64(res, a, b, c, d)
#define __sanitizer_syscall_post_fallocate(res, a, b, c, d)
#define __sanitizer_syscall_post_futex(res, a, b, c, d)
#define __sanitizer_syscall_post_getxattr(res, a, b, c, d)
#define __sanitizer_syscall_post_lgetxattr(res, a, b, c, d)
#define __sanitizer_syscall_post_newfstatat(res, a, b, c, d)
#define __sanitizer_syscall_post_openat(res, a, b, c, d)
#define __sanitizer_syscall_post_pread64(res, a, b, c, d)
#define __sanitizer_syscall_post_ptrace(res, a, b, c, d)
#define __sanitizer_syscall_post_pwrite64(res, a, b, c, d)
#define __sanitizer_syscall_post_quotactl(res, a, b, c, d)
#define __sanitizer_syscall_post_rt_sigaction(res, a, b, c, d)
#define __sanitizer_syscall_post_rt_sigprocmask(res, a, b, c, d)
#define __sanitizer_syscall_post_socketpair(res, a, b, c, d)
#define __sanitizer_syscall_post_wait4(res, a, b, c, d)
#define __sanitizer_syscall_post__mremap(res, a, b, c, d, e)
#define __sanitizer_syscall_post_io_getevents(res, a, b, c, d, e)
#define __sanitizer_syscall_post_lsetxattr(res, a, b, c, d, e)
#define __sanitizer_syscall_post_mount(res, a, b, c, d, e)
#define __sanitizer_syscall_post_preadv(res, a, b, c, d, e)
#define __sanitizer_syscall_post_pwritev(res, a, b, c, d, e)
#define __sanitizer_syscall_post_setxattr(res, a, b, c, d, e)
#define __sanitizer_syscall_post_mmap(res, a, b, c, d, e, f)
#define __sanitizer_syscall_post_move_pages(res, a, b, c, d, e, f)
#define __sanitizer_syscall_post_sendto(res, a, b, c, d, e, f)
#ifdef __cplusplus
} // extern "C"
#endif
#endif // SANITIZER_LINUX_SYSCALL_HOOKS_H

View File

@ -0,0 +1,50 @@
// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t 2>&1
// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t 2>&1
#include <assert.h>
#include <errno.h>
#include <glob.h>
#include <stdio.h>
#include <string.h>
#include <sanitizer/linux_syscall_hooks.h>
#include <sanitizer/msan_interface.h>
/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
sanity of their behaviour. */
int main(int argc, char *argv[]) {
char buf[1000];
const int kTen = 10;
memset(buf, 0, sizeof(buf));
__msan_unpoison(buf, sizeof(buf));
__sanitizer_syscall_pre_recvmsg(0, buf, 0);
__sanitizer_syscall_pre_rt_sigpending(buf, kTen);
__sanitizer_syscall_pre_getdents(0, buf, kTen);
__sanitizer_syscall_pre_getdents64(0, buf, kTen);
__msan_unpoison(buf, sizeof(buf));
__sanitizer_syscall_post_recvmsg(0, 0, buf, 0);
__sanitizer_syscall_post_rt_sigpending(-1, buf, kTen);
__sanitizer_syscall_post_getdents(0, 0, buf, kTen);
__sanitizer_syscall_post_getdents64(0, 0, buf, kTen);
assert(__msan_test_shadow(buf, sizeof(buf)) == -1);
__msan_unpoison(buf, sizeof(buf));
__sanitizer_syscall_post_recvmsg(kTen, 0, buf, 0);
// Tell the kernel that the output struct size is 10 bytes, verify that those
// bytes are unpoisoned, and the next byte is not.
__msan_poison(buf, kTen + 1);
__sanitizer_syscall_post_rt_sigpending(0, buf, kTen);
assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
__msan_poison(buf, kTen + 1);
__sanitizer_syscall_post_getdents(kTen, 0, buf, kTen);
assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
__msan_poison(buf, kTen + 1);
__sanitizer_syscall_post_getdents64(kTen, 0, buf, kTen);
assert(__msan_test_shadow(buf, sizeof(buf)) == kTen);
return 0;
}

View File

@ -43,7 +43,7 @@ using namespace __msan;
do { \
sptr offset = __msan_test_shadow(x, n); \
if (__msan::IsInSymbolizer()) break; \
if (offset >= 0 && flags()->report_umrs) { \
if (offset >= 0 && __msan::flags()->report_umrs) { \
GET_CALLER_PC_BP_SP; \
(void)sp; \
Printf("UMR in %s at offset %d inside [%p, +%d) \n", \
@ -938,6 +938,12 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
do { } while (false) // FIXME
#include "sanitizer_common/sanitizer_common_interceptors.inc"
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)
#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
#define COMMON_SYSCALL_POST_READ_RANGE(p, s)
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
// static
void *fast_memset(void *ptr, int c, SIZE_T n) {
// hack until we have a really fast internal_memset

View File

@ -34,6 +34,7 @@ set(SANITIZER_HEADERS
sanitizer_common.h
sanitizer_common_interceptors.inc
sanitizer_common_interceptors_scanf.inc
sanitizer_common_syscalls.inc
sanitizer_flags.h
sanitizer_internal_defs.h
sanitizer_lfstack.h

View File

@ -0,0 +1,102 @@
//===-- sanitizer_common_syscalls.inc ---------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Common syscalls handlers for tools like AddressSanitizer,
// ThreadSanitizer, MemorySanitizer, etc.
//
// This file should be included into the tool's interceptor file,
// which has to define it's own macros:
// COMMON_SYSCALL_PRE_READ_RANGE
// Called in prehook for regions that will be read by the kernel and
// must be initialized.
// COMMON_SYSCALL_PRE_WRITE_RANGE
// Called in prehook for regions that will be written to by the kernel
// and must be addressable. The actual write range may be smaller than
// reported in the prehook. See POST_WRITE_RANGE.
// COMMON_SYSCALL_POST_READ_RANGE
// Called in posthook for regions that were read by the kernel. Does
// not make much sense.
// COMMON_SYSCALL_POST_WRITE_RANGE
// Called in posthook for regions that were written to by the kernel
// and are now initialized.
//===----------------------------------------------------------------------===//
#define PRE_SYSCALL(name) \
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_##name
#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)
#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
#define POST_SYSCALL(name) \
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_##name
#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)
#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
extern "C" {
struct sanitizer_kernel_iovec {
void *iov_base;
unsigned long iov_len;
};
struct sanitizer_kernel_msghdr {
void *msg_name;
int msg_namelen;
struct sanitizer_kernel_iovec *msg_iov;
unsigned long msg_iovlen;
void *msg_control;
unsigned long msg_controllen;
unsigned msg_flags;
};
PRE_SYSCALL(recvmsg)(int sockfd, struct sanitizer_kernel_msghdr *msg,
int flags) {
PRE_READ(msg, sizeof(*msg));
}
POST_SYSCALL(recvmsg)(int res, int sockfd, struct sanitizer_kernel_msghdr *msg,
int flags) {
if (res > 0)
for (unsigned long i = 0; i < msg->msg_iovlen; ++i)
POST_WRITE(msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
POST_WRITE(msg->msg_control, msg->msg_controllen);
}
PRE_SYSCALL(rt_sigpending)(void *p, unsigned long s) { PRE_WRITE(p, s); }
POST_SYSCALL(rt_sigpending)(int res, void *p, unsigned long s) {
if (res == 0)
POST_WRITE(p, s);
}
PRE_SYSCALL(getdents)(int fd, void *dirp, int count) { PRE_WRITE(dirp, count); }
POST_SYSCALL(getdents)(int res, int fd, void *dirp, int count) {
if (res > 0)
POST_WRITE(dirp, res);
}
PRE_SYSCALL(getdents64)(int fd, void *dirp, int count) {
PRE_WRITE(dirp, count);
}
POST_SYSCALL(getdents64)(int res, int fd, void *dirp, int count) {
if (res > 0)
POST_WRITE(dirp, res);
}
} // extern "C"
#undef PRE_SYSCALL
#undef PRE_READ
#undef PRE_WRITE
#undef POST_SYSCALL
#undef POST_READ
#undef POST_WRITE