Skip to content

Commit

Permalink
Fixes issue 1361
Browse files Browse the repository at this point in the history
On Mac, have SYS_mmap invoked by DR use sysenter with no arg encoding in
the syscall number, as this seems to be the only combination that works for
that system call.

SVN-Revision: 2514
derekbruening committed Feb 11, 2014
1 parent 93cae80 commit a84e5c0
Showing 3 changed files with 99 additions and 4 deletions.
20 changes: 16 additions & 4 deletions core/unix/os.c
Original file line number Diff line number Diff line change
@@ -2177,12 +2177,24 @@ mmap_syscall_succeeded(byte *retval)
return !fail;
}

/* N.B.: offs should be in pages for 32-bit Linux */
static inline byte *
mmap_syscall(byte *addr, size_t len, ulong prot, ulong flags, ulong fd, ulong pgoff)
mmap_syscall(byte *addr, size_t len, ulong prot, ulong flags, ulong fd, ulong offs)
{
#ifdef MACOS
/* i#1361: for some reason, mmap only works properly when invoked via sysenter
* and without #args encoded into eax. The worst part is that it doesn't
* fail outright: it returns a success value with the mapping
* showing up when examined externally (e.g., via "vmmap") yet any
* access returns SIGBUS.
*/
return (byte *)(ptr_int_t)
dynamorio_syscall_sysenter(SYS_mmap, 6, addr, len, prot, flags, fd, offs);
#else
return (byte *)(ptr_int_t)
dynamorio_syscall(IF_MACOS_ELSE(SYS_mmap, IF_X64_ELSE(SYS_mmap, SYS_mmap2)), 6,
addr, len, prot, flags, fd, pgoff);
addr, len, prot, flags, fd, offs);
#endif
}

static inline long
@@ -3485,8 +3497,8 @@ os_map_file(file_t f, size_t *size INOUT, uint64 offs, app_pc addr, uint prot,
#endif
map = mmap_syscall(addr, *size, memprot_to_osprot(prot),
flags, f,
/* mmap in X64 uses offset instead of page offset */
IF_X64_ELSE(offs, pg_offs));
/* x86 Linux mmap uses offset in pages */
IF_LINUX_ELSE(IF_X64_ELSE(offs, pg_offs), offs));
if (!mmap_syscall_succeeded(map)) {
LOG(THREAD_GET, LOG_SYSCALLS, 2, "%s failed: "PIFX"\n",
__func__, map);
4 changes: 4 additions & 0 deletions core/x86/arch_exports.h
Original file line number Diff line number Diff line change
@@ -835,6 +835,10 @@ void client_int_syscall(void);
/* Some 32-bit syscalls return 64-bit values (e.g., SYS_lseek) in eax:edx */
int64 dynamorio_syscall(uint sysnum, uint num_args, ...);
int64 dynamorio_mach_dep_syscall(uint sysnum, uint num_args, ...);
# ifndef X64
/* This version only returns 32-bit, and does not encode #args into eax. */
int dynamorio_syscall_sysenter(int sysnum, uint num_args, ...);
# endif
# else
ptr_int_t dynamorio_syscall(uint sysnum, uint num_args, ...);
# endif
79 changes: 79 additions & 0 deletions core/x86/x86.asm
Original file line number Diff line number Diff line change
@@ -1316,6 +1316,85 @@ mach_dep_syscall_success:
END_FUNC(dynamorio_mach_dep_syscall)
# endif /* MACOS */

# if defined(MACOS) && !defined(X64)
/* This version uses sysenter, only returns 32-bit values, and does not
* encode #args into eax. We seem to need this for SYS_mmap (i#1361).
*/
DECLARE_FUNC(dynamorio_syscall_sysenter)
GLOBAL_LABEL(dynamorio_syscall_sysenter:)
/* x64 kernel doesn't clobber all the callee-saved registers */
push REG_XBX /* stack now aligned for x64 */
push REG_XBP
push REG_XSI
push REG_XDI
/* add 16 to skip the 4 pushes */
mov ecx, [16+ 8 + esp] /* num_args */
cmp ecx, 0
je syscall_sysenter_0args
cmp ecx, 1
je syscall_sysenter_1args
cmp ecx, 2
je syscall_sysenter_2args
cmp ecx, 3
je syscall_sysenter_3args
cmp ecx, 4
je syscall_sysenter_4args
cmp ecx, 5
je syscall_sysenter_5args
cmp ecx, 6
je syscall_sysenter_6args
# ifdef INTERNAL
cmp ecx, 7
jg GLOBAL_REF(unexpected_return)
# endif
mov eax, [16+36 + esp] /* arg7 */
syscall_sysenter_6args:
mov ebp, [16+32 + esp] /* arg6 */
syscall_sysenter_5args:
mov edi, [16+28 + esp] /* arg5 */
syscall_sysenter_4args:
mov esi, [16+24 + esp] /* arg4 */
syscall_sysenter_3args:
mov edx, [16+20 + esp] /* arg3 */
syscall_sysenter_2args:
mov ecx, [16+16 + esp] /* arg2 */
syscall_sysenter_1args:
mov ebx, [16+12 + esp] /* arg1 */
syscall_sysenter_0args:
push eax /* 7th arg, if any */
/* As promised, no arg encoding */
mov eax, [20+ 4 + esp] /* sysnum */
/* args are on stack, w/ an extra slot (retaddr of syscall wrapper) */
push ebp
push edi
push esi
push edx
push ecx
push ebx /* aligned to 16 after this push */
push 0 /* extra slot (app retaddr) */
mov ecx, esp
/* If we use ADDRTAKEN_LABEL and GLOBAL_REF we get text relocation
* complaints so we instead do this hack:
*/
call syscall_sysenter_next
syscall_sysenter_next:
pop edx
lea edx, [1/*pop*/ + 3/*lea*/ + 2/*sysenter*/ + edx]
sysenter
lea esp, [8*ARG_SZ + esp] /* must not change flags */
pop REG_XDI
pop REG_XSI
pop REG_XBP
pop REG_XBX
/* return val is in eax for us */
/* convert to -errno */
jae syscall_sysenter_success
neg eax
syscall_sysenter_success:
ret
END_FUNC(dynamorio_syscall_sysenter)
# endif /* defined(MACOS) && !defined(X64) */

/* FIXME: this function should be in #ifdef CLIENT_INTERFACE
* However, the compiler complains about it in
* vps-debug-internal-32 build, so we remove the ifdef now.

0 comments on commit a84e5c0

Please sign in to comment.