diff options
Diffstat (limited to 'lib/sanitizer_common/sanitizer_linux.cc')
-rw-r--r-- | lib/sanitizer_common/sanitizer_linux.cc | 304 |
1 files changed, 190 insertions, 114 deletions
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 96d6c1eff42c..48795674c54c 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -31,10 +31,6 @@ #include <asm/param.h> #endif -#if SANITIZER_NETBSD -#include <lwp.h> -#endif - // For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat' // format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To // access stat from asm/stat.h, without conflicting with definition in @@ -55,6 +51,7 @@ #include <sched.h> #include <signal.h> #include <sys/mman.h> +#include <sys/param.h> #if !SANITIZER_SOLARIS #include <sys/ptrace.h> #endif @@ -68,6 +65,7 @@ #endif #if SANITIZER_OPENBSD #include <sys/futex.h> +#include <sys/sysctl.h> #endif #include <unistd.h> @@ -116,6 +114,9 @@ struct kernel_timeval { // <linux/futex.h> is broken on some linux distributions. const int FUTEX_WAIT = 0; const int FUTEX_WAKE = 1; +const int FUTEX_PRIVATE_FLAG = 128; +const int FUTEX_WAIT_PRIVATE = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; +const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; #endif // SANITIZER_LINUX // Are we using 32-bit or 64-bit Linux syscalls? @@ -149,7 +150,11 @@ extern void internal_sigreturn(); #if SANITIZER_OPENBSD # define SANITIZER_USE_GETENTROPY 1 #else -# define SANITIZER_USE_GETENTROPY 0 +# if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000 +# define SANITIZER_USE_GETENTROPY 1 +# else +# define SANITIZER_USE_GETENTROPY 0 +# endif #endif // SANITIZER_USE_GETENTROPY namespace __sanitizer { @@ -165,14 +170,11 @@ namespace __sanitizer { #endif // --------------- sanitizer_libc.h -#if !SANITIZER_SOLARIS +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD #if !SANITIZER_S390 && !SANITIZER_OPENBSD uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, OFF_T offset) { -#if SANITIZER_NETBSD - return internal_syscall64(SYSCALL(mmap), addr, length, prot, flags, fd, - (long)0, offset); -#elif SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS +#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, offset); #else @@ -186,11 +188,11 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, #if !SANITIZER_OPENBSD uptr internal_munmap(void *addr, uptr length) { - return internal_syscall_ptr(SYSCALL(munmap), (uptr)addr, length); + return internal_syscall(SYSCALL(munmap), (uptr)addr, length); } int internal_mprotect(void *addr, uptr length, int prot) { - return internal_syscall_ptr(SYSCALL(mprotect), (uptr)addr, length, prot); + return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); } #endif @@ -202,7 +204,7 @@ uptr internal_open(const char *filename, int flags) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags); #else - return internal_syscall_ptr(SYSCALL(open), (uptr)filename, flags); + return internal_syscall(SYSCALL(open), (uptr)filename, flags); #endif } @@ -211,32 +213,28 @@ uptr internal_open(const char *filename, int flags, u32 mode) { return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags, mode); #else - return internal_syscall_ptr(SYSCALL(open), (uptr)filename, flags, mode); + return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode); #endif } uptr internal_read(fd_t fd, void *buf, uptr count) { sptr res; - HANDLE_EINTR(res, (sptr)internal_syscall_ptr(SYSCALL(read), fd, (uptr)buf, - count)); + HANDLE_EINTR(res, + (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); return res; } uptr internal_write(fd_t fd, const void *buf, uptr count) { sptr res; - HANDLE_EINTR(res, (sptr)internal_syscall_ptr(SYSCALL(write), fd, (uptr)buf, - count)); + HANDLE_EINTR(res, + (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); return res; } uptr internal_ftruncate(fd_t fd, uptr size) { sptr res; -#if SANITIZER_NETBSD - HANDLE_EINTR(res, internal_syscall64(SYSCALL(ftruncate), fd, 0, (s64)size)); -#else HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, (OFF_T)size)); -#endif return res; } @@ -308,9 +306,8 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { #endif uptr internal_stat(const char *path, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD - return internal_syscall_ptr(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, - 0); +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); @@ -333,9 +330,7 @@ uptr internal_stat(const char *path, void *buf) { } uptr internal_lstat(const char *path, void *buf) { -#if SANITIZER_NETBSD - return internal_syscall_ptr(SYSCALL(lstat), path, buf); -#elif SANITIZER_FREEBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, AT_SYMLINK_NOFOLLOW); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS @@ -360,16 +355,16 @@ uptr internal_lstat(const char *path, void *buf) { } uptr internal_fstat(fd_t fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD || \ SANITIZER_LINUX_USES_64BIT_SYSCALLS -#if SANITIZER_MIPS64 && !SANITIZER_NETBSD && !SANITIZER_OPENBSD +#if SANITIZER_MIPS64 && !SANITIZER_OPENBSD // For mips64, fstat syscall fills buffer in the format of kernel_stat struct kernel_stat kbuf; int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); kernel_stat_to_stat(&kbuf, (struct stat *)buf); return res; # else - return internal_syscall_ptr(SYSCALL(fstat), fd, (uptr)buf); + return internal_syscall(SYSCALL(fstat), fd, (uptr)buf); # endif #else struct stat64 buf64; @@ -386,6 +381,10 @@ uptr internal_filesize(fd_t fd) { return (uptr)st.st_size; } +uptr internal_dup(int oldfd) { + return internal_syscall(SYSCALL(dup), oldfd); +} + uptr internal_dup2(int oldfd, int newfd) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0); @@ -399,10 +398,10 @@ uptr internal_readlink(const char *path, char *buf, uptr bufsize) { return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, bufsize); #elif SANITIZER_OPENBSD - return internal_syscall_ptr(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, - (uptr)buf, bufsize); + return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf, + bufsize); #else - return internal_syscall_ptr(SYSCALL(readlink), path, buf, bufsize); + return internal_syscall(SYSCALL(readlink), path, buf, bufsize); #endif } @@ -410,7 +409,7 @@ uptr internal_unlink(const char *path) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0); #else - return internal_syscall_ptr(SYSCALL(unlink), (uptr)path); + return internal_syscall(SYSCALL(unlink), (uptr)path); #endif } @@ -419,7 +418,7 @@ uptr internal_rename(const char *oldpath, const char *newpath) { return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, (uptr)newpath); #else - return internal_syscall_ptr(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); + return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); #endif } @@ -428,7 +427,7 @@ uptr internal_sched_yield() { } void internal__exit(int exitcode) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD internal_syscall(SYSCALL(exit), exitcode); #else internal_syscall(SYSCALL(exit_group), exitcode); @@ -438,22 +437,24 @@ void internal__exit(int exitcode) { unsigned int internal_sleep(unsigned int seconds) { struct timespec ts; - ts.tv_sec = 1; + ts.tv_sec = seconds; ts.tv_nsec = 0; - int res = internal_syscall_ptr(SYSCALL(nanosleep), &ts, &ts); + int res = internal_syscall(SYSCALL(nanosleep), &ts, &ts); if (res) return ts.tv_sec; return 0; } uptr internal_execve(const char *filename, char *const argv[], char *const envp[]) { - return internal_syscall_ptr(SYSCALL(execve), (uptr)filename, (uptr)argv, - (uptr)envp); + return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, + (uptr)envp); } -#endif // !SANITIZER_SOLARIS +#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD // ----------------- sanitizer_common.h bool FileExists(const char *filename) { + if (ShouldMockFailureToOpen(filename)) + return false; struct stat st; #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS if (internal_syscall(SYSCALL(newfstatat), AT_FDCWD, filename, &st, 0)) @@ -465,6 +466,7 @@ bool FileExists(const char *filename) { return S_ISREG(st.st_mode); } +#if !SANITIZER_NETBSD tid_t GetTid() { #if SANITIZER_FREEBSD long Tid; @@ -472,8 +474,6 @@ tid_t GetTid() { return Tid; #elif SANITIZER_OPENBSD return internal_syscall(SYSCALL(getthrid)); -#elif SANITIZER_NETBSD - return _lwp_self(); #elif SANITIZER_SOLARIS return thr_self(); #else @@ -481,28 +481,43 @@ tid_t GetTid() { #endif } -#if !SANITIZER_SOLARIS +int TgKill(pid_t pid, tid_t tid, int sig) { +#if SANITIZER_LINUX + return internal_syscall(SYSCALL(tgkill), pid, tid, sig); +#elif SANITIZER_FREEBSD + return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig); +#elif SANITIZER_OPENBSD + (void)pid; + return internal_syscall(SYSCALL(thrkill), tid, sig, nullptr); +#elif SANITIZER_SOLARIS + (void)pid; + return thr_kill(tid, sig); +#endif +} +#endif + +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD u64 NanoTime() { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD timeval tv; #else kernel_timeval tv; #endif internal_memset(&tv, 0, sizeof(tv)); - internal_syscall_ptr(SYSCALL(gettimeofday), &tv, 0); + internal_syscall(SYSCALL(gettimeofday), &tv, 0); return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; } uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { - return internal_syscall_ptr(SYSCALL(clock_gettime), clk_id, tp); + return internal_syscall(SYSCALL(clock_gettime), clk_id, tp); } -#endif // !SANITIZER_SOLARIS +#endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD // Like getenv, but reads env directly from /proc (on Linux) or parses the // 'environ' array (on some others) and does not use libc. This function // should be called first inside __asan_init. const char *GetEnv(const char *name) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ SANITIZER_SOLARIS if (::environ != 0) { uptr NameLen = internal_strlen(name); @@ -580,8 +595,8 @@ static void GetArgsAndEnv(char ***argv, char ***envp) { // kern.ps_strings sysctl, which returns a pointer to a structure containing // this information. See also <sys/exec.h>. ps_strings *pss; - size_t sz = sizeof(pss); - if (sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) { + uptr sz = sizeof(pss); + if (internal_sysctlbyname("kern.ps_strings", &pss, &sz, NULL, 0) == -1) { Printf("sysctl kern.ps_strings failed\n"); Die(); } @@ -614,33 +629,13 @@ char **GetArgv() { return argv; } -void ReExec() { +char **GetEnviron() { char **argv, **envp; - const char *pathname = "/proc/self/exe"; - -#if SANITIZER_NETBSD - static const int name[] = { - CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME, - }; - char path[400]; - size_t len; - - len = sizeof(path); - if (sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1) - pathname = path; -#elif SANITIZER_SOLARIS - pathname = getexecname(); - CHECK_NE(pathname, NULL); -#endif - GetArgsAndEnv(&argv, &envp); - uptr rv = internal_execve(pathname, argv, envp); - int rverrno; - CHECK_EQ(internal_iserror(rv, &rverrno), true); - Printf("execve failed, errno %d\n", rverrno); - Die(); + return envp; } -#endif + +#endif // !SANITIZER_OPENBSD #if !SANITIZER_SOLARIS enum MutexState { @@ -664,7 +659,8 @@ void BlockingMutex::Lock() { #elif SANITIZER_NETBSD sched_yield(); /* No userspace futex-like synchronization */ #else - internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0); + internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT_PRIVATE, MtxSleeping, + 0, 0, 0); #endif } } @@ -679,7 +675,7 @@ void BlockingMutex::Unlock() { #elif SANITIZER_NETBSD /* No userspace futex-like synchronization */ #else - internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE, 1, 0, 0, 0); + internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); #endif } } @@ -694,7 +690,9 @@ void BlockingMutex::CheckLocked() { // The actual size of this structure is specified by d_reclen. // Note that getdents64 uses a different structure format. We only provide the // 32-bit syscall here. -#if SANITIZER_NETBSD || SANITIZER_OPENBSD +#if SANITIZER_NETBSD +// Not used +#elif SANITIZER_OPENBSD // struct dirent is different for Linux and us. At this moment, we use only // d_fileno (Linux call this d_ino), d_reclen, and d_name. struct linux_dirent { @@ -721,27 +719,15 @@ struct linux_dirent { }; #endif -#if !SANITIZER_SOLARIS +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD // Syscall wrappers. uptr internal_ptrace(int request, int pid, void *addr, void *data) { -#if SANITIZER_NETBSD - // XXX We need additional work for ptrace: - // - for request, we use PT_FOO whereas Linux uses PTRACE_FOO - // - data is int for us, but void * for Linux - // - Linux sometimes uses data in the case where we use addr instead - // At this moment, this function is used only within - // "#if SANITIZER_LINUX && defined(__x86_64__)" block in - // sanitizer_stoptheworld_linux_libcdep.cc. - return internal_syscall_ptr(SYSCALL(ptrace), request, pid, (uptr)addr, - (uptr)data); -#else return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, (uptr)data); -#endif } uptr internal_waitpid(int pid, int *status, int options) { - return internal_syscall_ptr(SYSCALL(wait4), pid, (uptr)status, options, + return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, 0 /* rusage */); } @@ -759,16 +745,12 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); #else - return internal_syscall_ptr(SYSCALL(getdents), fd, (uptr)dirp, count); + return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); #endif } uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { -#if SANITIZER_NETBSD - return internal_syscall64(SYSCALL(lseek), fd, 0, offset, whence); -#else return internal_syscall(SYSCALL(lseek), fd, offset, whence); -#endif } #if SANITIZER_LINUX @@ -778,7 +760,7 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { #endif uptr internal_sigaltstack(const void *ss, void *oss) { - return internal_syscall_ptr(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); + return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); } int internal_fork() { @@ -789,6 +771,26 @@ int internal_fork() { #endif } +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD +int internal_sysctl(const int *name, unsigned int namelen, void *oldp, + uptr *oldlenp, const void *newp, uptr newlen) { +#if SANITIZER_OPENBSD + return sysctl(name, namelen, oldp, (size_t *)oldlenp, (void *)newp, + (size_t)newlen); +#else + return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp, + (size_t *)oldlenp, newp, (size_t)newlen); +#endif +} + +#if SANITIZER_FREEBSD +int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, + const void *newp, uptr newlen) { + return sysctlbyname(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen); +} +#endif +#endif + #if SANITIZER_LINUX #define SA_RESTORER 0x04000000 // Doesn't set sa_restorer if the caller did not set it, so use with caution @@ -858,8 +860,8 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact) { uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD - return internal_syscall_ptr(SYSCALL(sigprocmask), how, set, oldset); +#if SANITIZER_FREEBSD || SANITIZER_OPENBSD + return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; @@ -897,9 +899,20 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { const uptr bit = signum % (sizeof(k_set->sig[0]) * 8); return k_set->sig[idx] & (1 << bit); } -#endif // SANITIZER_LINUX +#elif SANITIZER_FREEBSD +void internal_sigdelset(__sanitizer_sigset_t *set, int signum) { + sigset_t *rset = reinterpret_cast<sigset_t *>(set); + sigdelset(rset, signum); +} + +bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { + sigset_t *rset = reinterpret_cast<sigset_t *>(set); + return sigismember(rset, signum); +} +#endif #endif // !SANITIZER_SOLARIS +#if !SANITIZER_NETBSD // ThreadLister implementation. ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { char task_directory_path[80]; @@ -986,6 +999,7 @@ ThreadLister::~ThreadLister() { if (!internal_iserror(descriptor_)) internal_close(descriptor_); } +#endif #if SANITIZER_WORDSIZE == 32 // Take care of unusable kernel area in top gigabyte. @@ -996,6 +1010,8 @@ static uptr GetKernelAreaSize() { // Firstly check if there are writable segments // mapped to top gigabyte (e.g. stack). MemoryMappingLayout proc_maps(/*cache_enabled*/true); + if (proc_maps.Error()) + return 0; MemoryMappedSegment segment; while (proc_maps.Next(&segment)) { if ((segment.end >= 3 * gbyte) && segment.IsWritable()) return 0; @@ -1061,18 +1077,25 @@ uptr GetMaxUserVirtualAddress() { return addr; } +#if !SANITIZER_ANDROID uptr GetPageSize() { -// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array. -#if SANITIZER_ANDROID - return 4096; -#elif SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) return EXEC_PAGESIZE; #elif SANITIZER_USE_GETAUXVAL return getauxval(AT_PAGESZ); +#elif SANITIZER_FREEBSD || SANITIZER_NETBSD +// Use sysctl as sysconf can trigger interceptors internally. + int pz = 0; + uptr pzl = sizeof(pz); + int mib[2] = {CTL_HW, HW_PAGESIZE}; + int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); + CHECK_EQ(rv, 0); + return (uptr)pz; #else return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. #endif } +#endif // !SANITIZER_ANDROID #if !SANITIZER_OPENBSD uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { @@ -1088,8 +1111,9 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME}; #endif const char *default_module_name = "kern.proc.pathname"; - size_t Size = buf_len; - bool IsErr = (sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0); + uptr Size = buf_len; + bool IsErr = + (internal_sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0); int readlink_error = IsErr ? errno : 0; uptr module_name_len = Size; #else @@ -1239,7 +1263,7 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, "d"(parent_tidptr), "r"(r8), "r"(r10) - : "rsp", "memory", "r11", "rcx"); + : "memory", "r11", "rcx"); return res; } #elif defined(__mips__) @@ -1631,6 +1655,16 @@ static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size, static atomic_uint32_t android_api_level; +static AndroidApiLevel AndroidDetectApiLevelStatic() { +#if __ANDROID_API__ <= 19 + return ANDROID_KITKAT; +#elif __ANDROID_API__ <= 22 + return ANDROID_LOLLIPOP_MR1; +#else + return ANDROID_POST_LOLLIPOP; +#endif +} + static AndroidApiLevel AndroidDetectApiLevel() { if (!&dl_iterate_phdr) return ANDROID_KITKAT; // K or lower @@ -1643,11 +1677,14 @@ static AndroidApiLevel AndroidDetectApiLevel() { // interesting to detect. } +extern "C" __attribute__((weak)) void* _DYNAMIC; + AndroidApiLevel AndroidGetApiLevel() { AndroidApiLevel level = (AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed); if (level) return level; - level = AndroidDetectApiLevel(); + level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic() + : AndroidDetectApiLevel(); atomic_store(&android_api_level, level, memory_order_relaxed); return level; } @@ -1905,14 +1942,14 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { #elif defined(__sparc__) ucontext_t *ucontext = (ucontext_t*)context; uptr *stk_ptr; -# if defined (__sparcv9) +# if defined(__sparcv9) || defined (__arch64__) # ifndef MC_PC # define MC_PC REG_PC # endif # ifndef MC_O6 # define MC_O6 REG_O6 # endif -# ifdef SANITIZER_SOLARIS +# if SANITIZER_SOLARIS # define mc_gregs gregs # endif *pc = ucontext->uc_mcontext.mc_gregs[MC_PC]; @@ -1946,6 +1983,10 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } +void InitializePlatformEarly() { + // Do nothing. +} + void MaybeReexec() { // No need to re-exec on Linux. } @@ -1954,13 +1995,13 @@ void CheckASLR() { #if SANITIZER_NETBSD int mib[3]; int paxflags; - size_t len = sizeof(paxflags); + uptr len = sizeof(paxflags); mib[0] = CTL_PROC; mib[1] = internal_getpid(); mib[2] = PROC_PID_PAXFLAGS; - if (UNLIKELY(sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { + if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { Printf("sysctl failed\n"); Die(); } @@ -1969,6 +2010,41 @@ void CheckASLR() { Printf("This sanitizer is not compatible with enabled ASLR\n"); Die(); } +#elif SANITIZER_PPC64V2 + // Disable ASLR for Linux PPC64LE. + int old_personality = personality(0xffffffff); + if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) { + VReport(1, "WARNING: Program is being run with address space layout " + "randomization (ASLR) enabled which prevents the thread and " + "memory sanitizers from working on powerpc64le.\n" + "ASLR will be disabled and the program re-executed.\n"); + CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); + ReExec(); + } +#else + // Do nothing +#endif +} + +void CheckMPROTECT() { +#if SANITIZER_NETBSD + int mib[3]; + int paxflags; + uptr len = sizeof(paxflags); + + mib[0] = CTL_PROC; + mib[1] = internal_getpid(); + mib[2] = PROC_PID_PAXFLAGS; + + if (UNLIKELY(internal_sysctl(mib, 3, &paxflags, &len, NULL, 0) == -1)) { + Printf("sysctl failed\n"); + Die(); + } + + if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_MPROTECT)) { + Printf("This sanitizer is not compatible with enabled MPROTECT\n"); + Die(); + } #else // Do nothing #endif |