2019-02-27 15:44:03 +00:00
|
|
|
//===-- hwasan_interceptors.cpp -------------------------------------------===//
|
2017-12-09 01:31:51 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-12-09 01:31:51 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file is a part of HWAddressSanitizer.
|
|
|
|
//
|
|
|
|
// Interceptors for standard library functions.
|
|
|
|
//
|
|
|
|
// FIXME: move as many interceptors as possible into
|
|
|
|
// sanitizer_common/sanitizer_common_interceptors.h
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
[compiler-rt] Avoid memintrinsic calls inserted by the compiler
D135716 introduced -ftrivial-auto-var-init=pattern where supported.
Unfortunately this introduces unwanted memset() for large stack arrays,
as shown by the new tests added for asan and msan (tsan already had this
test).
In general, the problem of compiler-inserted memintrinsic calls
(memset/memcpy/memmove) is not new to compiler-rt, and has been a
problem before.
To avoid introducing unwanted memintrinsic calls, we redefine
memintrinsics as __sanitizer_internal_mem* at the assembly level for
most source files automatically (where sanitizer_common_internal_defs.h
is included).
In few cases, redefining a symbol in this way causes issues for
interceptors, namely the memintrinsic interceptor themselves. For such
source files we have to selectively disable the redefinition.
Other alternatives have been considered, but simply do not work well in
the context of compiler-rt:
1. Linker --wrap: this does not work because --wrap only
applies to the final link, and would not apply when building
sanitizer static libraries.
2. Changing references to memset() via objcopy: this may work,
but due to the complexities of the build system, introducing
such a post-processing step for the right object files (in
particular object files defining memset cannot be touched)
seems infeasible.
The chosen solution works well (as shown by the tests). Other libraries
have chosen the same solution where nothing else works (see e.g. glibc's
"symbol-hacks.h").
v4:
- Add interface attribute to __sanitizer_internal_mem* declarations as
well, as otherwise some compilers (MSVC) will complain.
- Add SANITIZER_COMMON_NO_REDEFINE_BUILTINS to source files using
C++STL, since this could lead to ODR violations (see added comment).
v3:
- Don't use ALIAS() to alias internal_mem*() functions to
__sanitizer_internal_mem*() functions, but just define them as
ALWAYS_INLINE functions instead. This will work on darwin and windows.
v2:
- Fix ubsan_minimal build where compiler decides to insert
memset/memcpy: ubsan_minimal has work without RTSanitizerCommonLibc,
therefore do not redefine the builtins.
- Fix definition of internal_mem* functions with compilers that want the
aliased function to already be defined before.
- Fix definition of __sanitizer_internal_mem* functions with compilers
more pedantic about attribute placement around extern "C".
Reviewed By: vitalybuka, dvyukov
Differential Revision: https://reviews.llvm.org/D151152
2023-05-30 11:59:22 +02:00
|
|
|
#define SANITIZER_COMMON_NO_REDEFINE_BUILTINS
|
|
|
|
|
2017-12-09 01:31:51 +00:00
|
|
|
#include "hwasan.h"
|
2023-05-25 20:37:11 +00:00
|
|
|
#include "hwasan_allocator.h"
|
2023-04-27 22:05:46 +00:00
|
|
|
#include "hwasan_checks.h"
|
2023-11-07 00:01:04 -08:00
|
|
|
#include "hwasan_mapping.h"
|
2023-05-19 23:19:44 +00:00
|
|
|
#include "hwasan_platform_interceptors.h"
|
2017-12-09 01:31:51 +00:00
|
|
|
#include "hwasan_thread.h"
|
2023-05-08 16:18:32 -07:00
|
|
|
#include "hwasan_thread_list.h"
|
2023-04-24 19:25:45 +00:00
|
|
|
#include "interception/interception.h"
|
2023-05-25 20:37:11 +00:00
|
|
|
#include "sanitizer_common/sanitizer_errno.h"
|
2023-04-24 19:25:45 +00:00
|
|
|
#include "sanitizer_common/sanitizer_linux.h"
|
2017-12-09 01:31:51 +00:00
|
|
|
#include "sanitizer_common/sanitizer_stackdepot.h"
|
|
|
|
|
2021-06-07 15:35:28 -07:00
|
|
|
#if !SANITIZER_FUCHSIA
|
2017-12-09 01:31:51 +00:00
|
|
|
|
|
|
|
using namespace __hwasan;
|
|
|
|
|
2023-09-29 16:14:48 -07:00
|
|
|
struct HWAsanInterceptorContext {
|
|
|
|
const char *interceptor_name;
|
|
|
|
};
|
|
|
|
|
2023-12-04 15:00:08 -08:00
|
|
|
# define ACCESS_MEMORY_RANGE(offset, size, access) \
|
|
|
|
do { \
|
|
|
|
__hwasan::CheckAddressSized<ErrorAction::Recover, access>((uptr)offset, \
|
|
|
|
size); \
|
2023-09-29 16:14:48 -07:00
|
|
|
} while (0)
|
|
|
|
|
2023-12-02 16:39:46 -08:00
|
|
|
# define HWASAN_READ_RANGE(offset, size) \
|
|
|
|
ACCESS_MEMORY_RANGE(offset, size, AccessType::Load)
|
|
|
|
# define HWASAN_WRITE_RANGE(offset, size) \
|
|
|
|
ACCESS_MEMORY_RANGE(offset, size, AccessType::Store)
|
2023-09-29 16:14:48 -07:00
|
|
|
|
2023-05-25 20:37:11 +00:00
|
|
|
# if !SANITIZER_APPLE
|
|
|
|
# define HWASAN_INTERCEPT_FUNC(name) \
|
|
|
|
do { \
|
|
|
|
if (!INTERCEPT_FUNCTION(name)) \
|
|
|
|
VReport(1, "HWAddressSanitizer: failed to intercept '%s'\n", #name); \
|
|
|
|
} while (0)
|
|
|
|
# define HWASAN_INTERCEPT_FUNC_VER(name, ver) \
|
|
|
|
do { \
|
|
|
|
if (!INTERCEPT_FUNCTION_VER(name, ver)) \
|
|
|
|
VReport(1, "HWAddressSanitizer: failed to intercept '%s@@%s'\n", \
|
|
|
|
#name, ver); \
|
|
|
|
} while (0)
|
|
|
|
# define HWASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \
|
|
|
|
do { \
|
|
|
|
if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \
|
|
|
|
VReport( \
|
|
|
|
1, "HWAddressSanitizer: failed to intercept '%s@@%s' or '%s'\n", \
|
|
|
|
#name, ver, #name); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
# else
|
|
|
|
// OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION.
|
|
|
|
# define HWASAN_INTERCEPT_FUNC(name)
|
|
|
|
# endif // SANITIZER_APPLE
|
|
|
|
|
2023-05-08 15:03:22 -07:00
|
|
|
# if HWASAN_WITH_INTERCEPTORS
|
2018-09-06 22:53:08 +00:00
|
|
|
|
2023-12-04 15:00:08 -08:00
|
|
|
# define COMMON_SYSCALL_PRE_READ_RANGE(p, s) HWASAN_READ_RANGE(p, s)
|
|
|
|
# define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) HWASAN_WRITE_RANGE(p, s)
|
2023-04-27 22:05:46 +00:00
|
|
|
# define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
|
|
|
|
do { \
|
|
|
|
(void)(p); \
|
|
|
|
(void)(s); \
|
|
|
|
} while (false)
|
|
|
|
# define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
|
|
|
|
do { \
|
|
|
|
(void)(p); \
|
|
|
|
(void)(s); \
|
|
|
|
} while (false)
|
|
|
|
# include "sanitizer_common/sanitizer_common_syscalls.inc"
|
|
|
|
# include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
|
|
|
|
|
2023-05-25 20:37:11 +00:00
|
|
|
# define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
|
2023-12-02 16:39:46 -08:00
|
|
|
HWASAN_WRITE_RANGE(ptr, size)
|
2023-05-25 20:37:11 +00:00
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
|
2023-12-02 16:39:46 -08:00
|
|
|
HWASAN_READ_RANGE(ptr, size)
|
2023-05-25 20:37:11 +00:00
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
|
2023-09-29 16:14:48 -07:00
|
|
|
HWAsanInterceptorContext _ctx = {#func}; \
|
|
|
|
ctx = (void *)&_ctx; \
|
2023-05-25 20:37:11 +00:00
|
|
|
do { \
|
|
|
|
(void)(ctx); \
|
|
|
|
(void)(func); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
|
|
|
|
do { \
|
|
|
|
(void)(ctx); \
|
|
|
|
(void)(path); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
|
|
|
|
do { \
|
|
|
|
(void)(ctx); \
|
|
|
|
(void)(fd); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
|
|
|
|
do { \
|
|
|
|
(void)(ctx); \
|
|
|
|
(void)(fd); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
|
|
|
|
do { \
|
|
|
|
(void)(ctx); \
|
|
|
|
(void)(fd); \
|
|
|
|
(void)(newfd); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
|
|
|
|
do { \
|
|
|
|
(void)(ctx); \
|
|
|
|
(void)(name); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
|
|
|
|
do { \
|
|
|
|
(void)(ctx); \
|
|
|
|
(void)(thread); \
|
|
|
|
(void)(name); \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_BLOCK_REAL(name) \
|
|
|
|
do { \
|
|
|
|
(void)(name); \
|
|
|
|
} while (false)
|
|
|
|
|
2023-11-07 00:01:04 -08:00
|
|
|
# define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \
|
|
|
|
{ \
|
|
|
|
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \
|
|
|
|
return internal_memset(dst, v, size); \
|
|
|
|
COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \
|
|
|
|
if (MemIsApp(UntagAddr(reinterpret_cast<uptr>(dst))) && \
|
|
|
|
common_flags()->intercept_intrin) \
|
|
|
|
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
|
|
|
|
return REAL(memset)(dst, v, size); \
|
|
|
|
}
|
2023-10-30 21:09:21 -07:00
|
|
|
|
2023-05-25 20:37:11 +00:00
|
|
|
# define COMMON_INTERCEPTOR_STRERROR() \
|
|
|
|
do { \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
# define COMMON_INTERCEPT_FUNCTION(name) HWASAN_INTERCEPT_FUNC(name)
|
|
|
|
|
|
|
|
# define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!hwasan_inited)
|
|
|
|
|
|
|
|
// The main purpose of the mmap interceptor is to prevent the user from
|
|
|
|
// allocating on top of shadow pages.
|
|
|
|
//
|
|
|
|
// For compatibility, it does not tag pointers, nor does it allow
|
|
|
|
// MAP_FIXED in combination with a tagged pointer. (Since mmap itself
|
|
|
|
// will not return a tagged pointer, the tagged pointer must have come
|
|
|
|
// from elsewhere, such as the secondary allocator, which makes it a
|
|
|
|
// very odd usecase.)
|
|
|
|
template <class Mmap>
|
|
|
|
static void *mmap_interceptor(Mmap real_mmap, void *addr, SIZE_T length,
|
|
|
|
int prot, int flags, int fd, OFF64_T offset) {
|
|
|
|
if (addr) {
|
|
|
|
if (flags & map_fixed) CHECK_EQ(addr, UntagPtr(addr));
|
|
|
|
|
|
|
|
addr = UntagPtr(addr);
|
|
|
|
}
|
|
|
|
SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
|
|
|
|
void *end_addr = (char *)addr + (rounded_length - 1);
|
2023-06-14 15:22:32 -07:00
|
|
|
if (addr && length &&
|
|
|
|
(!MemIsApp(reinterpret_cast<uptr>(addr)) ||
|
|
|
|
!MemIsApp(reinterpret_cast<uptr>(end_addr)))) {
|
2023-05-25 20:37:11 +00:00
|
|
|
// User requested an address that is incompatible with HWASan's
|
|
|
|
// memory layout. Use a different address if allowed, else fail.
|
|
|
|
if (flags & map_fixed) {
|
|
|
|
errno = errno_EINVAL;
|
|
|
|
return (void *)-1;
|
|
|
|
} else {
|
|
|
|
addr = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void *res = real_mmap(addr, length, prot, flags, fd, offset);
|
2023-06-14 15:22:32 -07:00
|
|
|
if (length && res != (void *)-1) {
|
|
|
|
uptr beg = reinterpret_cast<uptr>(res);
|
|
|
|
DCHECK(IsAligned(beg, GetPageSize()));
|
|
|
|
if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
|
2023-05-25 20:37:11 +00:00
|
|
|
// Application has attempted to map more memory than is supported by
|
|
|
|
// HWASan. Act as if we ran out of memory.
|
|
|
|
internal_munmap(res, length);
|
|
|
|
errno = errno_ENOMEM;
|
|
|
|
return (void *)-1;
|
|
|
|
}
|
2023-06-14 15:22:32 -07:00
|
|
|
__hwasan::TagMemoryAligned(beg, rounded_length, 0);
|
2023-05-25 20:37:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-06-10 00:16:48 +00:00
|
|
|
template <class Munmap>
|
|
|
|
static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {
|
2023-06-14 15:22:32 -07:00
|
|
|
// We should not tag if munmap fail, but it's to late to tag after
|
|
|
|
// real_munmap, as the pages could be mmaped by another thread.
|
|
|
|
uptr beg = reinterpret_cast<uptr>(addr);
|
|
|
|
if (length && IsAligned(beg, GetPageSize())) {
|
|
|
|
SIZE_T rounded_length = RoundUpTo(length, GetPageSize());
|
|
|
|
// Protect from unmapping the shadow.
|
|
|
|
if (!MemIsApp(beg) || !MemIsApp(beg + rounded_length - 1)) {
|
|
|
|
errno = errno_EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
__hwasan::TagMemoryAligned(beg, rounded_length, 0);
|
|
|
|
}
|
2023-06-10 00:16:48 +00:00
|
|
|
return real_munmap(addr, length);
|
|
|
|
}
|
|
|
|
|
2023-05-25 20:37:11 +00:00
|
|
|
# define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, length, prot, flags, \
|
|
|
|
fd, offset) \
|
|
|
|
do { \
|
|
|
|
(void)(ctx); \
|
|
|
|
return mmap_interceptor(REAL(mmap), addr, sz, prot, flags, fd, off); \
|
|
|
|
} while (false)
|
|
|
|
|
2023-06-15 22:59:37 +00:00
|
|
|
# define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, length) \
|
|
|
|
do { \
|
|
|
|
(void)(ctx); \
|
|
|
|
return munmap_interceptor(REAL(munmap), addr, sz); \
|
2023-06-10 00:16:48 +00:00
|
|
|
} while (false)
|
|
|
|
|
2023-05-30 11:59:16 +02:00
|
|
|
# include "sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc"
|
2023-05-25 20:37:11 +00:00
|
|
|
# include "sanitizer_common/sanitizer_common_interceptors.inc"
|
2023-05-19 23:19:44 +00:00
|
|
|
|
2023-05-08 15:15:15 -07:00
|
|
|
struct ThreadStartArg {
|
|
|
|
__sanitizer_sigset_t starting_sigset_;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void *HwasanThreadStartFunc(void *arg) {
|
|
|
|
__hwasan_thread_enter();
|
2023-05-29 23:49:46 -07:00
|
|
|
SetSigProcMask(&reinterpret_cast<ThreadStartArg *>(arg)->starting_sigset_,
|
|
|
|
nullptr);
|
2023-05-08 15:24:33 -07:00
|
|
|
InternalFree(arg);
|
2023-05-08 16:18:32 -07:00
|
|
|
auto self = GetThreadSelf();
|
|
|
|
auto args = hwasanThreadArgRetval().GetArgs(self);
|
|
|
|
void *retval = (*args.routine)(args.arg_retval);
|
|
|
|
hwasanThreadArgRetval().Finish(self, retval);
|
|
|
|
return retval;
|
2023-05-08 15:15:15 -07:00
|
|
|
}
|
|
|
|
|
2023-05-08 16:18:32 -07:00
|
|
|
extern "C" {
|
|
|
|
int pthread_attr_getdetachstate(void *attr, int *v);
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(int, pthread_create, void *thread, void *attr,
|
2023-05-08 15:03:22 -07:00
|
|
|
void *(*callback)(void *), void *param) {
|
2023-02-02 01:32:16 +00:00
|
|
|
EnsureMainThreadIDIsCorrect();
|
2023-02-08 22:52:28 +00:00
|
|
|
ScopedTaggingDisabler tagging_disabler;
|
2023-05-18 00:53:53 -07:00
|
|
|
bool detached = [attr]() {
|
|
|
|
int d = 0;
|
|
|
|
return attr && !pthread_attr_getdetachstate(attr, &d) && IsStateDetached(d);
|
|
|
|
}();
|
2023-05-08 15:24:33 -07:00
|
|
|
ThreadStartArg *A = (ThreadStartArg *)InternalAlloc(sizeof(ThreadStartArg));
|
2023-04-24 19:25:45 +00:00
|
|
|
ScopedBlockSignals block(&A->starting_sigset_);
|
|
|
|
// ASAN uses the same approach to disable leaks from pthread_create.
|
2023-02-08 22:52:28 +00:00
|
|
|
# if CAN_SANITIZE_LEAKS
|
2023-04-24 19:25:45 +00:00
|
|
|
__lsan::ScopedInterceptorDisabler lsan_disabler;
|
2023-02-08 22:52:28 +00:00
|
|
|
# endif
|
2023-05-08 16:18:32 -07:00
|
|
|
|
|
|
|
int result;
|
|
|
|
hwasanThreadArgRetval().Create(detached, {callback, param}, [&]() -> uptr {
|
|
|
|
result = REAL(pthread_create)(thread, attr, &HwasanThreadStartFunc, A);
|
|
|
|
return result ? 0 : *(uptr *)(thread);
|
|
|
|
});
|
2023-05-08 15:24:33 -07:00
|
|
|
if (result != 0)
|
|
|
|
InternalFree(A);
|
|
|
|
return result;
|
2019-01-04 23:24:02 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 16:18:32 -07:00
|
|
|
INTERCEPTOR(int, pthread_join, void *thread, void **retval) {
|
|
|
|
int result;
|
|
|
|
hwasanThreadArgRetval().Join((uptr)thread, [&]() {
|
|
|
|
result = REAL(pthread_join)(thread, retval);
|
|
|
|
return !result;
|
|
|
|
});
|
|
|
|
return result;
|
2021-12-01 23:52:31 -08:00
|
|
|
}
|
|
|
|
|
2023-05-07 16:12:04 -07:00
|
|
|
INTERCEPTOR(int, pthread_detach, void *thread) {
|
2023-05-08 16:18:32 -07:00
|
|
|
int result;
|
|
|
|
hwasanThreadArgRetval().Detach((uptr)thread, [&]() {
|
|
|
|
result = REAL(pthread_detach)(thread);
|
|
|
|
return !result;
|
|
|
|
});
|
|
|
|
return result;
|
2023-05-07 16:12:04 -07:00
|
|
|
}
|
|
|
|
|
2023-11-05 22:41:37 -08:00
|
|
|
INTERCEPTOR(void, pthread_exit, void *retval) {
|
2023-05-12 10:05:46 -07:00
|
|
|
hwasanThreadArgRetval().Finish(GetThreadSelf(), retval);
|
2023-11-05 22:41:37 -08:00
|
|
|
REAL(pthread_exit)(retval);
|
2023-05-07 16:12:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
# if SANITIZER_GLIBC
|
|
|
|
INTERCEPTOR(int, pthread_tryjoin_np, void *thread, void **ret) {
|
2023-05-08 16:18:32 -07:00
|
|
|
int result;
|
|
|
|
hwasanThreadArgRetval().Join((uptr)thread, [&]() {
|
|
|
|
result = REAL(pthread_tryjoin_np)(thread, ret);
|
|
|
|
return !result;
|
|
|
|
});
|
|
|
|
return result;
|
2023-05-07 16:12:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
|
|
|
|
const struct timespec *abstime) {
|
2023-05-08 16:18:32 -07:00
|
|
|
int result;
|
|
|
|
hwasanThreadArgRetval().Join((uptr)thread, [&]() {
|
|
|
|
result = REAL(pthread_timedjoin_np)(thread, ret, abstime);
|
|
|
|
return !result;
|
|
|
|
});
|
|
|
|
return result;
|
2023-05-07 16:12:04 -07:00
|
|
|
}
|
|
|
|
# endif
|
|
|
|
|
2024-06-25 09:42:01 -07:00
|
|
|
DEFINE_INTERNAL_PTHREAD_FUNCTIONS
|
2021-12-01 23:52:31 -08:00
|
|
|
|
2024-03-26 08:42:47 +09:00
|
|
|
DEFINE_REAL(int, vfork,)
|
|
|
|
DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,)
|
[hwasan, asan] Intercept vfork.
Summary:
Intercept vfork on arm, aarch64, i386 and x86_64.
Reviewers: pcc, vitalybuka
Subscribers: kubamracek, mgorny, javed.absar, krytarowski, kristof.beyls, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58533
llvm-svn: 355030
2019-02-27 21:11:50 +00:00
|
|
|
|
2019-10-30 14:04:40 +00:00
|
|
|
// Get and/or change the set of blocked signals.
|
|
|
|
extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set,
|
|
|
|
__hw_sigset_t *__restrict __oset);
|
2023-05-08 15:03:22 -07:00
|
|
|
# define SIG_BLOCK 0
|
|
|
|
# define SIG_SETMASK 2
|
2019-10-30 14:04:40 +00:00
|
|
|
extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) {
|
2021-09-15 07:53:25 -07:00
|
|
|
env[0].__magic = kHwJmpBufMagic;
|
2019-10-30 14:04:40 +00:00
|
|
|
env[0].__mask_was_saved =
|
2023-05-08 15:03:22 -07:00
|
|
|
(savemask &&
|
|
|
|
sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0, &env[0].__saved_mask) == 0);
|
2019-10-30 14:04:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __attribute__((always_inline))
|
|
|
|
InternalLongjmp(__hw_register_buf env, int retval) {
|
2021-09-17 07:08:57 -07:00
|
|
|
# if defined(__aarch64__)
|
|
|
|
constexpr size_t kSpIndex = 13;
|
|
|
|
# elif defined(__x86_64__)
|
|
|
|
constexpr size_t kSpIndex = 6;
|
2022-07-31 13:38:36 +03:00
|
|
|
# elif SANITIZER_RISCV64
|
|
|
|
constexpr size_t kSpIndex = 13;
|
2021-09-17 07:08:57 -07:00
|
|
|
# endif
|
|
|
|
|
2019-10-30 14:04:40 +00:00
|
|
|
// Clear all memory tags on the stack between here and where we're going.
|
2021-09-17 07:08:57 -07:00
|
|
|
unsigned long long stack_pointer = env[kSpIndex];
|
2019-10-30 14:04:40 +00:00
|
|
|
// The stack pointer should never be tagged, so we don't need to clear the
|
|
|
|
// tag for this function call.
|
|
|
|
__hwasan_handle_longjmp((void *)stack_pointer);
|
|
|
|
|
|
|
|
// Run code for handling a longjmp.
|
|
|
|
// Need to use a register that isn't going to be loaded from the environment
|
|
|
|
// buffer -- hence why we need to specify the register to use.
|
|
|
|
// Must implement this ourselves, since we don't know the order of registers
|
|
|
|
// in different libc implementations and many implementations mangle the
|
|
|
|
// stack pointer so we can't use it without knowing the demangling scheme.
|
2021-09-17 07:08:57 -07:00
|
|
|
# if defined(__aarch64__)
|
2019-10-30 14:04:40 +00:00
|
|
|
register long int retval_tmp asm("x1") = retval;
|
|
|
|
register void *env_address asm("x0") = &env[0];
|
2023-05-08 15:03:22 -07:00
|
|
|
asm volatile(
|
|
|
|
"ldp x19, x20, [%0, #0<<3];"
|
|
|
|
"ldp x21, x22, [%0, #2<<3];"
|
|
|
|
"ldp x23, x24, [%0, #4<<3];"
|
|
|
|
"ldp x25, x26, [%0, #6<<3];"
|
|
|
|
"ldp x27, x28, [%0, #8<<3];"
|
|
|
|
"ldp x29, x30, [%0, #10<<3];"
|
|
|
|
"ldp d8, d9, [%0, #14<<3];"
|
|
|
|
"ldp d10, d11, [%0, #16<<3];"
|
|
|
|
"ldp d12, d13, [%0, #18<<3];"
|
|
|
|
"ldp d14, d15, [%0, #20<<3];"
|
|
|
|
"ldr x5, [%0, #13<<3];"
|
|
|
|
"mov sp, x5;"
|
|
|
|
// Return the value requested to return through arguments.
|
|
|
|
// This should be in x1 given what we requested above.
|
|
|
|
"cmp %1, #0;"
|
|
|
|
"mov x0, #1;"
|
|
|
|
"csel x0, %1, x0, ne;"
|
|
|
|
"br x30;"
|
|
|
|
: "+r"(env_address)
|
|
|
|
: "r"(retval_tmp));
|
2021-09-17 07:08:57 -07:00
|
|
|
# elif defined(__x86_64__)
|
|
|
|
register long int retval_tmp asm("%rsi") = retval;
|
|
|
|
register void *env_address asm("%rdi") = &env[0];
|
|
|
|
asm volatile(
|
|
|
|
// Restore registers.
|
|
|
|
"mov (0*8)(%0),%%rbx;"
|
|
|
|
"mov (1*8)(%0),%%rbp;"
|
|
|
|
"mov (2*8)(%0),%%r12;"
|
|
|
|
"mov (3*8)(%0),%%r13;"
|
|
|
|
"mov (4*8)(%0),%%r14;"
|
|
|
|
"mov (5*8)(%0),%%r15;"
|
|
|
|
"mov (6*8)(%0),%%rsp;"
|
|
|
|
"mov (7*8)(%0),%%rdx;"
|
|
|
|
// Return 1 if retval is 0.
|
|
|
|
"mov $1,%%rax;"
|
|
|
|
"test %1,%1;"
|
|
|
|
"cmovnz %1,%%rax;"
|
|
|
|
"jmp *%%rdx;" ::"r"(env_address),
|
|
|
|
"r"(retval_tmp));
|
2022-07-31 13:38:36 +03:00
|
|
|
# elif SANITIZER_RISCV64
|
|
|
|
register long int retval_tmp asm("x11") = retval;
|
|
|
|
register void *env_address asm("x10") = &env[0];
|
|
|
|
asm volatile(
|
|
|
|
"ld ra, 0<<3(%0);"
|
|
|
|
"ld s0, 1<<3(%0);"
|
|
|
|
"ld s1, 2<<3(%0);"
|
|
|
|
"ld s2, 3<<3(%0);"
|
|
|
|
"ld s3, 4<<3(%0);"
|
|
|
|
"ld s4, 5<<3(%0);"
|
|
|
|
"ld s5, 6<<3(%0);"
|
|
|
|
"ld s6, 7<<3(%0);"
|
|
|
|
"ld s7, 8<<3(%0);"
|
|
|
|
"ld s8, 9<<3(%0);"
|
|
|
|
"ld s9, 10<<3(%0);"
|
|
|
|
"ld s10, 11<<3(%0);"
|
|
|
|
"ld s11, 12<<3(%0);"
|
|
|
|
# if __riscv_float_abi_double
|
|
|
|
"fld fs0, 14<<3(%0);"
|
|
|
|
"fld fs1, 15<<3(%0);"
|
|
|
|
"fld fs2, 16<<3(%0);"
|
|
|
|
"fld fs3, 17<<3(%0);"
|
|
|
|
"fld fs4, 18<<3(%0);"
|
|
|
|
"fld fs5, 19<<3(%0);"
|
|
|
|
"fld fs6, 20<<3(%0);"
|
|
|
|
"fld fs7, 21<<3(%0);"
|
|
|
|
"fld fs8, 22<<3(%0);"
|
|
|
|
"fld fs9, 23<<3(%0);"
|
|
|
|
"fld fs10, 24<<3(%0);"
|
|
|
|
"fld fs11, 25<<3(%0);"
|
|
|
|
# elif __riscv_float_abi_soft
|
|
|
|
# else
|
|
|
|
# error "Unsupported case"
|
|
|
|
# endif
|
|
|
|
"ld a4, 13<<3(%0);"
|
|
|
|
"mv sp, a4;"
|
|
|
|
// Return the value requested to return through arguments.
|
|
|
|
// This should be in x11 given what we requested above.
|
|
|
|
"seqz a0, %1;"
|
|
|
|
"add a0, a0, %1;"
|
|
|
|
"ret;"
|
|
|
|
: "+r"(env_address)
|
|
|
|
: "r"(retval_tmp));
|
2021-09-17 07:08:57 -07:00
|
|
|
# endif
|
2019-10-30 14:04:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) {
|
2021-09-15 07:53:25 -07:00
|
|
|
if (env[0].__magic != kHwJmpBufMagic) {
|
|
|
|
Printf(
|
|
|
|
"WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
|
2021-09-15 09:06:01 -07:00
|
|
|
"there is a bug in HWASan.\n");
|
2021-09-15 07:53:25 -07:00
|
|
|
return REAL(siglongjmp)(env, val);
|
|
|
|
}
|
|
|
|
|
2019-10-30 14:04:40 +00:00
|
|
|
if (env[0].__mask_was_saved)
|
|
|
|
// Restore the saved signal mask.
|
2023-05-08 15:03:22 -07:00
|
|
|
(void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask, (__hw_sigset_t *)0);
|
2019-10-30 14:04:40 +00:00
|
|
|
InternalLongjmp(env[0].__jmpbuf, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Required since glibc libpthread calls __libc_longjmp on pthread_exit, and
|
|
|
|
// _setjmp on start_thread. Hence we have to intercept the longjmp on
|
|
|
|
// pthread_exit so the __hw_jmp_buf order matches.
|
|
|
|
INTERCEPTOR(void, __libc_longjmp, __hw_jmp_buf env, int val) {
|
2021-09-15 07:53:25 -07:00
|
|
|
if (env[0].__magic != kHwJmpBufMagic)
|
|
|
|
return REAL(__libc_longjmp)(env, val);
|
2019-10-30 14:04:40 +00:00
|
|
|
InternalLongjmp(env[0].__jmpbuf, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) {
|
2021-09-15 07:53:25 -07:00
|
|
|
if (env[0].__magic != kHwJmpBufMagic) {
|
|
|
|
Printf(
|
|
|
|
"WARNING: Unexpected bad jmp_buf. Either setjmp was not called or "
|
2021-09-15 09:06:01 -07:00
|
|
|
"there is a bug in HWASan.\n");
|
2021-09-15 07:53:25 -07:00
|
|
|
return REAL(longjmp)(env, val);
|
|
|
|
}
|
2019-10-30 14:04:40 +00:00
|
|
|
InternalLongjmp(env[0].__jmpbuf, val);
|
|
|
|
}
|
2023-05-08 15:03:22 -07:00
|
|
|
# undef SIG_BLOCK
|
|
|
|
# undef SIG_SETMASK
|
2019-10-30 14:04:40 +00:00
|
|
|
|
2021-09-17 07:08:57 -07:00
|
|
|
# endif // HWASAN_WITH_INTERCEPTORS
|
2019-10-30 14:04:40 +00:00
|
|
|
|
2017-12-09 01:31:51 +00:00
|
|
|
namespace __hwasan {
|
|
|
|
|
|
|
|
int OnExit() {
|
2022-12-21 22:31:40 +00:00
|
|
|
if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
|
|
|
|
__lsan::HasReportedLeaks()) {
|
|
|
|
return common_flags()->exitcode;
|
|
|
|
}
|
2017-12-09 01:31:51 +00:00
|
|
|
// FIXME: ask frontend whether we need to return failure.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-05-08 15:03:22 -07:00
|
|
|
} // namespace __hwasan
|
2017-12-09 01:31:51 +00:00
|
|
|
|
|
|
|
namespace __hwasan {
|
|
|
|
|
|
|
|
void InitializeInterceptors() {
|
|
|
|
static int inited = 0;
|
|
|
|
CHECK_EQ(inited, 0);
|
|
|
|
|
2023-08-16 20:50:16 +00:00
|
|
|
# if HWASAN_WITH_INTERCEPTORS
|
2024-03-12 23:09:36 -07:00
|
|
|
__interception::DoesNotSupportStaticLinking();
|
2023-05-25 20:37:11 +00:00
|
|
|
InitializeCommonInterceptors();
|
|
|
|
|
2023-05-19 23:19:44 +00:00
|
|
|
(void)(read_iovec);
|
|
|
|
(void)(write_iovec);
|
|
|
|
|
2023-05-06 14:57:45 -07:00
|
|
|
# if defined(__linux__)
|
2021-09-15 07:53:25 -07:00
|
|
|
INTERCEPT_FUNCTION(__libc_longjmp);
|
|
|
|
INTERCEPT_FUNCTION(longjmp);
|
|
|
|
INTERCEPT_FUNCTION(siglongjmp);
|
[hwasan, asan] Intercept vfork.
Summary:
Intercept vfork on arm, aarch64, i386 and x86_64.
Reviewers: pcc, vitalybuka
Subscribers: kubamracek, mgorny, javed.absar, krytarowski, kristof.beyls, #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D58533
llvm-svn: 355030
2019-02-27 21:11:50 +00:00
|
|
|
INTERCEPT_FUNCTION(vfork);
|
2023-05-06 14:57:45 -07:00
|
|
|
# endif // __linux__
|
2019-01-04 23:24:02 +00:00
|
|
|
INTERCEPT_FUNCTION(pthread_create);
|
2021-12-01 23:52:31 -08:00
|
|
|
INTERCEPT_FUNCTION(pthread_join);
|
2023-05-07 16:12:04 -07:00
|
|
|
INTERCEPT_FUNCTION(pthread_detach);
|
|
|
|
INTERCEPT_FUNCTION(pthread_exit);
|
|
|
|
# if SANITIZER_GLIBC
|
|
|
|
INTERCEPT_FUNCTION(pthread_tryjoin_np);
|
|
|
|
INTERCEPT_FUNCTION(pthread_timedjoin_np);
|
|
|
|
# endif
|
2021-12-01 23:52:31 -08:00
|
|
|
# endif
|
[hwasan] Add a (almost) no-interceptor mode.
Summary:
The idea behind this change is to allow sanitization of libc. We are prototyping on Bionic,
but the tool interface will be general enough (or at least generalizable) to support any other libc.
When libc depends on libclang_rt.hwasan, the latter can not interpose libc functions.
In fact, majority of interceptors become unnecessary when libc code is instrumented.
This change gets rid of most hwasan interceptors and provides interface for libc to notify
hwasan about thread creation and destruction events. Some interceptors (pthread_create)
are kept under #ifdef to enable testing with uninstrumented libc. They are expressed in
terms of the new libc interface.
The new cmake switch, COMPILER_RT_HWASAN_WITH_INTERCEPTORS, ON by default, builds testing
version of the library with the aforementioned pthread_create interceptor.
With the OFF setting, the library becomes more of a libc plugin.
Reviewers: vitalybuka, kcc, jfb
Subscribers: srhines, kubamracek, mgorny, jfb, llvm-commits
Differential Revision: https://reviews.llvm.org/D50922
llvm-svn: 340216
2018-08-20 21:49:15 +00:00
|
|
|
|
2017-12-09 01:31:51 +00:00
|
|
|
inited = 1;
|
|
|
|
}
|
2023-05-08 15:03:22 -07:00
|
|
|
} // namespace __hwasan
|
2021-06-07 15:35:28 -07:00
|
|
|
|
|
|
|
#endif // #if !SANITIZER_FUCHSIA
|