168d75effSDimitry Andric //===-- sanitizer_posix_libcdep.cpp ---------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 1068d75effSDimitry Andric // run-time libraries and implements libc-dependent POSIX-specific functions 1168d75effSDimitry Andric // from sanitizer_libc.h. 1268d75effSDimitry Andric //===----------------------------------------------------------------------===// 1368d75effSDimitry Andric 1468d75effSDimitry Andric #include "sanitizer_platform.h" 1568d75effSDimitry Andric 1668d75effSDimitry Andric #if SANITIZER_POSIX 1768d75effSDimitry Andric 1868d75effSDimitry Andric #include "sanitizer_common.h" 1968d75effSDimitry Andric #include "sanitizer_flags.h" 2068d75effSDimitry Andric #include "sanitizer_platform_limits_netbsd.h" 2168d75effSDimitry Andric #include "sanitizer_platform_limits_posix.h" 2268d75effSDimitry Andric #include "sanitizer_platform_limits_solaris.h" 2368d75effSDimitry Andric #include "sanitizer_posix.h" 2468d75effSDimitry Andric #include "sanitizer_procmaps.h" 2568d75effSDimitry Andric 2668d75effSDimitry Andric #include <errno.h> 2768d75effSDimitry Andric #include <fcntl.h> 2868d75effSDimitry Andric #include <pthread.h> 2968d75effSDimitry Andric #include <signal.h> 3068d75effSDimitry Andric #include <stdlib.h> 3168d75effSDimitry Andric #include <sys/mman.h> 3268d75effSDimitry Andric #include <sys/resource.h> 3368d75effSDimitry Andric #include <sys/stat.h> 3468d75effSDimitry Andric #include <sys/time.h> 3568d75effSDimitry Andric #include <sys/types.h> 3668d75effSDimitry Andric #include <sys/wait.h> 3768d75effSDimitry Andric #include <unistd.h> 3868d75effSDimitry Andric 3968d75effSDimitry Andric #if SANITIZER_FREEBSD 4068d75effSDimitry Andric // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before 4168d75effSDimitry Andric // that, it was never implemented. So just define it to zero. 4268d75effSDimitry Andric #undef MAP_NORESERVE 4368d75effSDimitry Andric #define MAP_NORESERVE 0 4468d75effSDimitry Andric #endif 4568d75effSDimitry Andric 4668d75effSDimitry Andric typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); 4768d75effSDimitry Andric 4868d75effSDimitry Andric namespace __sanitizer { 4968d75effSDimitry Andric 5068d75effSDimitry Andric u32 GetUid() { 5168d75effSDimitry Andric return getuid(); 5268d75effSDimitry Andric } 5368d75effSDimitry Andric 5468d75effSDimitry Andric uptr GetThreadSelf() { 5568d75effSDimitry Andric return (uptr)pthread_self(); 5668d75effSDimitry Andric } 5768d75effSDimitry Andric 5868d75effSDimitry Andric void ReleaseMemoryPagesToOS(uptr beg, uptr end) { 5968d75effSDimitry Andric uptr page_size = GetPageSizeCached(); 6068d75effSDimitry Andric uptr beg_aligned = RoundUpTo(beg, page_size); 6168d75effSDimitry Andric uptr end_aligned = RoundDownTo(end, page_size); 6268d75effSDimitry Andric if (beg_aligned < end_aligned) 63e8d8bef9SDimitry Andric internal_madvise(beg_aligned, end_aligned - beg_aligned, 6468d75effSDimitry Andric SANITIZER_MADVISE_DONTNEED); 6568d75effSDimitry Andric } 6668d75effSDimitry Andric 6768d75effSDimitry Andric void SetShadowRegionHugePageMode(uptr addr, uptr size) { 6868d75effSDimitry Andric #ifdef MADV_NOHUGEPAGE // May not be defined on old systems. 6968d75effSDimitry Andric if (common_flags()->no_huge_pages_for_shadow) 70e8d8bef9SDimitry Andric internal_madvise(addr, size, MADV_NOHUGEPAGE); 7168d75effSDimitry Andric else 72e8d8bef9SDimitry Andric internal_madvise(addr, size, MADV_HUGEPAGE); 7368d75effSDimitry Andric #endif // MADV_NOHUGEPAGE 7468d75effSDimitry Andric } 7568d75effSDimitry Andric 7668d75effSDimitry Andric bool DontDumpShadowMemory(uptr addr, uptr length) { 7768d75effSDimitry Andric #if defined(MADV_DONTDUMP) 78e8d8bef9SDimitry Andric return internal_madvise(addr, length, MADV_DONTDUMP) == 0; 7968d75effSDimitry Andric #elif defined(MADV_NOCORE) 80e8d8bef9SDimitry Andric return internal_madvise(addr, length, MADV_NOCORE) == 0; 8168d75effSDimitry Andric #else 8268d75effSDimitry Andric return true; 8368d75effSDimitry Andric #endif // MADV_DONTDUMP 8468d75effSDimitry Andric } 8568d75effSDimitry Andric 8668d75effSDimitry Andric static rlim_t getlim(int res) { 8768d75effSDimitry Andric rlimit rlim; 8868d75effSDimitry Andric CHECK_EQ(0, getrlimit(res, &rlim)); 8968d75effSDimitry Andric return rlim.rlim_cur; 9068d75effSDimitry Andric } 9168d75effSDimitry Andric 9268d75effSDimitry Andric static void setlim(int res, rlim_t lim) { 9368d75effSDimitry Andric struct rlimit rlim; 94*0fca6ea1SDimitry Andric if (getrlimit(res, &rlim)) { 9568d75effSDimitry Andric Report("ERROR: %s getrlimit() failed %d\n", SanitizerToolName, errno); 9668d75effSDimitry Andric Die(); 9768d75effSDimitry Andric } 9868d75effSDimitry Andric rlim.rlim_cur = lim; 99*0fca6ea1SDimitry Andric if (setrlimit(res, &rlim)) { 10068d75effSDimitry Andric Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno); 10168d75effSDimitry Andric Die(); 10268d75effSDimitry Andric } 10368d75effSDimitry Andric } 10468d75effSDimitry Andric 10568d75effSDimitry Andric void DisableCoreDumperIfNecessary() { 10668d75effSDimitry Andric if (common_flags()->disable_coredump) { 107*0fca6ea1SDimitry Andric rlimit rlim; 108*0fca6ea1SDimitry Andric CHECK_EQ(0, getrlimit(RLIMIT_CORE, &rlim)); 109*0fca6ea1SDimitry Andric // On Linux, if the kernel.core_pattern sysctl starts with a '|' (i.e. it 110*0fca6ea1SDimitry Andric // is being piped to a coredump handler such as systemd-coredumpd), the 111*0fca6ea1SDimitry Andric // kernel ignores RLIMIT_CORE (since we aren't creating a file in the file 112*0fca6ea1SDimitry Andric // system) except for the magic value of 1, which disables coredumps when 113*0fca6ea1SDimitry Andric // piping. 1 byte is too small for any kind of valid core dump, so it 114*0fca6ea1SDimitry Andric // also disables coredumps if kernel.core_pattern creates files directly. 115*0fca6ea1SDimitry Andric // While most piped coredump handlers do respect the crashing processes' 116*0fca6ea1SDimitry Andric // RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump 117*0fca6ea1SDimitry Andric // due to a local patch that changes sysctl.d/50-coredump.conf to ignore 118*0fca6ea1SDimitry Andric // the specified limit and instead use RLIM_INFINITY. 119*0fca6ea1SDimitry Andric // 120*0fca6ea1SDimitry Andric // The alternative to using RLIMIT_CORE=1 would be to use prctl() with the 121*0fca6ea1SDimitry Andric // PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it 122*0fca6ea1SDimitry Andric // impossible to attach a debugger. 123*0fca6ea1SDimitry Andric // 124*0fca6ea1SDimitry Andric // Note: we use rlim_max in the Min() call here since that is the upper 125*0fca6ea1SDimitry Andric // limit for what can be set without getting an EINVAL error. 126*0fca6ea1SDimitry Andric rlim.rlim_cur = Min<rlim_t>(SANITIZER_LINUX ? 1 : 0, rlim.rlim_max); 127*0fca6ea1SDimitry Andric CHECK_EQ(0, setrlimit(RLIMIT_CORE, &rlim)); 12868d75effSDimitry Andric } 12968d75effSDimitry Andric } 13068d75effSDimitry Andric 13168d75effSDimitry Andric bool StackSizeIsUnlimited() { 13268d75effSDimitry Andric rlim_t stack_size = getlim(RLIMIT_STACK); 13368d75effSDimitry Andric return (stack_size == RLIM_INFINITY); 13468d75effSDimitry Andric } 13568d75effSDimitry Andric 13668d75effSDimitry Andric void SetStackSizeLimitInBytes(uptr limit) { 13768d75effSDimitry Andric setlim(RLIMIT_STACK, (rlim_t)limit); 13868d75effSDimitry Andric CHECK(!StackSizeIsUnlimited()); 13968d75effSDimitry Andric } 14068d75effSDimitry Andric 14168d75effSDimitry Andric bool AddressSpaceIsUnlimited() { 14268d75effSDimitry Andric rlim_t as_size = getlim(RLIMIT_AS); 14368d75effSDimitry Andric return (as_size == RLIM_INFINITY); 14468d75effSDimitry Andric } 14568d75effSDimitry Andric 14668d75effSDimitry Andric void SetAddressSpaceUnlimited() { 14768d75effSDimitry Andric setlim(RLIMIT_AS, RLIM_INFINITY); 14868d75effSDimitry Andric CHECK(AddressSpaceIsUnlimited()); 14968d75effSDimitry Andric } 15068d75effSDimitry Andric 15168d75effSDimitry Andric void Abort() { 15268d75effSDimitry Andric #if !SANITIZER_GO 15368d75effSDimitry Andric // If we are handling SIGABRT, unhandle it first. 15468d75effSDimitry Andric // TODO(vitalybuka): Check if handler belongs to sanitizer. 15568d75effSDimitry Andric if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) { 15668d75effSDimitry Andric struct sigaction sigact; 15768d75effSDimitry Andric internal_memset(&sigact, 0, sizeof(sigact)); 158fe6060f1SDimitry Andric sigact.sa_handler = SIG_DFL; 15968d75effSDimitry Andric internal_sigaction(SIGABRT, &sigact, nullptr); 16068d75effSDimitry Andric } 16168d75effSDimitry Andric #endif 16268d75effSDimitry Andric 16368d75effSDimitry Andric abort(); 16468d75effSDimitry Andric } 16568d75effSDimitry Andric 16668d75effSDimitry Andric int Atexit(void (*function)(void)) { 16768d75effSDimitry Andric #if !SANITIZER_GO 16868d75effSDimitry Andric return atexit(function); 16968d75effSDimitry Andric #else 17068d75effSDimitry Andric return 0; 17168d75effSDimitry Andric #endif 17268d75effSDimitry Andric } 17368d75effSDimitry Andric 174349cc55cSDimitry Andric bool CreateDir(const char *pathname) { return mkdir(pathname, 0755) == 0; } 175349cc55cSDimitry Andric 17668d75effSDimitry Andric bool SupportsColoredOutput(fd_t fd) { 17768d75effSDimitry Andric return isatty(fd) != 0; 17868d75effSDimitry Andric } 17968d75effSDimitry Andric 18068d75effSDimitry Andric #if !SANITIZER_GO 18168d75effSDimitry Andric // TODO(glider): different tools may require different altstack size. 1824652422eSDimitry Andric static uptr GetAltStackSize() { 1834652422eSDimitry Andric // Note: since GLIBC_2.31, SIGSTKSZ may be a function call, so this may be 1844652422eSDimitry Andric // more costly that you think. However GetAltStackSize is only call 2-3 times 1854652422eSDimitry Andric // per thread so don't cache the evaluation. 1864652422eSDimitry Andric return SIGSTKSZ * 4; 1874652422eSDimitry Andric } 18868d75effSDimitry Andric 18968d75effSDimitry Andric void SetAlternateSignalStack() { 19068d75effSDimitry Andric stack_t altstack, oldstack; 19168d75effSDimitry Andric CHECK_EQ(0, sigaltstack(nullptr, &oldstack)); 19268d75effSDimitry Andric // If the alternate stack is already in place, do nothing. 19368d75effSDimitry Andric // Android always sets an alternate stack, but it's too small for us. 19468d75effSDimitry Andric if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return; 19568d75effSDimitry Andric // TODO(glider): the mapped stack should have the MAP_STACK flag in the 19668d75effSDimitry Andric // future. It is not required by man 2 sigaltstack now (they're using 19768d75effSDimitry Andric // malloc()). 1984652422eSDimitry Andric altstack.ss_size = GetAltStackSize(); 199fe6060f1SDimitry Andric altstack.ss_sp = (char *)MmapOrDie(altstack.ss_size, __func__); 200fe6060f1SDimitry Andric altstack.ss_flags = 0; 20168d75effSDimitry Andric CHECK_EQ(0, sigaltstack(&altstack, nullptr)); 20268d75effSDimitry Andric } 20368d75effSDimitry Andric 20468d75effSDimitry Andric void UnsetAlternateSignalStack() { 20568d75effSDimitry Andric stack_t altstack, oldstack; 20668d75effSDimitry Andric altstack.ss_sp = nullptr; 20768d75effSDimitry Andric altstack.ss_flags = SS_DISABLE; 2084652422eSDimitry Andric altstack.ss_size = GetAltStackSize(); // Some sane value required on Darwin. 20968d75effSDimitry Andric CHECK_EQ(0, sigaltstack(&altstack, &oldstack)); 21068d75effSDimitry Andric UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); 21168d75effSDimitry Andric } 21268d75effSDimitry Andric 21368d75effSDimitry Andric static void MaybeInstallSigaction(int signum, 21468d75effSDimitry Andric SignalHandlerType handler) { 21568d75effSDimitry Andric if (GetHandleSignalMode(signum) == kHandleSignalNo) return; 21668d75effSDimitry Andric 21768d75effSDimitry Andric struct sigaction sigact; 21868d75effSDimitry Andric internal_memset(&sigact, 0, sizeof(sigact)); 21968d75effSDimitry Andric sigact.sa_sigaction = (sa_sigaction_t)handler; 22068d75effSDimitry Andric // Do not block the signal from being received in that signal's handler. 22168d75effSDimitry Andric // Clients are responsible for handling this correctly. 22268d75effSDimitry Andric sigact.sa_flags = SA_SIGINFO | SA_NODEFER; 22368d75effSDimitry Andric if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; 22468d75effSDimitry Andric CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); 22568d75effSDimitry Andric VReport(1, "Installed the sigaction for signal %d\n", signum); 22668d75effSDimitry Andric } 22768d75effSDimitry Andric 22868d75effSDimitry Andric void InstallDeadlySignalHandlers(SignalHandlerType handler) { 22968d75effSDimitry Andric // Set the alternate signal stack for the main thread. 23068d75effSDimitry Andric // This will cause SetAlternateSignalStack to be called twice, but the stack 23168d75effSDimitry Andric // will be actually set only once. 23268d75effSDimitry Andric if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); 23368d75effSDimitry Andric MaybeInstallSigaction(SIGSEGV, handler); 23468d75effSDimitry Andric MaybeInstallSigaction(SIGBUS, handler); 23568d75effSDimitry Andric MaybeInstallSigaction(SIGABRT, handler); 23668d75effSDimitry Andric MaybeInstallSigaction(SIGFPE, handler); 23768d75effSDimitry Andric MaybeInstallSigaction(SIGILL, handler); 23868d75effSDimitry Andric MaybeInstallSigaction(SIGTRAP, handler); 23968d75effSDimitry Andric } 24068d75effSDimitry Andric 24168d75effSDimitry Andric bool SignalContext::IsStackOverflow() const { 24268d75effSDimitry Andric // Access at a reasonable offset above SP, or slightly below it (to account 24368d75effSDimitry Andric // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is 24468d75effSDimitry Andric // probably a stack overflow. 24568d75effSDimitry Andric #ifdef __s390__ 24668d75effSDimitry Andric // On s390, the fault address in siginfo points to start of the page, not 24768d75effSDimitry Andric // to the precise word that was accessed. Mask off the low bits of sp to 24868d75effSDimitry Andric // take it into account. 24968d75effSDimitry Andric bool IsStackAccess = addr >= (sp & ~0xFFF) && addr < sp + 0xFFFF; 25068d75effSDimitry Andric #else 25168d75effSDimitry Andric // Let's accept up to a page size away from top of stack. Things like stack 25268d75effSDimitry Andric // probing can trigger accesses with such large offsets. 25368d75effSDimitry Andric bool IsStackAccess = addr + GetPageSizeCached() > sp && addr < sp + 0xFFFF; 25468d75effSDimitry Andric #endif 25568d75effSDimitry Andric 25668d75effSDimitry Andric #if __powerpc__ 25768d75effSDimitry Andric // Large stack frames can be allocated with e.g. 25868d75effSDimitry Andric // lis r0,-10000 25968d75effSDimitry Andric // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000 26068d75effSDimitry Andric // If the store faults then sp will not have been updated, so test above 26168d75effSDimitry Andric // will not work, because the fault address will be more than just "slightly" 26268d75effSDimitry Andric // below sp. 26368d75effSDimitry Andric if (!IsStackAccess && IsAccessibleMemoryRange(pc, 4)) { 26468d75effSDimitry Andric u32 inst = *(unsigned *)pc; 26568d75effSDimitry Andric u32 ra = (inst >> 16) & 0x1F; 26668d75effSDimitry Andric u32 opcd = inst >> 26; 26768d75effSDimitry Andric u32 xo = (inst >> 1) & 0x3FF; 26868d75effSDimitry Andric // Check for store-with-update to sp. The instructions we accept are: 26968d75effSDimitry Andric // stbu rs,d(ra) stbux rs,ra,rb 27068d75effSDimitry Andric // sthu rs,d(ra) sthux rs,ra,rb 27168d75effSDimitry Andric // stwu rs,d(ra) stwux rs,ra,rb 27268d75effSDimitry Andric // stdu rs,ds(ra) stdux rs,ra,rb 27368d75effSDimitry Andric // where ra is r1 (the stack pointer). 27468d75effSDimitry Andric if (ra == 1 && 27568d75effSDimitry Andric (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 || 27668d75effSDimitry Andric (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181)))) 27768d75effSDimitry Andric IsStackAccess = true; 27868d75effSDimitry Andric } 27968d75effSDimitry Andric #endif // __powerpc__ 28068d75effSDimitry Andric 28168d75effSDimitry Andric // We also check si_code to filter out SEGV caused by something else other 28268d75effSDimitry Andric // then hitting the guard page or unmapped memory, like, for example, 28368d75effSDimitry Andric // unaligned memory access. 28468d75effSDimitry Andric auto si = static_cast<const siginfo_t *>(siginfo); 28568d75effSDimitry Andric return IsStackAccess && 28668d75effSDimitry Andric (si->si_code == si_SEGV_MAPERR || si->si_code == si_SEGV_ACCERR); 28768d75effSDimitry Andric } 28868d75effSDimitry Andric 28968d75effSDimitry Andric #endif // SANITIZER_GO 29068d75effSDimitry Andric 29168d75effSDimitry Andric bool IsAccessibleMemoryRange(uptr beg, uptr size) { 29268d75effSDimitry Andric uptr page_size = GetPageSizeCached(); 29368d75effSDimitry Andric // Checking too large memory ranges is slow. 29468d75effSDimitry Andric CHECK_LT(size, page_size * 10); 29568d75effSDimitry Andric int sock_pair[2]; 29668d75effSDimitry Andric if (pipe(sock_pair)) 29768d75effSDimitry Andric return false; 29868d75effSDimitry Andric uptr bytes_written = 29968d75effSDimitry Andric internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size); 30068d75effSDimitry Andric int write_errno; 30168d75effSDimitry Andric bool result; 30268d75effSDimitry Andric if (internal_iserror(bytes_written, &write_errno)) { 30368d75effSDimitry Andric CHECK_EQ(EFAULT, write_errno); 30468d75effSDimitry Andric result = false; 30568d75effSDimitry Andric } else { 30668d75effSDimitry Andric result = (bytes_written == size); 30768d75effSDimitry Andric } 30868d75effSDimitry Andric internal_close(sock_pair[0]); 30968d75effSDimitry Andric internal_close(sock_pair[1]); 31068d75effSDimitry Andric return result; 31168d75effSDimitry Andric } 31268d75effSDimitry Andric 31381ad6265SDimitry Andric void PlatformPrepareForSandboxing(void *args) { 31468d75effSDimitry Andric // Some kinds of sandboxes may forbid filesystem access, so we won't be able 31568d75effSDimitry Andric // to read the file mappings from /proc/self/maps. Luckily, neither the 31668d75effSDimitry Andric // process will be able to load additional libraries, so it's fine to use the 31768d75effSDimitry Andric // cached mappings. 31868d75effSDimitry Andric MemoryMappingLayout::CacheMemoryMappings(); 31968d75effSDimitry Andric } 32068d75effSDimitry Andric 32168d75effSDimitry Andric static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags, 32268d75effSDimitry Andric const char *name) { 32368d75effSDimitry Andric size = RoundUpTo(size, GetPageSizeCached()); 32468d75effSDimitry Andric fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached()); 32568d75effSDimitry Andric uptr p = 32668d75effSDimitry Andric MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE, 32768d75effSDimitry Andric MAP_PRIVATE | MAP_FIXED | additional_flags | MAP_ANON, name); 32868d75effSDimitry Andric int reserrno; 32968d75effSDimitry Andric if (internal_iserror(p, &reserrno)) { 330*0fca6ea1SDimitry Andric Report( 331*0fca6ea1SDimitry Andric "ERROR: %s failed to " 332*0fca6ea1SDimitry Andric "allocate 0x%zx (%zd) bytes at address %p (errno: %d)\n", 333*0fca6ea1SDimitry Andric SanitizerToolName, size, size, (void *)fixed_addr, reserrno); 33468d75effSDimitry Andric return false; 33568d75effSDimitry Andric } 33668d75effSDimitry Andric IncreaseTotalMmap(size); 33768d75effSDimitry Andric return true; 33868d75effSDimitry Andric } 33968d75effSDimitry Andric 34068d75effSDimitry Andric bool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { 34168d75effSDimitry Andric return MmapFixed(fixed_addr, size, MAP_NORESERVE, name); 34268d75effSDimitry Andric } 34368d75effSDimitry Andric 34468d75effSDimitry Andric bool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) { 34568d75effSDimitry Andric #if SANITIZER_FREEBSD 34668d75effSDimitry Andric if (common_flags()->no_huge_pages_for_shadow) 34768d75effSDimitry Andric return MmapFixedNoReserve(fixed_addr, size, name); 34868d75effSDimitry Andric // MAP_NORESERVE is implicit with FreeBSD 34968d75effSDimitry Andric return MmapFixed(fixed_addr, size, MAP_ALIGNED_SUPER, name); 35068d75effSDimitry Andric #else 35168d75effSDimitry Andric bool r = MmapFixedNoReserve(fixed_addr, size, name); 35268d75effSDimitry Andric if (r) 35368d75effSDimitry Andric SetShadowRegionHugePageMode(fixed_addr, size); 35468d75effSDimitry Andric return r; 35568d75effSDimitry Andric #endif 35668d75effSDimitry Andric } 35768d75effSDimitry Andric 35868d75effSDimitry Andric uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) { 35968d75effSDimitry Andric base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size, name) 36068d75effSDimitry Andric : MmapNoAccess(size); 36168d75effSDimitry Andric size_ = size; 36268d75effSDimitry Andric name_ = name; 36368d75effSDimitry Andric (void)os_handle_; // unsupported 36468d75effSDimitry Andric return reinterpret_cast<uptr>(base_); 36568d75effSDimitry Andric } 36668d75effSDimitry Andric 36768d75effSDimitry Andric // Uses fixed_addr for now. 36868d75effSDimitry Andric // Will use offset instead once we've implemented this function for real. 36968d75effSDimitry Andric uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) { 37068d75effSDimitry Andric return reinterpret_cast<uptr>( 37168d75effSDimitry Andric MmapFixedOrDieOnFatalError(fixed_addr, size, name)); 37268d75effSDimitry Andric } 37368d75effSDimitry Andric 37468d75effSDimitry Andric uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size, 37568d75effSDimitry Andric const char *name) { 37668d75effSDimitry Andric return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size, name)); 37768d75effSDimitry Andric } 37868d75effSDimitry Andric 37968d75effSDimitry Andric void ReservedAddressRange::Unmap(uptr addr, uptr size) { 38068d75effSDimitry Andric CHECK_LE(size, size_); 38168d75effSDimitry Andric if (addr == reinterpret_cast<uptr>(base_)) 38268d75effSDimitry Andric // If we unmap the whole range, just null out the base. 38368d75effSDimitry Andric base_ = (size == size_) ? nullptr : reinterpret_cast<void*>(addr + size); 38468d75effSDimitry Andric else 38568d75effSDimitry Andric CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_); 38668d75effSDimitry Andric size_ -= size; 38768d75effSDimitry Andric UnmapOrDie(reinterpret_cast<void*>(addr), size); 38868d75effSDimitry Andric } 38968d75effSDimitry Andric 39068d75effSDimitry Andric void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) { 39168d75effSDimitry Andric return (void *)MmapNamed((void *)fixed_addr, size, PROT_NONE, 39268d75effSDimitry Andric MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE | MAP_ANON, 39368d75effSDimitry Andric name); 39468d75effSDimitry Andric } 39568d75effSDimitry Andric 39668d75effSDimitry Andric void *MmapNoAccess(uptr size) { 39768d75effSDimitry Andric unsigned flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE; 39868d75effSDimitry Andric return (void *)internal_mmap(nullptr, size, PROT_NONE, flags, -1, 0); 39968d75effSDimitry Andric } 40068d75effSDimitry Andric 40168d75effSDimitry Andric // This function is defined elsewhere if we intercepted pthread_attr_getstack. 40268d75effSDimitry Andric extern "C" { 40368d75effSDimitry Andric SANITIZER_WEAK_ATTRIBUTE int 40468d75effSDimitry Andric real_pthread_attr_getstack(void *attr, void **addr, size_t *size); 40568d75effSDimitry Andric } // extern "C" 40668d75effSDimitry Andric 40706c3fb27SDimitry Andric int internal_pthread_attr_getstack(void *attr, void **addr, uptr *size) { 40881ad6265SDimitry Andric #if !SANITIZER_GO && !SANITIZER_APPLE 40968d75effSDimitry Andric if (&real_pthread_attr_getstack) 41068d75effSDimitry Andric return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, 41168d75effSDimitry Andric (size_t *)size); 41268d75effSDimitry Andric #endif 41368d75effSDimitry Andric return pthread_attr_getstack((pthread_attr_t *)attr, addr, (size_t *)size); 41468d75effSDimitry Andric } 41568d75effSDimitry Andric 41668d75effSDimitry Andric #if !SANITIZER_GO 41768d75effSDimitry Andric void AdjustStackSize(void *attr_) { 41868d75effSDimitry Andric pthread_attr_t *attr = (pthread_attr_t *)attr_; 41968d75effSDimitry Andric uptr stackaddr = 0; 42068d75effSDimitry Andric uptr stacksize = 0; 42106c3fb27SDimitry Andric internal_pthread_attr_getstack(attr, (void **)&stackaddr, &stacksize); 42268d75effSDimitry Andric // GLibC will return (0 - stacksize) as the stack address in the case when 42368d75effSDimitry Andric // stacksize is set, but stackaddr is not. 42468d75effSDimitry Andric bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0); 42568d75effSDimitry Andric // We place a lot of tool data into TLS, account for that. 42668d75effSDimitry Andric const uptr minstacksize = GetTlsSize() + 128*1024; 42768d75effSDimitry Andric if (stacksize < minstacksize) { 42868d75effSDimitry Andric if (!stack_set) { 42968d75effSDimitry Andric if (stacksize != 0) { 43068d75effSDimitry Andric VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize, 43168d75effSDimitry Andric minstacksize); 43268d75effSDimitry Andric pthread_attr_setstacksize(attr, minstacksize); 43368d75effSDimitry Andric } 43468d75effSDimitry Andric } else { 43568d75effSDimitry Andric Printf("Sanitizer: pre-allocated stack size is insufficient: " 43668d75effSDimitry Andric "%zu < %zu\n", stacksize, minstacksize); 43768d75effSDimitry Andric Printf("Sanitizer: pthread_create is likely to fail.\n"); 43868d75effSDimitry Andric } 43968d75effSDimitry Andric } 44068d75effSDimitry Andric } 44168d75effSDimitry Andric #endif // !SANITIZER_GO 44268d75effSDimitry Andric 44368d75effSDimitry Andric pid_t StartSubprocess(const char *program, const char *const argv[], 4445ffd83dbSDimitry Andric const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, 4455ffd83dbSDimitry Andric fd_t stderr_fd) { 44668d75effSDimitry Andric auto file_closer = at_scope_exit([&] { 44768d75effSDimitry Andric if (stdin_fd != kInvalidFd) { 44868d75effSDimitry Andric internal_close(stdin_fd); 44968d75effSDimitry Andric } 45068d75effSDimitry Andric if (stdout_fd != kInvalidFd) { 45168d75effSDimitry Andric internal_close(stdout_fd); 45268d75effSDimitry Andric } 45368d75effSDimitry Andric if (stderr_fd != kInvalidFd) { 45468d75effSDimitry Andric internal_close(stderr_fd); 45568d75effSDimitry Andric } 45668d75effSDimitry Andric }); 45768d75effSDimitry Andric 45868d75effSDimitry Andric int pid = internal_fork(); 45968d75effSDimitry Andric 46068d75effSDimitry Andric if (pid < 0) { 46168d75effSDimitry Andric int rverrno; 46268d75effSDimitry Andric if (internal_iserror(pid, &rverrno)) { 46368d75effSDimitry Andric Report("WARNING: failed to fork (errno %d)\n", rverrno); 46468d75effSDimitry Andric } 46568d75effSDimitry Andric return pid; 46668d75effSDimitry Andric } 46768d75effSDimitry Andric 46868d75effSDimitry Andric if (pid == 0) { 46968d75effSDimitry Andric // Child subprocess 47068d75effSDimitry Andric if (stdin_fd != kInvalidFd) { 47168d75effSDimitry Andric internal_close(STDIN_FILENO); 47268d75effSDimitry Andric internal_dup2(stdin_fd, STDIN_FILENO); 47368d75effSDimitry Andric internal_close(stdin_fd); 47468d75effSDimitry Andric } 47568d75effSDimitry Andric if (stdout_fd != kInvalidFd) { 47668d75effSDimitry Andric internal_close(STDOUT_FILENO); 47768d75effSDimitry Andric internal_dup2(stdout_fd, STDOUT_FILENO); 47868d75effSDimitry Andric internal_close(stdout_fd); 47968d75effSDimitry Andric } 48068d75effSDimitry Andric if (stderr_fd != kInvalidFd) { 48168d75effSDimitry Andric internal_close(STDERR_FILENO); 48268d75effSDimitry Andric internal_dup2(stderr_fd, STDERR_FILENO); 48368d75effSDimitry Andric internal_close(stderr_fd); 48468d75effSDimitry Andric } 48568d75effSDimitry Andric 48668d75effSDimitry Andric for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); 48768d75effSDimitry Andric 4885ffd83dbSDimitry Andric internal_execve(program, const_cast<char **>(&argv[0]), 4895ffd83dbSDimitry Andric const_cast<char *const *>(envp)); 49068d75effSDimitry Andric internal__exit(1); 49168d75effSDimitry Andric } 49268d75effSDimitry Andric 49368d75effSDimitry Andric return pid; 49468d75effSDimitry Andric } 49568d75effSDimitry Andric 49668d75effSDimitry Andric bool IsProcessRunning(pid_t pid) { 49768d75effSDimitry Andric int process_status; 49868d75effSDimitry Andric uptr waitpid_status = internal_waitpid(pid, &process_status, WNOHANG); 49968d75effSDimitry Andric int local_errno; 50068d75effSDimitry Andric if (internal_iserror(waitpid_status, &local_errno)) { 50168d75effSDimitry Andric VReport(1, "Waiting on the process failed (errno %d).\n", local_errno); 50268d75effSDimitry Andric return false; 50368d75effSDimitry Andric } 50468d75effSDimitry Andric return waitpid_status == 0; 50568d75effSDimitry Andric } 50668d75effSDimitry Andric 50768d75effSDimitry Andric int WaitForProcess(pid_t pid) { 50868d75effSDimitry Andric int process_status; 50968d75effSDimitry Andric uptr waitpid_status = internal_waitpid(pid, &process_status, 0); 51068d75effSDimitry Andric int local_errno; 51168d75effSDimitry Andric if (internal_iserror(waitpid_status, &local_errno)) { 51268d75effSDimitry Andric VReport(1, "Waiting on the process failed (errno %d).\n", local_errno); 51368d75effSDimitry Andric return -1; 51468d75effSDimitry Andric } 51568d75effSDimitry Andric return process_status; 51668d75effSDimitry Andric } 51768d75effSDimitry Andric 51868d75effSDimitry Andric bool IsStateDetached(int state) { 51968d75effSDimitry Andric return state == PTHREAD_CREATE_DETACHED; 52068d75effSDimitry Andric } 52168d75effSDimitry Andric 52268d75effSDimitry Andric } // namespace __sanitizer 52368d75effSDimitry Andric 52468d75effSDimitry Andric #endif // SANITIZER_POSIX 525