aboutsummaryrefslogtreecommitdiff
path: root/lib/sanitizer_common/sanitizer_linux.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sanitizer_common/sanitizer_linux.cc')
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc395
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