diff --git a/CMakeLists.txt b/CMakeLists.txt index bcd5b1c..c2bfc23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,8 +127,8 @@ set(GRANARY_SRC_FILES "./granary/base/interrupt.cc" "./granary/os/schedule.cc" "./granary/os/process.cc" - "./granary/os/decree_user/syscall.cc" "./granary/os/decree_user/snapshot.cc" + "./granary/os/decree_user/syscall.cc" "./granary/os/snapshot.cc" "./granary/os/file.cc" "./granary/code/instruction.cc" @@ -168,12 +168,12 @@ set(DUMP_SRC_FILES "./granary/base/breakpoint.cc" "./granary/base/interrupt.cc" "./third_party/xxhash/xxhash.c" - ) + granary/os/user.h) set(PLAY_SRC_FILES "${GRANARY_SRC_DIR}/play.cc" "${GRANARY_SRC_FILES}" - ) + granary/os/user.h) set(SNAPSHOT_SRC_FILES "${GRANARY_SRC_DIR}/snapshot.cc" @@ -181,7 +181,7 @@ set(SNAPSHOT_SRC_FILES "${GRANARY_SRC_DIR}/granary/os/decree_user/snapshot.cc" "${GRANARY_SRC_DIR}/granary/base/breakpoint.cc" "${GRANARY_SRC_DIR}/granary/base/interrupt.cc" -) + granary/os/user.h) # Build the actual executables add_executable(grrplay ${PLAY_SRC_FILES}) @@ -198,5 +198,4 @@ install(TARGETS grrplay grrshot grrcov DESTINATION "${GRANARY_PREFIX_DIR}/bin" PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE - WORLD_READ WORLD_EXECUTE -) + WORLD_READ WORLD_EXECUTE) diff --git a/granary/arch/x86/branch_tracer.S b/granary/arch/x86/branch_tracer.S index 29ae78c..c88a40f 100644 --- a/granary/arch/x86/branch_tracer.S +++ b/granary/arch/x86/branch_tracer.S @@ -1,10 +1,16 @@ /* Copyright 2015 Peter Goodman, all rights reserved. */ +#ifdef __APPLE__ +# define SYMBOL(x) _ ## x +#else +# define SYMBOL(x) x +#endif + .file "granary/arch/x86/branch_tracer.S" .intel_syntax noprefix .text - .extern TraceBranchImpl + .extern SYMBOL(TraceBranchImpl) // r15 os::Process32 * Process32 object. // r14 index::Value Meta-data about this block. @@ -16,9 +22,8 @@ // r8 Addr64 64-bit base of 32-bit address space. // .align 16 - .globl TraceBranch - .type TraceBranch, @function -TraceBranch: + .globl SYMBOL(TraceBranch) +SYMBOL(TraceBranch): .cfi_startproc pushfq @@ -41,7 +46,7 @@ TraceBranch: mov edi, dword ptr [r15 + 52] mov esi, r14d mov edx, r10d - call TraceBranchImpl + call SYMBOL(TraceBranchImpl) pop r15 pop r14 @@ -62,5 +67,4 @@ TraceBranch: ret .cfi_endproc - .size TraceBranch, .-TraceBranch ud2 diff --git a/granary/arch/x86/cache.S b/granary/arch/x86/cache.S index ebcc537..3cfbd47 100644 --- a/granary/arch/x86/cache.S +++ b/granary/arch/x86/cache.S @@ -1,35 +1,39 @@ +/* Copyright 2015 Peter Goodman, all rights reserved. */ + +#ifdef __APPLE__ +# define SYMBOL(x) _ ## x +#else +# define SYMBOL(x) x +#endif .file "granary/arch/x86/cache.S" .intel_syntax noprefix .data -granary_stack_pointer: +SYMBOL(granary_stack_pointer): .quad 0 - .extern gInlineCache + .extern SYMBOL(gInlineCache) // Used to return from the code cache with a bad block. .align 16 - .globl granary_bad_block - .type granary_bad_block, @function -granary_bad_block: + .globl SYMBOL(granary_bad_block) +SYMBOL(granary_bad_block): .cfi_startproc xor r14, r14 not r14 - mov r11, [RIP + granary_stack_pointer] + mov r11, [RIP + SYMBOL(granary_stack_pointer)] sub r11, 8 mov rsp, r11 ret .cfi_endproc - .size _ZN7granary5cache4CallEPNS_2os9Process32EPh, .-_ZN7granary5cache4CallEPNS_2os9Process32EPh ud2 // CachePC cache::Call(os::Process32 *process, CachePC block); .align 16 - .globl _ZN7granary5cache4CallEPNS_2os9Process32EPh; - .type _ZN7granary5cache4CallEPNS_2os9Process32EPh, @function -_ZN7granary5cache4CallEPNS_2os9Process32EPh: + .globl SYMBOL(_ZN7granary5cache4CallEPNS_2os9Process32EPh); +SYMBOL(_ZN7granary5cache4CallEPNS_2os9Process32EPh): .cfi_startproc /* Save the Linux ABI callee-saved regs */ @@ -65,7 +69,7 @@ _ZN7granary5cache4CallEPNS_2os9Process32EPh: /* Don't restore the emulated pc */ // So that we can jump back into the top-level cache call. - mov [RIP + granary_stack_pointer], rsp + mov [RIP + SYMBOL(granary_stack_pointer)], rsp /* Call into the block */ .Lenter_cache: @@ -91,7 +95,12 @@ _ZN7granary5cache4CallEPNS_2os9Process32EPh: mov r11d, dword ptr [r15 + 52] and r11, 0x7ff shl r11, 3 /* Scale by 8 bytes, the size of each entry. */ - lea r11, [r11 + gInlineCache] + + /* Get first probe point into the inline cache. */ + push r12 + lea r12, [RIP + SYMBOL(gInlineCache)] + lea r11, [r11 + r12] + pop r12 #define CHECK_CACHE(entry) \ cmp dword ptr [r11 + (entry * 8)], r10d ; \ @@ -145,5 +154,4 @@ _ZN7granary5cache4CallEPNS_2os9Process32EPh: ret .cfi_endproc - .size _ZN7granary5cache4CallEPNS_2os9Process32EPh, .-_ZN7granary5cache4CallEPNS_2os9Process32EPh ud2 diff --git a/granary/arch/x86/coverage.S b/granary/arch/x86/coverage.S index 7f66b1b..30f772f 100644 --- a/granary/arch/x86/coverage.S +++ b/granary/arch/x86/coverage.S @@ -1,14 +1,20 @@ /* Copyright 2015 Peter Goodman, all rights reserved. */ +#ifdef __APPLE__ +# define SYMBOL(x) _ ## x +#else +# define SYMBOL(x) x +#endif + .file "granary/arch/x86/coverage.S" .intel_syntax noprefix .text - .extern gPathEntries - .extern gNextPathEntry - .extern UpdateCoverageSet - .extern gInputIndex + .extern SYMBOL(gPathEntries) + .extern SYMBOL(gNextPathEntry) + .extern SYMBOL(UpdateCoverageSet) + .extern SYMBOL(gInputIndex) // r15 os::Process32 * Process32 object. // r14 index::Value Meta-data about this block. @@ -25,23 +31,22 @@ // Add an entry to the path coverage list. If the list get full, then // call into UpdateCoverageSet to flush it and reset. .align 16 - .globl CoverPath - .type CoverPath, @function -CoverPath: + .globl SYMBOL(CoverPath) +SYMBOL(CoverPath): .cfi_startproc pushfq // If we haven't read any input then it's not possible to have any // input-dependent code coverage. - cmp qword ptr [RIP + gInputIndex], 0 - jz done + cmp qword ptr [RIP + SYMBOL(gInputIndex)], 0 + jz .Ldone - mov r13d, dword ptr [RIP + gNextPathEntry] + mov r13d, dword ptr [RIP + SYMBOL(gNextPathEntry)] cmp r13, 4096 * 3 * 4 - jz update_coverage_map + jz .Lupdate_coverage_map -add_entry: - lea r11, [RIP + gPathEntries] +.Ladd_entry: + lea r11, [RIP + SYMBOL(gPathEntries)] mov r12d, dword ptr [r15 + 52] // Prev branch EIP mov dword ptr [r11 + r13 + 0], r12d // Prev branch EIP. @@ -50,13 +55,13 @@ add_entry: mov dword ptr [r11 + r13 + 12], 1 // Exec count // Move to the next path entry. - add dword ptr [RIP + gNextPathEntry], 4 * 4 + add dword ptr [RIP + SYMBOL(gNextPathEntry)], 4 * 4 -done: +.Ldone: popfq ret -update_coverage_map: +.Lupdate_coverage_map: push rax push rbx push rcx @@ -79,7 +84,7 @@ update_coverage_map: // push [rsp] // and rsp, -16 - call UpdateCoverageSet + call SYMBOL(UpdateCoverageSet) // pop rsp pop r15 @@ -100,11 +105,10 @@ update_coverage_map: pop rbx pop rax - mov dword ptr [RIP + gNextPathEntry], 0 + mov dword ptr [RIP + SYMBOL(gNextPathEntry)], 0 xor r13, r13 - jmp add_entry + jmp .Ladd_entry .cfi_endproc - .size CoverPath, .-CoverPath ud2 diff --git a/granary/arch/x86/patch.cc b/granary/arch/x86/patch.cc index 099f13e..bb89e96 100644 --- a/granary/arch/x86/patch.cc +++ b/granary/arch/x86/patch.cc @@ -14,6 +14,14 @@ #include +#ifndef MAP_32BIT +# define MAP_32BIT 0 +#endif + +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif + DECLARE_bool(persist); DECLARE_string(persist_dir); diff --git a/granary/arch/x86/process.cc b/granary/arch/x86/process.cc index cb1b876..e904e7d 100644 --- a/granary/arch/x86/process.cc +++ b/granary/arch/x86/process.cc @@ -138,7 +138,11 @@ bool Process32::DoTryRead(const uint8_t *ptr, uint8_t *val) const { bool Process32::RecoverFromTryReadWrite(ucontext_t *context) const { if (!fault_can_recover) return false; fault_can_recover = false; +#ifdef __APPLE__ + auto &pc = context->uc_mcontext->__ss.__rip; +#else auto &pc = context->uc_mcontext.gregs[REG_RIP]; +#endif GRANARY_ASSERT(pc == (pc & ~15LL) && "Crash wasn't in a TryRead/TryWrite."); pc += 16LL; return true; @@ -164,6 +168,18 @@ void Process32::InitRegs(const Snapshot32 *snapshot) { } void Process32::SynchronizeRegState(ucontext_t *context) { +#ifdef __APPLE__ + regs.edi = static_cast(context->uc_mcontext->__ss.__rdi); + regs.esi = static_cast(context->uc_mcontext->__ss.__rsi); + regs.ebp = static_cast(context->uc_mcontext->__ss.__rbp); + regs.ebx = static_cast(context->uc_mcontext->__ss.__rbx); + regs.edx = static_cast(context->uc_mcontext->__ss.__rdx); + regs.ecx = static_cast(context->uc_mcontext->__ss.__rcx); + regs.eax = static_cast(context->uc_mcontext->__ss.__rax); + regs.esp = static_cast(context->uc_mcontext->__ss.__rsp); + regs.eip = static_cast(context->uc_mcontext->__ss.__rip); + regs.eflags = static_cast(context->uc_mcontext->__ss.__rflags); +#else regs.edi = static_cast(context->uc_mcontext.gregs[REG_RDI]); regs.esi = static_cast(context->uc_mcontext.gregs[REG_RSI]); regs.ebp = static_cast(context->uc_mcontext.gregs[REG_RBP]); @@ -174,6 +190,7 @@ void Process32::SynchronizeRegState(ucontext_t *context) { regs.esp = static_cast(context->uc_mcontext.gregs[REG_R9]); regs.eip = static_cast(context->uc_mcontext.gregs[REG_R10]); regs.eflags = static_cast(context->uc_mcontext.gregs[REG_EFL]); +#endif } void Process32::RestoreFPUState(void) const { diff --git a/granary/arch/x86/syscall.S b/granary/arch/x86/syscall.S index bf4948e..20d1313 100644 --- a/granary/arch/x86/syscall.S +++ b/granary/arch/x86/syscall.S @@ -1,17 +1,21 @@ /* Copyright 2015 Peter Goodman, all rights reserved. */ +#ifdef __APPLE__ +# define SYMBOL(x) _ ## x +#else +# define SYMBOL(x) x +#endif + .file "granary/arch/x86/syscall.S" .intel_syntax noprefix .text // NextAppPC32 cache::Call(os::Process32 *process, CachePC block); .align 16 - .globl sys_sigreturn; - .type sys_sigreturn, @function -sys_sigreturn: + .globl SYMBOL(sys_sigreturn); +SYMBOL(sys_sigreturn): .cfi_startproc mov eax, 15 // `__NR_rt_sigreturn`. syscall .cfi_endproc - .size sigreturn, .-sigreturn ud2 diff --git a/granary/code/cache.cc b/granary/code/cache.cc index a32310d..c3a3b99 100644 --- a/granary/code/cache.cc +++ b/granary/code/cache.cc @@ -17,6 +17,21 @@ #include #include +#ifndef MAP_POPULATE +# define MAP_POPULATE 0 +#endif + +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif + +#ifndef MAP_32BIT +# define HAS_MAP32BIT 0 +# define MAP_32BIT 0 +#else +# define HAS_MAP32BIT 1 +#endif + DECLARE_bool(persist); DECLARE_string(persist_dir); @@ -81,25 +96,25 @@ static bool kCacheIsEmpty = true; // Returns the size of the existing cache. static size_t ExistingCacheSize(void) { if (!FLAGS_persist) return 0; - struct stat64 info; - fstat64(gFd, &info); + struct stat info; + fstat(gFd, &info); return static_cast(info.st_size); } // Adds a new page to the end of the code cache. static void ResizeCache(void) { - off64_t offset = 0; + off_t offset = 0; if (FLAGS_persist) { GRANARY_IF_ASSERT( errno = 0; ) - ftruncate64(gFd, static_cast(gCacheSize + os::kPageSize)); + ftruncate(gFd, static_cast(gCacheSize + os::kPageSize)); GRANARY_ASSERT(!errno && "Unable to resize code cache."); - offset = static_cast(gCacheSize); + offset = static_cast(gCacheSize); } GRANARY_IF_ASSERT( errno = 0; ) - mmap64(gEnd, os::kPageSize, PROT_READ | PROT_WRITE | PROT_EXEC, gMMapFlags, - gFd, offset); + mmap(gEnd, os::kPageSize, PROT_READ | PROT_WRITE | PROT_EXEC, gMMapFlags, + gFd, offset); GRANARY_ASSERT(!errno && "Unable to map new end of code cache."); gCacheSize += os::kPageSize; @@ -108,7 +123,7 @@ static void ResizeCache(void) { static void InitInstrumentation(void) { GRANARY_IF_ASSERT( errno = 0; ) - mmap64(gBegin, os::kPageSize, PROT_READ | PROT_WRITE, + mmap(gBegin, os::kPageSize, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0); GRANARY_ASSERT(!errno && "Unable to map instrumentation page."); @@ -153,9 +168,15 @@ void Init(void) { } GRANARY_IF_ASSERT( errno = 0; ) - gBegin = mmap64(nullptr, k250MiB, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_32BIT, - -1, 0); +#if HAS_MAP32BIT + gBegin = mmap(nullptr, k250MiB, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_32BIT, + -1, 0); +#else + gBegin = mmap(reinterpret_cast(0x70000000), k250MiB, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED, + -1, 0); +#endif GRANARY_ASSERT(!errno && "Unable to map address space for code cache."); // The first page of the code cache is for instrumentation. @@ -176,14 +197,14 @@ void Init(void) { // Scale the cache file out to a multiple of the page size so that we can // mmap it. GRANARY_IF_ASSERT( errno = 0; ) - ftruncate64(gFd, static_cast(scaled_cache_size)); + ftruncate(gFd, static_cast(scaled_cache_size)); GRANARY_ASSERT(!errno && "Unable to scale the code cache file."); // Bring the old cache into memory, although scale it out. We'll keep as // many of the original cache pages non-writable, just in case this helps // us to catch spurious bugs. GRANARY_IF_ASSERT( errno = 0; ) - mmap64(gBeginSync, scaled_cache_size, PROT_READ | PROT_WRITE | PROT_EXEC, + mmap(gBeginSync, scaled_cache_size, PROT_READ | PROT_WRITE | PROT_EXEC, gMMapFlags, gFd, 0); GRANARY_ASSERT(!errno && "Unable to map the scaled code cache file."); @@ -198,7 +219,7 @@ void Exit(void) { auto actual_cache_size = gNextBlockPC - gBeginSyncPC; msync(gBeginSync, gCacheSize, MS_SYNC | MS_INVALIDATE); munmap(gBegin, k250MiB); - ftruncate64(gFd, actual_cache_size); + ftruncate(gFd, actual_cache_size); close(gFd); } diff --git a/granary/code/coverage.cc b/granary/code/coverage.cc index 9a2794e..6e013bf 100644 --- a/granary/code/coverage.cc +++ b/granary/code/coverage.cc @@ -20,6 +20,9 @@ #include "third_party/md5/md5.h" +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif DECLARE_bool(path_coverage); DECLARE_string(coverage_file); @@ -149,8 +152,8 @@ void InitPathCoverage(void) { } GRANARY_IF_ASSERT( errno = 0; ) - auto fd = open64(FLAGS_coverage_file.c_str(), - O_RDONLY | O_CLOEXEC | O_CREAT | O_LARGEFILE, 0666); + auto fd = open(FLAGS_coverage_file.c_str(), + O_RDONLY | O_CLOEXEC | O_CREAT | O_LARGEFILE, 0666); GRANARY_ASSERT(!errno && "Unable to open a coverage file."); struct stat file_info; @@ -231,7 +234,7 @@ void ExitPathCoverage(void) { auto cov_file = ss.str(); GRANARY_IF_ASSERT( errno = 0; ) - auto fd = open64( + auto fd = open( cov_file.c_str(), O_RDWR | O_CLOEXEC | O_CREAT | O_LARGEFILE | O_TRUNC, 0666); diff --git a/granary/code/index.cc b/granary/code/index.cc index 3cd348b..6db3e45 100644 --- a/granary/code/index.cc +++ b/granary/code/index.cc @@ -18,6 +18,18 @@ #include "../../third_party/xxhash/xxhash.h" +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif + +#ifndef MAP_POPULATE +# define MAP_POPULATE 0 +#endif + +#ifdef __APPLE__ +typedef off_t off64_t; +#endif + DECLARE_bool(persist); DECLARE_string(persist_dir); @@ -63,8 +75,8 @@ static void ReviveCache(void) { auto fd = open(gIndexPath, O_CREAT | O_RDWR | O_CLOEXEC | O_LARGEFILE, 0666); GRANARY_ASSERT(!errno && "Unable to open persisted code cache index file."); - struct stat64 info; - fstat64(fd, &info); + struct stat info; + fstat(fd, &info); GRANARY_ASSERT(!errno && "Could stat code cache index file."); // Existing file is empty; nothing to revive. @@ -82,11 +94,11 @@ static void ReviveCache(void) { auto scaled_size = (size + os::kPageSize - 1) & os::kPageMask; if (scaled_size > size) { - ftruncate64(fd, static_cast(scaled_size)); + ftruncate(fd, static_cast(scaled_size)); GRANARY_ASSERT(!errno && "Could not scale code cache index file."); } - auto ret = mmap64(nullptr, scaled_size, PROT_READ, - MAP_PRIVATE | MAP_POPULATE, fd, 0); + auto ret = mmap(nullptr, scaled_size, PROT_READ, + MAP_PRIVATE | MAP_POPULATE, fd, 0); GRANARY_ASSERT(!errno && "Could not map code cache index file."); gTable.reserve(num_entries); @@ -117,18 +129,18 @@ void Exit(void) { GRANARY_ASSERT(!errno && "Unable to open persisted code cache index file."); if (gOldIndexExists) { - ftruncate64(fd, 0); + ftruncate(fd, 0); GRANARY_ASSERT(!errno && "Could not clear stale code cache index file."); } auto size = sizeof(Entry) * gTable.size(); auto scaled_size = (size + os::kPageSize - 1) & os::kPageMask; - ftruncate64(fd, static_cast(scaled_size)); + ftruncate(fd, static_cast(scaled_size)); GRANARY_ASSERT(!errno && "Could not scale new code cache index file."); - auto ret = mmap64(nullptr, scaled_size, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); + auto ret = mmap(nullptr, scaled_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); GRANARY_ASSERT(!errno && "Could not map new code cache index file."); // Serialize. @@ -143,7 +155,7 @@ void Exit(void) { // Truncate. if (size < scaled_size) { - ftruncate64(fd, static_cast(size)); + ftruncate(fd, static_cast(size)); GRANARY_ASSERT(!errno && "Could resize new code cache index file."); } } diff --git a/granary/os/decree_user/snapshot.cc b/granary/os/decree_user/snapshot.cc index a1f4f27..63ce4db 100644 --- a/granary/os/decree_user/snapshot.cc +++ b/granary/os/decree_user/snapshot.cc @@ -10,7 +10,9 @@ #include #include #include +#ifndef __APPLE__ #include +#endif #include #include #include @@ -23,6 +25,14 @@ #include #include +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif + +#ifndef MAP_POPULATE +# define MAP_POPULATE 0 +#endif + #include "granary/os/process.h" DECLARE_string(snapshot_dir); @@ -33,18 +43,23 @@ namespace os { namespace { static char gSnapshotPath[128] = {'\0'}; static char gMem[kPageSize] = {'\0'}; -} // namespace + +#ifndef __APPLE__ + +enum { + kMaxNumAttempts = 100 +}; // Copy the memory from one process directly into a memory mapped file. -void SnapshotRange(const detail::MappedRange32 &source_range, int source_fd, - int dest_fd) { +static void SnapshotRange(const detail::MappedRange32 &source_range, + int source_fd, int dest_fd) { auto desired_size = static_cast(source_range.Size()); for (ssize_t copied_size = 0; copied_size < desired_size; ) { auto size = std::min(static_cast(desired_size - copied_size), sizeof gMem); GRANARY_IF_ASSERT( errno = 0; ) - lseek64(source_fd, static_cast(source_range.begin) + copied_size, + lseek(source_fd, static_cast(source_range.begin) + copied_size, SEEK_SET); GRANARY_ASSERT(!errno && "Unable to seek to mapped memory range."); @@ -62,10 +77,6 @@ void SnapshotRange(const detail::MappedRange32 &source_range, int source_fd, } } -namespace { -enum { - kMaxNumAttempts = 100 -}; // Enable tracing of the target binary. static void EnableTracing(void) { @@ -219,27 +230,6 @@ static std::vector GetRanges(pid_t pid, AppPC32 eip) { return ranges; } -// Open the snapshot file. -static int OpenSnapshotFile(int exe_num, bool create) { - sprintf(gSnapshotPath, "%s/grr.snapshot.%d.persist", - FLAGS_snapshot_dir.c_str(), exe_num); - - auto flags = 0; - auto mode = 0; - if (create) { - flags = O_CREAT | O_TRUNC | O_RDWR | O_LARGEFILE; - mode = 0666; - } else { - flags = O_RDONLY | O_LARGEFILE; - } - - GRANARY_IF_ASSERT( errno = 0; ) - auto fd = open(gSnapshotPath, flags, mode); - GRANARY_ASSERT(!errno && "Unable to open the snapshot file."); - - return fd; -} - static char * const gArgv[] = {nullptr}; // Initialize the snapshot file. @@ -257,7 +247,7 @@ static void InitSnapshotFile(const char *exe_name, int exe_num, int fd) { // Align the file handle to the end of the file. GRANARY_IF_ASSERT( errno = 0; ) - ftruncate64(fd, static_cast(sizeof(detail::Snapshot32File))); + ftruncate(fd, static_cast(sizeof(detail::Snapshot32File))); GRANARY_ASSERT(!errno && "Unable to scale snapshot file."); auto file = new (mmap(nullptr, sizeof(detail::Snapshot32File), @@ -338,10 +328,10 @@ static void InitSnapshotFile(const char *exe_name, int exe_num, int fd) { // Align the file handle to the end of the file. GRANARY_IF_ASSERT( errno = 0; ) - ftruncate64(fd, static_cast(sizeof(detail::Snapshot32File))); + ftruncate(fd, static_cast(sizeof(detail::Snapshot32File))); GRANARY_ASSERT(!errno && "Unable to scale snapshot file (1)"); - lseek64(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_END); GRANARY_ASSERT(!errno && "Unable to seek to end of snapshot file (1)"); // Copy the memory into the snapshot file. @@ -352,7 +342,7 @@ static void InitSnapshotFile(const char *exe_name, int exe_num, int fd) { } // Add in the stack and the magic page. - ftruncate64(fd, static_cast(snapshot_offset)); + ftruncate(fd, static_cast(snapshot_offset)); GRANARY_ASSERT(!errno && "Unable to scale snapshot file (2)"); // Clean up. @@ -390,11 +380,11 @@ static std::string CopyExecutableFile(const char *exe_path, int exe_num) { new_path += std::to_string(exe_num); auto path = new_path.c_str(); - auto new_fd = open64(path, O_CREAT | O_CLOEXEC | O_RDWR | O_TRUNC, 0777); + auto new_fd = open(path, O_CREAT | O_CLOEXEC | O_RDWR | O_TRUNC, 0777); GRANARY_ASSERT(!errno && "Could not create copy of the executable."); struct stat64 stat; - fstat64(fd, &stat); + fstat(fd, &stat); GRANARY_ASSERT(!errno && "Could not `fstat` the original executable."); write(new_fd, kELFHeader, kELFHeaderLen); @@ -405,7 +395,7 @@ static std::string CopyExecutableFile(const char *exe_path, int exe_num) { static_cast(stat.st_size - kELFHeaderLen)); GRANARY_ASSERT(!errno && "Could not copy the original executable."); - lseek64(new_fd, 0, SEEK_SET); + lseek(new_fd, 0, SEEK_SET); GRANARY_ASSERT(!errno && "Could not seek to beginning of new executable."); // Make ELF binary executable. @@ -420,6 +410,29 @@ static std::string CopyExecutableFile(const char *exe_path, int exe_num) { return new_path; } +#endif // !defined(__APPLE__) + +// Open the snapshot file. +static int OpenSnapshotFile(int exe_num, bool create) { + sprintf(gSnapshotPath, "%s/grr.snapshot.%d.persist", + FLAGS_snapshot_dir.c_str(), exe_num); + + auto flags = 0; + auto mode = 0; + if (create) { + flags = O_CREAT | O_TRUNC | O_RDWR | O_LARGEFILE; + mode = 0666; + } else { + flags = O_RDONLY | O_LARGEFILE; + } + + GRANARY_IF_ASSERT( errno = 0; ) + auto fd = open(gSnapshotPath, flags, mode); + GRANARY_ASSERT(!errno && "Unable to open the snapshot file."); + + return fd; +} + } // namespace // Revives a snapshot file. @@ -428,7 +441,7 @@ Snapshot32::Snapshot32(int exe_num_) exe_num(exe_num_) { GRANARY_IF_ASSERT( errno = 0; ) file = reinterpret_cast( - mmap64(nullptr, sizeof(detail::Snapshot32File), + mmap(nullptr, sizeof(detail::Snapshot32File), PROT_READ, MAP_POPULATE | MAP_PRIVATE, fd, 0)); GRANARY_ASSERT(!errno && "Unable to map snapshot file meta-data."); GRANARY_ASSERT(file->meta.exe_num == exe_num && @@ -437,11 +450,16 @@ Snapshot32::Snapshot32(int exe_num_) // Creates a snapshot file. void Snapshot32::Create(const char *exe_name, int exe_num) { +#ifdef __APPLE__ + std::cerr << "Cannot create snapshots on macOS\n"; + abort(); +#else auto exe_path = CopyExecutableFile(exe_name, exe_num); auto snapshot_fd = OpenSnapshotFile(exe_num, true); auto exe_path_str = exe_path.c_str(); InitSnapshotFile(exe_path_str, exe_num, snapshot_fd); unlink(exe_path_str); +#endif } // Creates the snapshot from a process. @@ -463,15 +481,15 @@ void Snapshot32::Create(const Process32 *process) { auto temp_snapshot_path = temp_path.c_str(); GRANARY_IF_ASSERT( errno = 0; ) - auto fd = open64(temp_snapshot_path, + auto fd = open(temp_snapshot_path, O_CREAT | O_CLOEXEC | O_RDWR | O_TRUNC, 0666); GRANARY_ASSERT(!errno && "Unable to create snapshot file."); - ftruncate64(fd, static_cast(size)); + ftruncate(fd, static_cast(size)); GRANARY_ASSERT(!errno && "Unable to scale snapshot file."); auto file = reinterpret_cast( - mmap64(nullptr, size, + mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); GRANARY_ASSERT(!errno && "Unable to map snapshot file meta-data."); diff --git a/granary/os/process.cc b/granary/os/process.cc index 3082593..6f99299 100644 --- a/granary/os/process.cc +++ b/granary/os/process.cc @@ -85,8 +85,8 @@ static void DebugRanges(const std::vector &pages, } // namespace Process32::Process32(const Snapshot32 *snapshot) - : base(mmap64(nullptr, kProcessSize, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0)), + : base(mmap(nullptr, kProcessSize, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0)), pid(snapshot->exe_num), text_base(kMaxAddress), fault_can_recover(false), @@ -372,8 +372,8 @@ Addr32 Process32::Allocate(size_t num_bytes, PagePerms perms) { auto addr64 = ConvertAddress(addr32); GRANARY_IF_ASSERT( errno = 0; ) - auto ret = mmap64(addr64, num_bytes, PermsToProt(perms), - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + auto ret = mmap(addr64, num_bytes, PermsToProt(perms), + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); GRANARY_ASSERT(!errno && "Unable to map newly allocated process32 memory."); if (ret != addr64) return 0; diff --git a/granary/os/process.h b/granary/os/process.h index ece32c1..43e6b3f 100644 --- a/granary/os/process.h +++ b/granary/os/process.h @@ -4,14 +4,17 @@ #define GRANARY_OS_PROCESS_H_ #include "granary/os/page.h" +#include "granary/os/user.h" #include #include + +#define _XOPEN_SOURCE #include #include -#include + namespace granary { namespace os { diff --git a/granary/os/schedule.cc b/granary/os/schedule.cc index a744321..95db60a 100644 --- a/granary/os/schedule.cc +++ b/granary/os/schedule.cc @@ -67,7 +67,9 @@ static void signal(int signum, SignalHandler *handler) { struct sigaction sig; sig.sa_sigaction = handler; sig.sa_flags = SA_SIGINFO; +#ifndef __APPLE__ sig.sa_restorer = sys_sigreturn; +#endif sigfillset(&(sig.sa_mask)); sigaction(signum, &sig, nullptr); } @@ -125,7 +127,13 @@ static void CatchFault(int sig, siginfo_t *si, void *context_) { cache::ClearInlineCache(); auto context = reinterpret_cast(context_); - granary_crash_pc = context->uc_mcontext.gregs[REG_RIP]; +#ifdef __APPLE__ + auto &pc_ref = context->uc_mcontext->__ss.__rip; +#else + auto &pc_ref = context->uc_mcontext.gregs[REG_RIP]; +#endif + + granary_crash_pc = pc_ref; granary_crash_addr = reinterpret_cast(si->si_addr); auto process = os::gProcess; @@ -133,8 +141,7 @@ static void CatchFault(int sig, siginfo_t *si, void *context_) { process->signal = sig; const auto fault_addr64 = reinterpret_cast(si->si_addr); - const auto fault_rip64 = static_cast( - context->uc_mcontext.gregs[REG_RIP]); + const auto fault_rip64 = static_cast(pc_ref); GRANARY_ASSERT(process->IsProcessAddress(fault_addr64)); @@ -170,8 +177,8 @@ static void CatchFault(int sig, siginfo_t *si, void *context_) { process->fault_addr = fault_addr32; process->fault_base_addr = base; process->fault_index_addr = index; - context->uc_mcontext.gregs[REG_RIP] = reinterpret_cast( - granary_bad_block); + pc_ref = static_cast( + reinterpret_cast(granary_bad_block)); GRANARY_DEBUG( std::cerr @@ -189,9 +196,14 @@ static void CatchCrash(int sig, siginfo_t *, void *context_) { GRANARY_DEBUG( std::cerr << " CatchCrash " << sig << std::endl; ) auto process = os::gProcess; auto context = reinterpret_cast(context_); +#ifdef __APPLE__ + auto &pc_ref = context->uc_mcontext->__ss.__rip; +#else + auto &pc_ref = context->uc_mcontext.gregs[REG_RIP]; +#endif if (!process) { - granary_crash_pc = context->uc_mcontext.gregs[REG_RIP]; + granary_crash_pc = pc_ref; GRANARY_ASSERT(false && "os::gProcess in CatchCrash is nullptr."); } @@ -202,13 +214,12 @@ static void CatchCrash(int sig, siginfo_t *, void *context_) { return; } - const auto fault_rip64 = static_cast( - context->uc_mcontext.gregs[REG_RIP]); + const auto fault_rip64 = static_cast(pc_ref); // Make sure we faulted within the code cache. GRANARY_ASSERT(cache::IsCachePC(fault_rip64)); - context->uc_mcontext.gregs[REG_RIP] = reinterpret_cast( - granary_bad_block); + pc_ref = static_cast( + reinterpret_cast(granary_bad_block)); } static bool gHasSigHandlers = false; @@ -222,7 +233,9 @@ static struct { int sig; SignalHandler *handler; } gSignalHandlers[] = { {SIGSEGV, CatchFault}, {SIGBUS, CatchCrash}, {SIGFPE, CatchCrash}, +#ifdef SIGSTKFLT {SIGSTKFLT, CatchCrash}, +#endif {SIGTRAP, CatchCrash}, {SIGILL, CatchCrash} }; @@ -268,7 +281,6 @@ static void Schedule(Process32Group &processes, FileTable &files) { PushProcess32 set_process(process); - cache::ClearInlineCache(); // Allows us to repeat system calls that are in-progress. If the diff --git a/granary/os/snapshot.cc b/granary/os/snapshot.cc index 7d11364..c15eae8 100644 --- a/granary/os/snapshot.cc +++ b/granary/os/snapshot.cc @@ -6,6 +6,7 @@ #include #include #include +#include namespace granary { namespace os { @@ -39,8 +40,8 @@ void MappedRange32::CopyFromFileIntoMem(int snapshot_fd, void *mem, } GRANARY_IF_ASSERT( errno = 0; ) - mmap64(mem, Size(), prot, MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE, - snapshot_fd, fd_offs); + mmap(mem, Size(), prot, MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE, + snapshot_fd, fd_offs); GRANARY_ASSERT(!errno && "Failed to copy snapshotted memory into process."); // Deal with lazily allocated pages. diff --git a/granary/os/snapshot.h b/granary/os/snapshot.h index 304f6e6..789e42a 100644 --- a/granary/os/snapshot.h +++ b/granary/os/snapshot.h @@ -4,6 +4,7 @@ #define GRANARY_OS_SNAPSHOT_H_ #include "granary/os/page.h" +#include "granary/os/user.h" #include #include diff --git a/granary/os/user.h b/granary/os/user.h new file mode 100644 index 0000000..cd0ac8c --- /dev/null +++ b/granary/os/user.h @@ -0,0 +1,56 @@ +/* Copyright 2019 Peter Goodman, all rights reserved. */ + +#ifndef GRR_GRANARY_OS_USER_H_ +#define GRR_GRANARY_OS_USER_H_ + +#include +#include + +#ifdef __APPLE__ +struct user_fpregs_struct { + uint16_t cwd; + uint16_t swd; + uint16_t ftw; + uint16_t fop; + uint64_t rip; + uint64_t rdp; + uint32_t mxcsr; + uint32_t mxcr_mask; + uint32_t st_space[32]; + uint32_t xmm_space[64]; + uint32_t padding[24]; +}; + +struct user_regs_struct { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t rbp; + uint64_t rbx; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rsi; + uint64_t rdi; + uint64_t orig_rax; + uint64_t rip; + uint64_t cs; + uint64_t eflags; + uint64_t rsp; + uint64_t ss; + uint64_t fs_base; + uint64_t gs_base; + uint64_t ds; + uint64_t es; + uint64_t fs; + uint64_t gs; +}; + +#endif + +#endif //GRR_GRANARY_OS_USER_H_ diff --git a/play.cc b/play.cc index 3b6fae8..e27578b 100644 --- a/play.cc +++ b/play.cc @@ -29,6 +29,10 @@ #include "third_party/md5/md5.h" +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif + DEFINE_bool(about, false, "Show the compile date of grr."); DEFINE_string(snapshot_dir, "", "Directory where snapshots are stored.");