xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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