diff options
Diffstat (limited to 'lib/sanitizer_common/sanitizer_linux.cc')
-rw-r--r-- | lib/sanitizer_common/sanitizer_linux.cc | 395 |
1 files changed, 267 insertions, 128 deletions
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 6c83e8db42a5..96d6c1eff42c 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -15,7 +15,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS + SANITIZER_OPENBSD || SANITIZER_SOLARIS #include "sanitizer_common.h" #include "sanitizer_flags.h" @@ -26,8 +26,6 @@ #include "sanitizer_mutex.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" #if SANITIZER_LINUX #include <asm/param.h> @@ -55,6 +53,7 @@ #include <link.h> #include <pthread.h> #include <sched.h> +#include <signal.h> #include <sys/mman.h> #if !SANITIZER_SOLARIS #include <sys/ptrace.h> @@ -64,7 +63,12 @@ #include <sys/syscall.h> #include <sys/time.h> #include <sys/types.h> +#if !SANITIZER_OPENBSD #include <ucontext.h> +#endif +#if SANITIZER_OPENBSD +#include <sys/futex.h> +#endif #include <unistd.h> #if SANITIZER_LINUX @@ -84,13 +88,12 @@ extern "C" { // FreeBSD 9.2 and 10.0. #include <sys/umtx.h> } -extern char **environ; // provided by crt1 +#include <sys/thr.h> #endif // SANITIZER_FREEBSD #if SANITIZER_NETBSD #include <limits.h> // For NAME_MAX #include <sys/sysctl.h> -extern char **environ; // provided by crt1 #include <sys/exec.h> extern struct ps_strings *__ps_strings; #endif // SANITIZER_NETBSD @@ -98,14 +101,10 @@ extern struct ps_strings *__ps_strings; #if SANITIZER_SOLARIS #include <stdlib.h> #include <thread.h> - -extern char **_environ; #define environ _environ #endif -#if !SANITIZER_ANDROID -#include <sys/signal.h> -#endif +extern char **environ; #if SANITIZER_LINUX // <linux/time.h> @@ -122,8 +121,8 @@ const int FUTEX_WAKE = 1; // Are we using 32-bit or 64-bit Linux syscalls? // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32 // but it still needs to use 64-bit syscalls. -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \ - SANITIZER_WORDSIZE == 64) +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \ + SANITIZER_WORDSIZE == 64) # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 #else # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 @@ -135,6 +134,9 @@ extern void internal_sigreturn(); } #endif +// Note : FreeBSD had implemented both +// Linux and OpenBSD apis, available from +// future 12.x version most likely #if SANITIZER_LINUX && defined(__NR_getrandom) # if !defined(GRND_NONBLOCK) # define GRND_NONBLOCK 1 @@ -144,6 +146,12 @@ extern void internal_sigreturn(); # define SANITIZER_USE_GETRANDOM 0 #endif // SANITIZER_LINUX && defined(__NR_getrandom) +#if SANITIZER_OPENBSD +# define SANITIZER_USE_GETENTROPY 1 +#else +# define SANITIZER_USE_GETENTROPY 0 +#endif // SANITIZER_USE_GETENTROPY + namespace __sanitizer { #if SANITIZER_LINUX && defined(__x86_64__) @@ -158,11 +166,11 @@ namespace __sanitizer { // --------------- sanitizer_libc.h #if !SANITIZER_SOLARIS -#if !SANITIZER_S390 +#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_syscall_ptr(SYSCALL(mmap), addr, length, prot, flags, fd, + return internal_syscall64(SYSCALL(mmap), addr, length, prot, flags, fd, (long)0, offset); #elif SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, @@ -174,8 +182,9 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, offset / 4096); #endif } -#endif // !SANITIZER_S390 +#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD +#if !SANITIZER_OPENBSD uptr internal_munmap(void *addr, uptr length) { return internal_syscall_ptr(SYSCALL(munmap), (uptr)addr, length); } @@ -183,6 +192,7 @@ uptr internal_munmap(void *addr, uptr length) { int internal_mprotect(void *addr, uptr length, int prot) { return internal_syscall_ptr(SYSCALL(mprotect), (uptr)addr, length, prot); } +#endif uptr internal_close(fd_t fd) { return internal_syscall(SYSCALL(close), fd); @@ -298,12 +308,12 @@ 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 - return internal_syscall_ptr(SYSCALL(fstatat), AT_FDCWD, (uptr)path, - (uptr)buf, 0); +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD + return internal_syscall_ptr(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); + return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, + 0); #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS # if defined(__mips64) // For mips64, stat syscall fills buffer in the format of kernel_stat @@ -325,12 +335,12 @@ 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 - return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, - (uptr)buf, AT_SYMLINK_NOFOLLOW); +#elif SANITIZER_FREEBSD || SANITIZER_OPENBSD + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, + AT_SYMLINK_NOFOLLOW); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, - (uptr)buf, AT_SYMLINK_NOFOLLOW); + return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, + AT_SYMLINK_NOFOLLOW); #elif SANITIZER_LINUX_USES_64BIT_SYSCALLS # if SANITIZER_MIPS64 // For mips64, lstat syscall fills buffer in the format of kernel_stat @@ -350,8 +360,9 @@ uptr internal_lstat(const char *path, void *buf) { } uptr internal_fstat(fd_t fd, void *buf) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS -# if SANITIZER_MIPS64 && !SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ + SANITIZER_LINUX_USES_64BIT_SYSCALLS +#if SANITIZER_MIPS64 && !SANITIZER_NETBSD && !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); @@ -385,15 +396,18 @@ uptr internal_dup2(int oldfd, int newfd) { uptr internal_readlink(const char *path, char *buf, uptr bufsize) { #if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS - return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, - (uptr)path, (uptr)buf, 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); #else return internal_syscall_ptr(SYSCALL(readlink), path, buf, bufsize); #endif } uptr internal_unlink(const char *path) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#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); @@ -401,7 +415,7 @@ uptr internal_unlink(const char *path) { } uptr internal_rename(const char *oldpath, const char *newpath) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS || SANITIZER_OPENBSD return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, (uptr)newpath); #else @@ -414,7 +428,7 @@ uptr internal_sched_yield() { } void internal__exit(int exitcode) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD internal_syscall(SYSCALL(exit), exitcode); #else internal_syscall(SYSCALL(exit_group), exitcode); @@ -434,7 +448,7 @@ unsigned int internal_sleep(unsigned int seconds) { uptr internal_execve(const char *filename, char *const argv[], char *const envp[]) { return internal_syscall_ptr(SYSCALL(execve), (uptr)filename, (uptr)argv, - (uptr)envp); + (uptr)envp); } #endif // !SANITIZER_SOLARIS @@ -453,11 +467,15 @@ bool FileExists(const char *filename) { tid_t GetTid() { #if SANITIZER_FREEBSD - return (uptr)pthread_self(); + long Tid; + thr_self(&Tid); + return Tid; +#elif SANITIZER_OPENBSD + return internal_syscall(SYSCALL(getthrid)); #elif SANITIZER_NETBSD return _lwp_self(); #elif SANITIZER_SOLARIS - return (uptr)thr_self(); + return thr_self(); #else return internal_syscall(SYSCALL(gettid)); #endif @@ -465,7 +483,7 @@ tid_t GetTid() { #if !SANITIZER_SOLARIS u64 NanoTime() { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD timeval tv; #else kernel_timeval tv; @@ -484,7 +502,8 @@ uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { // '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_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ + SANITIZER_SOLARIS if (::environ != 0) { uptr NameLen = internal_strlen(name); for (char **Env = ::environ; *Env != 0; Env++) { @@ -522,13 +541,14 @@ const char *GetEnv(const char *name) { #endif } -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD extern "C" { - SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; +SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; } #endif -#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD +#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \ + !SANITIZER_OPENBSD static void ReadNullSepFileToArray(const char *path, char ***arr, int arr_size) { char *buff; @@ -553,6 +573,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr, } #endif +#if !SANITIZER_OPENBSD static void GetArgsAndEnv(char ***argv, char ***envp) { #if SANITIZER_FREEBSD // On FreeBSD, retrieving the argument and environment arrays is done via the @@ -568,11 +589,11 @@ static void GetArgsAndEnv(char ***argv, char ***envp) { *envp = pss->ps_envstr; #elif SANITIZER_NETBSD *argv = __ps_strings->ps_argvstr; - *argv = __ps_strings->ps_envstr; -#else + *envp = __ps_strings->ps_envstr; +#else // SANITIZER_FREEBSD #if !SANITIZER_GO if (&__libc_stack_end) { -#endif +#endif // !SANITIZER_GO uptr* stack_end = (uptr*)__libc_stack_end; int argc = *stack_end; *argv = (char**)(stack_end + 1); @@ -583,8 +604,8 @@ static void GetArgsAndEnv(char ***argv, char ***envp) { ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); } -#endif -#endif +#endif // !SANITIZER_GO +#endif // SANITIZER_FREEBSD } char **GetArgv() { @@ -619,6 +640,7 @@ void ReExec() { Printf("execve failed, errno %d\n", rverrno); Die(); } +#endif #if !SANITIZER_SOLARIS enum MutexState { @@ -672,7 +694,7 @@ 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 +#if SANITIZER_NETBSD || 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 { @@ -825,19 +847,18 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact) { __sanitizer_sigaction u_adjust; internal_memcpy(&u_adjust, act, sizeof(u_adjust)); #if !SANITIZER_ANDROID || !SANITIZER_MIPS32 - if (u_adjust.sa_restorer == nullptr) { - u_adjust.sa_restorer = internal_sigreturn; - } + if (u_adjust.sa_restorer == nullptr) { + u_adjust.sa_restorer = internal_sigreturn; + } #endif - return internal_sigaction_norestorer(signum, (const void *)&u_adjust, - oldact); + return internal_sigaction_norestorer(signum, (const void *)&u_adjust, oldact); } -#endif // defined(__x86_64__) && !SANITIZER_GO +#endif // defined(__x86_64__) && !SANITIZER_GO #endif // SANITIZER_LINUX uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, - __sanitizer_sigset_t *oldset) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD + __sanitizer_sigset_t *oldset) { +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD return internal_syscall_ptr(SYSCALL(sigprocmask), how, set, oldset); #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; @@ -880,71 +901,90 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { #endif // !SANITIZER_SOLARIS // ThreadLister implementation. -ThreadLister::ThreadLister(int pid) - : pid_(pid), - descriptor_(-1), - buffer_(4096), - error_(true), - entry_((struct linux_dirent *)buffer_.data()), - bytes_read_(0) { +ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { char task_directory_path[80]; internal_snprintf(task_directory_path, sizeof(task_directory_path), "/proc/%d/task/", pid); - uptr openrv = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); - if (internal_iserror(openrv)) { - error_ = true; + descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY); + if (internal_iserror(descriptor_)) { Report("Can't open /proc/%d/task for reading.\n", pid); - } else { - error_ = false; - descriptor_ = openrv; } } -int ThreadLister::GetNextTID() { - int tid = -1; - do { - if (error_) - return -1; - if ((char *)entry_ >= &buffer_[bytes_read_] && !GetDirectoryEntries()) - return -1; - if (entry_->d_ino != 0 && entry_->d_name[0] >= '0' && - entry_->d_name[0] <= '9') { - // Found a valid tid. - tid = (int)internal_atoll(entry_->d_name); +ThreadLister::Result ThreadLister::ListThreads( + InternalMmapVector<tid_t> *threads) { + if (internal_iserror(descriptor_)) + return Error; + internal_lseek(descriptor_, 0, SEEK_SET); + threads->clear(); + + Result result = Ok; + for (bool first_read = true;; first_read = false) { + // Resize to max capacity if it was downsized by IsAlive. + buffer_.resize(buffer_.capacity()); + CHECK_GE(buffer_.size(), 4096); + uptr read = internal_getdents( + descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size()); + if (!read) + return result; + if (internal_iserror(read)) { + Report("Can't read directory entries from /proc/%d/task.\n", pid_); + return Error; } - entry_ = (struct linux_dirent *)(((char *)entry_) + entry_->d_reclen); - } while (tid < 0); - return tid; -} -void ThreadLister::Reset() { - if (error_ || descriptor_ < 0) - return; - internal_lseek(descriptor_, 0, SEEK_SET); -} + for (uptr begin = (uptr)buffer_.data(), end = begin + read; begin < end;) { + struct linux_dirent *entry = (struct linux_dirent *)begin; + begin += entry->d_reclen; + if (entry->d_ino == 1) { + // Inode 1 is for bad blocks and also can be a reason for early return. + // Should be emitted if kernel tried to output terminating thread. + // See proc_task_readdir implementation in Linux. + result = Incomplete; + } + if (entry->d_ino && *entry->d_name >= '0' && *entry->d_name <= '9') + threads->push_back(internal_atoll(entry->d_name)); + } -ThreadLister::~ThreadLister() { - if (descriptor_ >= 0) - internal_close(descriptor_); + // Now we are going to detect short-read or early EOF. In such cases Linux + // can return inconsistent list with missing alive threads. + // Code will just remember that the list can be incomplete but it will + // continue reads to return as much as possible. + if (!first_read) { + // The first one was a short-read by definition. + result = Incomplete; + } else if (read > buffer_.size() - 1024) { + // Read was close to the buffer size. So double the size and assume the + // worst. + buffer_.resize(buffer_.size() * 2); + result = Incomplete; + } else if (!threads->empty() && !IsAlive(threads->back())) { + // Maybe Linux early returned from read on terminated thread (!pid_alive) + // and failed to restore read position. + // See next_tid and proc_task_instantiate in Linux. + result = Incomplete; + } + } } -bool ThreadLister::error() { return error_; } - -bool ThreadLister::GetDirectoryEntries() { - CHECK_GE(descriptor_, 0); - CHECK_NE(error_, true); - bytes_read_ = internal_getdents(descriptor_, - (struct linux_dirent *)buffer_.data(), - buffer_.size()); - if (internal_iserror(bytes_read_)) { - Report("Can't read directory entries from /proc/%d/task.\n", pid_); - error_ = true; +bool ThreadLister::IsAlive(int tid) { + // /proc/%d/task/%d/status uses same call to detect alive threads as + // proc_task_readdir. See task_state implementation in Linux. + char path[80]; + internal_snprintf(path, sizeof(path), "/proc/%d/task/%d/status", pid_, tid); + if (!ReadFileToVector(path, &buffer_) || buffer_.empty()) return false; - } else if (bytes_read_ == 0) { + buffer_.push_back(0); + static const char kPrefix[] = "\nPPid:"; + const char *field = internal_strstr(buffer_.data(), kPrefix); + if (!field) return false; - } - entry_ = (struct linux_dirent *)buffer_.data(); - return true; + field += internal_strlen(kPrefix); + return (int)internal_atoll(field) != 0; +} + +ThreadLister::~ThreadLister() { + if (!internal_iserror(descriptor_)) + internal_close(descriptor_); } #if SANITIZER_WORDSIZE == 32 @@ -983,7 +1023,7 @@ static uptr GetKernelAreaSize() { #endif // SANITIZER_WORDSIZE == 32 uptr GetMaxVirtualAddress() { -#if SANITIZER_NETBSD && defined(__x86_64__) +#if (SANITIZER_NETBSD || SANITIZER_OPENBSD) && defined(__x86_64__) return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE) #elif SANITIZER_WORDSIZE == 64 # if defined(__powerpc64__) || defined(__aarch64__) @@ -1034,6 +1074,7 @@ uptr GetPageSize() { #endif } +#if !SANITIZER_OPENBSD uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { #if SANITIZER_SOLARIS const char *default_module_name = getexecname(); @@ -1069,6 +1110,7 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { return module_name_len; #endif } +#endif // !SANITIZER_OPENBSD uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { #if SANITIZER_LINUX @@ -1101,10 +1143,10 @@ bool LibraryNameIs(const char *full_name, const char *base_name) { // Call cb for each region mapped by map. void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) { CHECK_NE(map, nullptr); -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_OPENBSD typedef ElfW(Phdr) Elf_Phdr; typedef ElfW(Ehdr) Elf_Ehdr; -#endif // !SANITIZER_FREEBSD +#endif // !SANITIZER_FREEBSD && !SANITIZER_OPENBSD char *base = (char *)map->l_addr; Elf_Ehdr *ehdr = (Elf_Ehdr *)base; char *phdrs = base + ehdr->e_phoff; @@ -1618,6 +1660,8 @@ static HandleSignalMode GetHandleSignalModeImpl(int signum) { return common_flags()->handle_abort; case SIGILL: return common_flags()->handle_sigill; + case SIGTRAP: + return common_flags()->handle_sigtrap; case SIGFPE: return common_flags()->handle_sigfpe; case SIGSEGV: @@ -1684,21 +1728,78 @@ static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { } #endif +#if SANITIZER_OPENBSD +using Context = sigcontext; +#else +using Context = ucontext_t; +#endif + SignalContext::WriteFlag SignalContext::GetWriteFlag() const { - ucontext_t *ucontext = (ucontext_t *)context; + Context *ucontext = (Context *)context; #if defined(__x86_64__) || defined(__i386__) static const uptr PF_WRITE = 1U << 1; #if SANITIZER_FREEBSD uptr err = ucontext->uc_mcontext.mc_err; #elif SANITIZER_NETBSD uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR]; +#elif SANITIZER_OPENBSD + uptr err = ucontext->sc_err; #elif SANITIZER_SOLARIS && defined(__i386__) -# define ERR 13 - uptr err = ucontext->uc_mcontext.gregs[ERR]; + const int Err = 13; + uptr err = ucontext->uc_mcontext.gregs[Err]; #else uptr err = ucontext->uc_mcontext.gregs[REG_ERR]; -#endif +#endif // SANITIZER_FREEBSD return err & PF_WRITE ? WRITE : READ; +#elif defined(__mips__) + uint32_t *exception_source; + uint32_t faulty_instruction; + uint32_t op_code; + + exception_source = (uint32_t *)ucontext->uc_mcontext.pc; + faulty_instruction = (uint32_t)(*exception_source); + + op_code = (faulty_instruction >> 26) & 0x3f; + + // FIXME: Add support for FPU, microMIPS, DSP, MSA memory instructions. + switch (op_code) { + case 0x28: // sb + case 0x29: // sh + case 0x2b: // sw + case 0x3f: // sd +#if __mips_isa_rev < 6 + case 0x2c: // sdl + case 0x2d: // sdr + case 0x2a: // swl + case 0x2e: // swr +#endif + return SignalContext::WRITE; + + case 0x20: // lb + case 0x24: // lbu + case 0x21: // lh + case 0x25: // lhu + case 0x23: // lw + case 0x27: // lwu + case 0x37: // ld +#if __mips_isa_rev < 6 + case 0x1a: // ldl + case 0x1b: // ldr + case 0x22: // lwl + case 0x26: // lwr +#endif + return SignalContext::READ; +#if __mips_isa_rev == 6 + case 0x3b: // pcrel + op_code = (faulty_instruction >> 19) & 0x3; + switch (op_code) { + case 0x1: // lwpc + case 0x2: // lwupc + return SignalContext::READ; + } +#endif + } + return SignalContext::UNKNOWN; #elif defined(__arm__) static const uptr FSR_WRITE = 1U << 11; uptr fsr = ucontext->uc_mcontext.error_code; @@ -1725,7 +1826,13 @@ void SignalContext::DumpAllRegisters(void *context) { } static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { -#if defined(__arm__) +#if SANITIZER_NETBSD + // This covers all NetBSD architectures + ucontext_t *ucontext = (ucontext_t *)context; + *pc = _UC_MACHINE_PC(ucontext); + *bp = _UC_MACHINE_FP(ucontext); + *sp = _UC_MACHINE_SP(ucontext); +#elif defined(__arm__) ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.arm_pc; *bp = ucontext->uc_mcontext.arm_fp; @@ -1747,11 +1854,11 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.mc_rip; *bp = ucontext->uc_mcontext.mc_rbp; *sp = ucontext->uc_mcontext.mc_rsp; -#elif SANITIZER_NETBSD - ucontext_t *ucontext = (ucontext_t *)context; - *pc = ucontext->uc_mcontext.__gregs[_REG_RIP]; - *bp = ucontext->uc_mcontext.__gregs[_REG_RBP]; - *sp = ucontext->uc_mcontext.__gregs[_REG_RSP]; +#elif SANITIZER_OPENBSD + sigcontext *ucontext = (sigcontext *)context; + *pc = ucontext->sc_rip; + *bp = ucontext->sc_rbp; + *sp = ucontext->sc_rsp; # else ucontext_t *ucontext = (ucontext_t*)context; *pc = ucontext->uc_mcontext.gregs[REG_RIP]; @@ -1764,11 +1871,11 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { *pc = ucontext->uc_mcontext.mc_eip; *bp = ucontext->uc_mcontext.mc_ebp; *sp = ucontext->uc_mcontext.mc_esp; -#elif SANITIZER_NETBSD - ucontext_t *ucontext = (ucontext_t *)context; - *pc = ucontext->uc_mcontext.__gregs[_REG_EIP]; - *bp = ucontext->uc_mcontext.__gregs[_REG_EBP]; - *sp = ucontext->uc_mcontext.__gregs[_REG_ESP]; +#elif SANITIZER_OPENBSD + sigcontext *ucontext = (sigcontext *)context; + *pc = ucontext->sc_eip; + *bp = ucontext->sc_ebp; + *sp = ucontext->sc_esp; # else ucontext_t *ucontext = (ucontext_t*)context; # if SANITIZER_SOLARIS @@ -1843,6 +1950,30 @@ void MaybeReexec() { // No need to re-exec on Linux. } +void CheckASLR() { +#if SANITIZER_NETBSD + int mib[3]; + int paxflags; + size_t 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)) { + Printf("sysctl failed\n"); + Die(); + } + + if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) { + Printf("This sanitizer is not compatible with enabled ASLR\n"); + Die(); + } +#else + // Do nothing +#endif +} + void PrintModuleMap() { } void CheckNoDeepBind(const char *filename, int flag) { @@ -1861,7 +1992,8 @@ void CheckNoDeepBind(const char *filename, int flag) { } uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, - uptr *largest_gap_found) { + uptr *largest_gap_found, + uptr *max_occupied_addr) { UNREACHABLE("FindAvailableMemoryRange is not available"); return 0; } @@ -1869,6 +2001,15 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding, bool GetRandom(void *buffer, uptr length, bool blocking) { if (!buffer || !length || length > 256) return false; +#if SANITIZER_USE_GETENTROPY + uptr rnd = getentropy(buffer, length); + int rverrno = 0; + if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT) + return false; + else if (rnd == 0) + return true; +#endif // SANITIZER_USE_GETENTROPY + #if SANITIZER_USE_GETRANDOM static atomic_uint8_t skip_getrandom_syscall; if (!atomic_load_relaxed(&skip_getrandom_syscall)) { @@ -1881,7 +2022,7 @@ bool GetRandom(void *buffer, uptr length, bool blocking) { else if (res == length) return true; } -#endif // SANITIZER_USE_GETRANDOM +#endif // SANITIZER_USE_GETRANDOM // Up to 256 bytes, a read off /dev/urandom will not be interrupted. // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom. uptr fd = internal_open("/dev/urandom", O_RDONLY); @@ -1896,6 +2037,4 @@ bool GetRandom(void *buffer, uptr length, bool blocking) { } // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || - // SANITIZER_SOLARIS - +#endif |