llvm-project
523 строки · 17.3 Кб
1//===-- sanitizer_posix_libcdep.cpp ---------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is shared between AddressSanitizer and ThreadSanitizer
10// run-time libraries and implements libc-dependent POSIX-specific functions
11// from sanitizer_libc.h.
12//===----------------------------------------------------------------------===//
13
14#include "sanitizer_platform.h"15
16#if SANITIZER_POSIX17
18#include "sanitizer_common.h"19#include "sanitizer_flags.h"20#include "sanitizer_platform_limits_netbsd.h"21#include "sanitizer_platform_limits_posix.h"22#include "sanitizer_platform_limits_solaris.h"23#include "sanitizer_posix.h"24#include "sanitizer_procmaps.h"25
26#include <errno.h>27#include <fcntl.h>28#include <pthread.h>29#include <signal.h>30#include <stdlib.h>31#include <sys/mman.h>32#include <sys/resource.h>33#include <sys/stat.h>34#include <sys/time.h>35#include <sys/types.h>36#include <sys/wait.h>37#include <unistd.h>38
39#if SANITIZER_FREEBSD40// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
41// that, it was never implemented. So just define it to zero.
42#undef MAP_NORESERVE43#define MAP_NORESERVE 044#endif45
46typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);47
48namespace __sanitizer {49
50u32 GetUid() {51return getuid();52}
53
54uptr GetThreadSelf() {55return (uptr)pthread_self();56}
57
58void ReleaseMemoryPagesToOS(uptr beg, uptr end) {59uptr page_size = GetPageSizeCached();60uptr beg_aligned = RoundUpTo(beg, page_size);61uptr end_aligned = RoundDownTo(end, page_size);62if (beg_aligned < end_aligned)63internal_madvise(beg_aligned, end_aligned - beg_aligned,64SANITIZER_MADVISE_DONTNEED);65}
66
67void SetShadowRegionHugePageMode(uptr addr, uptr size) {68#ifdef MADV_NOHUGEPAGE // May not be defined on old systems.69if (common_flags()->no_huge_pages_for_shadow)70internal_madvise(addr, size, MADV_NOHUGEPAGE);71else72internal_madvise(addr, size, MADV_HUGEPAGE);73#endif // MADV_NOHUGEPAGE74}
75
76bool DontDumpShadowMemory(uptr addr, uptr length) {77#if defined(MADV_DONTDUMP)78return internal_madvise(addr, length, MADV_DONTDUMP) == 0;79#elif defined(MADV_NOCORE)80return internal_madvise(addr, length, MADV_NOCORE) == 0;81#else82return true;83#endif // MADV_DONTDUMP84}
85
86static rlim_t getlim(int res) {87rlimit rlim;88CHECK_EQ(0, getrlimit(res, &rlim));89return rlim.rlim_cur;90}
91
92static void setlim(int res, rlim_t lim) {93struct rlimit rlim;94if (getrlimit(res, &rlim)) {95Report("ERROR: %s getrlimit() failed %d\n", SanitizerToolName, errno);96Die();97}98rlim.rlim_cur = lim;99if (setrlimit(res, &rlim)) {100Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);101Die();102}103}
104
105void DisableCoreDumperIfNecessary() {106if (common_flags()->disable_coredump) {107rlimit rlim;108CHECK_EQ(0, getrlimit(RLIMIT_CORE, &rlim));109// On Linux, if the kernel.core_pattern sysctl starts with a '|' (i.e. it110// is being piped to a coredump handler such as systemd-coredumpd), the111// kernel ignores RLIMIT_CORE (since we aren't creating a file in the file112// system) except for the magic value of 1, which disables coredumps when113// piping. 1 byte is too small for any kind of valid core dump, so it114// also disables coredumps if kernel.core_pattern creates files directly.115// While most piped coredump handlers do respect the crashing processes'116// RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump117// due to a local patch that changes sysctl.d/50-coredump.conf to ignore118// the specified limit and instead use RLIM_INFINITY.119//120// The alternative to using RLIMIT_CORE=1 would be to use prctl() with the121// PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it122// impossible to attach a debugger.123//124// Note: we use rlim_max in the Min() call here since that is the upper125// limit for what can be set without getting an EINVAL error.126rlim.rlim_cur = Min<rlim_t>(SANITIZER_LINUX ? 1 : 0, rlim.rlim_max);127CHECK_EQ(0, setrlimit(RLIMIT_CORE, &rlim));128}129}
130
131bool StackSizeIsUnlimited() {132rlim_t stack_size = getlim(RLIMIT_STACK);133return (stack_size == RLIM_INFINITY);134}
135
136void SetStackSizeLimitInBytes(uptr limit) {137setlim(RLIMIT_STACK, (rlim_t)limit);138CHECK(!StackSizeIsUnlimited());139}
140
141bool AddressSpaceIsUnlimited() {142rlim_t as_size = getlim(RLIMIT_AS);143return (as_size == RLIM_INFINITY);144}
145
146void SetAddressSpaceUnlimited() {147setlim(RLIMIT_AS, RLIM_INFINITY);148CHECK(AddressSpaceIsUnlimited());149}
150
151void Abort() {152#if !SANITIZER_GO153// If we are handling SIGABRT, unhandle it first.154// TODO(vitalybuka): Check if handler belongs to sanitizer.155if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) {156struct sigaction sigact;157internal_memset(&sigact, 0, sizeof(sigact));158sigact.sa_handler = SIG_DFL;159internal_sigaction(SIGABRT, &sigact, nullptr);160}161#endif162
163abort();164}
165
166int Atexit(void (*function)(void)) {167#if !SANITIZER_GO168return atexit(function);169#else170return 0;171#endif172}
173
174bool CreateDir(const char *pathname) { return mkdir(pathname, 0755) == 0; }175
176bool SupportsColoredOutput(fd_t fd) {177return isatty(fd) != 0;178}
179
180#if !SANITIZER_GO181// TODO(glider): different tools may require different altstack size.
182static uptr GetAltStackSize() {183// Note: since GLIBC_2.31, SIGSTKSZ may be a function call, so this may be184// more costly that you think. However GetAltStackSize is only call 2-3 times185// per thread so don't cache the evaluation.186return SIGSTKSZ * 4;187}
188
189void SetAlternateSignalStack() {190stack_t altstack, oldstack;191CHECK_EQ(0, sigaltstack(nullptr, &oldstack));192// If the alternate stack is already in place, do nothing.193// Android always sets an alternate stack, but it's too small for us.194if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return;195// TODO(glider): the mapped stack should have the MAP_STACK flag in the196// future. It is not required by man 2 sigaltstack now (they're using197// malloc()).198altstack.ss_size = GetAltStackSize();199altstack.ss_sp = (char *)MmapOrDie(altstack.ss_size, __func__);200altstack.ss_flags = 0;201CHECK_EQ(0, sigaltstack(&altstack, nullptr));202}
203
204void UnsetAlternateSignalStack() {205stack_t altstack, oldstack;206altstack.ss_sp = nullptr;207altstack.ss_flags = SS_DISABLE;208altstack.ss_size = GetAltStackSize(); // Some sane value required on Darwin.209CHECK_EQ(0, sigaltstack(&altstack, &oldstack));210UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);211}
212
213static void MaybeInstallSigaction(int signum,214SignalHandlerType handler) {215if (GetHandleSignalMode(signum) == kHandleSignalNo) return;216
217struct sigaction sigact;218internal_memset(&sigact, 0, sizeof(sigact));219sigact.sa_sigaction = (sa_sigaction_t)handler;220// Do not block the signal from being received in that signal's handler.221// Clients are responsible for handling this correctly.222sigact.sa_flags = SA_SIGINFO | SA_NODEFER;223if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;224CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr));225VReport(1, "Installed the sigaction for signal %d\n", signum);226}
227
228void InstallDeadlySignalHandlers(SignalHandlerType handler) {229// Set the alternate signal stack for the main thread.230// This will cause SetAlternateSignalStack to be called twice, but the stack231// will be actually set only once.232if (common_flags()->use_sigaltstack) SetAlternateSignalStack();233MaybeInstallSigaction(SIGSEGV, handler);234MaybeInstallSigaction(SIGBUS, handler);235MaybeInstallSigaction(SIGABRT, handler);236MaybeInstallSigaction(SIGFPE, handler);237MaybeInstallSigaction(SIGILL, handler);238MaybeInstallSigaction(SIGTRAP, handler);239}
240
241bool SignalContext::IsStackOverflow() const {242// Access at a reasonable offset above SP, or slightly below it (to account243// for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is244// probably a stack overflow.245#ifdef __s390__246// On s390, the fault address in siginfo points to start of the page, not247// to the precise word that was accessed. Mask off the low bits of sp to248// take it into account.249bool IsStackAccess = addr >= (sp & ~0xFFF) && addr < sp + 0xFFFF;250#else251// Let's accept up to a page size away from top of stack. Things like stack252// probing can trigger accesses with such large offsets.253bool IsStackAccess = addr + GetPageSizeCached() > sp && addr < sp + 0xFFFF;254#endif255
256#if __powerpc__257// Large stack frames can be allocated with e.g.258// lis r0,-10000259// stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000260// If the store faults then sp will not have been updated, so test above261// will not work, because the fault address will be more than just "slightly"262// below sp.263if (!IsStackAccess && IsAccessibleMemoryRange(pc, 4)) {264u32 inst = *(unsigned *)pc;265u32 ra = (inst >> 16) & 0x1F;266u32 opcd = inst >> 26;267u32 xo = (inst >> 1) & 0x3FF;268// Check for store-with-update to sp. The instructions we accept are:269// stbu rs,d(ra) stbux rs,ra,rb270// sthu rs,d(ra) sthux rs,ra,rb271// stwu rs,d(ra) stwux rs,ra,rb272// stdu rs,ds(ra) stdux rs,ra,rb273// where ra is r1 (the stack pointer).274if (ra == 1 &&275(opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||276(opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))277IsStackAccess = true;278}279#endif // __powerpc__280
281// We also check si_code to filter out SEGV caused by something else other282// then hitting the guard page or unmapped memory, like, for example,283// unaligned memory access.284auto si = static_cast<const siginfo_t *>(siginfo);285return IsStackAccess &&286(si->si_code == si_SEGV_MAPERR || si->si_code == si_SEGV_ACCERR);287}
288
289#endif // SANITIZER_GO290
291bool IsAccessibleMemoryRange(uptr beg, uptr size) {292uptr page_size = GetPageSizeCached();293// Checking too large memory ranges is slow.294CHECK_LT(size, page_size * 10);295int sock_pair[2];296if (pipe(sock_pair))297return false;298uptr bytes_written =299internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size);300int write_errno;301bool result;302if (internal_iserror(bytes_written, &write_errno)) {303CHECK_EQ(EFAULT, write_errno);304result = false;305} else {306result = (bytes_written == size);307}308internal_close(sock_pair[0]);309internal_close(sock_pair[1]);310return result;311}
312
313void PlatformPrepareForSandboxing(void *args) {314// Some kinds of sandboxes may forbid filesystem access, so we won't be able315// to read the file mappings from /proc/self/maps. Luckily, neither the316// process will be able to load additional libraries, so it's fine to use the317// cached mappings.318MemoryMappingLayout::CacheMemoryMappings();319}
320
321static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags,322const char *name) {323size = RoundUpTo(size, GetPageSizeCached());324fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached());325uptr p =326MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE,327MAP_PRIVATE | MAP_FIXED | additional_flags | MAP_ANON, name);328int reserrno;329if (internal_iserror(p, &reserrno)) {330Report("ERROR: %s failed to "331"allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",332SanitizerToolName, size, size, fixed_addr, reserrno);333return false;334}335IncreaseTotalMmap(size);336return true;337}
338
339bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {340return MmapFixed(fixed_addr, size, MAP_NORESERVE, name);341}
342
343bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) {344#if SANITIZER_FREEBSD345if (common_flags()->no_huge_pages_for_shadow)346return MmapFixedNoReserve(fixed_addr, size, name);347// MAP_NORESERVE is implicit with FreeBSD348return MmapFixed(fixed_addr, size, MAP_ALIGNED_SUPER, name);349#else350bool r = MmapFixedNoReserve(fixed_addr, size, name);351if (r)352SetShadowRegionHugePageMode(fixed_addr, size);353return r;354#endif355}
356
357uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) {358base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size, name)359: MmapNoAccess(size);360size_ = size;361name_ = name;362(void)os_handle_; // unsupported363return reinterpret_cast<uptr>(base_);364}
365
366// Uses fixed_addr for now.
367// Will use offset instead once we've implemented this function for real.
368uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) {369return reinterpret_cast<uptr>(370MmapFixedOrDieOnFatalError(fixed_addr, size, name));371}
372
373uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size,374const char *name) {375return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size, name));376}
377
378void ReservedAddressRange::Unmap(uptr addr, uptr size) {379CHECK_LE(size, size_);380if (addr == reinterpret_cast<uptr>(base_))381// If we unmap the whole range, just null out the base.382base_ = (size == size_) ? nullptr : reinterpret_cast<void*>(addr + size);383else384CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_);385size_ -= size;386UnmapOrDie(reinterpret_cast<void*>(addr), size);387}
388
389void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {390return (void *)MmapNamed((void *)fixed_addr, size, PROT_NONE,391MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON,392name);393}
394
395void *MmapNoAccess(uptr size) {396unsigned flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE;397return (void *)internal_mmap(nullptr, size, PROT_NONE, flags, -1, 0);398}
399
400// This function is defined elsewhere if we intercepted pthread_attr_getstack.
401extern "C" {402SANITIZER_WEAK_ATTRIBUTE int403real_pthread_attr_getstack(void *attr, void **addr, size_t *size);404} // extern "C"405
406int internal_pthread_attr_getstack(void *attr, void **addr, uptr *size) {407#if !SANITIZER_GO && !SANITIZER_APPLE408if (&real_pthread_attr_getstack)409return real_pthread_attr_getstack((pthread_attr_t *)attr, addr,410(size_t *)size);411#endif412return pthread_attr_getstack((pthread_attr_t *)attr, addr, (size_t *)size);413}
414
415#if !SANITIZER_GO416void AdjustStackSize(void *attr_) {417pthread_attr_t *attr = (pthread_attr_t *)attr_;418uptr stackaddr = 0;419uptr stacksize = 0;420internal_pthread_attr_getstack(attr, (void **)&stackaddr, &stacksize);421// GLibC will return (0 - stacksize) as the stack address in the case when422// stacksize is set, but stackaddr is not.423bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0);424// We place a lot of tool data into TLS, account for that.425const uptr minstacksize = GetTlsSize() + 128*1024;426if (stacksize < minstacksize) {427if (!stack_set) {428if (stacksize != 0) {429VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize,430minstacksize);431pthread_attr_setstacksize(attr, minstacksize);432}433} else {434Printf("Sanitizer: pre-allocated stack size is insufficient: "435"%zu < %zu\n", stacksize, minstacksize);436Printf("Sanitizer: pthread_create is likely to fail.\n");437}438}439}
440#endif // !SANITIZER_GO441
442pid_t StartSubprocess(const char *program, const char *const argv[],443const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,444fd_t stderr_fd) {445auto file_closer = at_scope_exit([&] {446if (stdin_fd != kInvalidFd) {447internal_close(stdin_fd);448}449if (stdout_fd != kInvalidFd) {450internal_close(stdout_fd);451}452if (stderr_fd != kInvalidFd) {453internal_close(stderr_fd);454}455});456
457int pid = internal_fork();458
459if (pid < 0) {460int rverrno;461if (internal_iserror(pid, &rverrno)) {462Report("WARNING: failed to fork (errno %d)\n", rverrno);463}464return pid;465}466
467if (pid == 0) {468// Child subprocess469if (stdin_fd != kInvalidFd) {470internal_close(STDIN_FILENO);471internal_dup2(stdin_fd, STDIN_FILENO);472internal_close(stdin_fd);473}474if (stdout_fd != kInvalidFd) {475internal_close(STDOUT_FILENO);476internal_dup2(stdout_fd, STDOUT_FILENO);477internal_close(stdout_fd);478}479if (stderr_fd != kInvalidFd) {480internal_close(STDERR_FILENO);481internal_dup2(stderr_fd, STDERR_FILENO);482internal_close(stderr_fd);483}484
485for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);486
487internal_execve(program, const_cast<char **>(&argv[0]),488const_cast<char *const *>(envp));489internal__exit(1);490}491
492return pid;493}
494
495bool IsProcessRunning(pid_t pid) {496int process_status;497uptr waitpid_status = internal_waitpid(pid, &process_status, WNOHANG);498int local_errno;499if (internal_iserror(waitpid_status, &local_errno)) {500VReport(1, "Waiting on the process failed (errno %d).\n", local_errno);501return false;502}503return waitpid_status == 0;504}
505
506int WaitForProcess(pid_t pid) {507int process_status;508uptr waitpid_status = internal_waitpid(pid, &process_status, 0);509int local_errno;510if (internal_iserror(waitpid_status, &local_errno)) {511VReport(1, "Waiting on the process failed (errno %d).\n", local_errno);512return -1;513}514return process_status;515}
516
517bool IsStateDetached(int state) {518return state == PTHREAD_CREATE_DETACHED;519}
520
521} // namespace __sanitizer522
523#endif // SANITIZER_POSIX524