Skip to content

Commit

Permalink
ntdll: Support x86_64 syscall emulation.
Browse files Browse the repository at this point in the history
The patch assigns the range of syscall numbers which does not
overlap with native syscalls and assumes these numbers are
used in the applications (i. e., that the applications
get the number from syscall thunks). Linux specific Seccomp
is used for trapping syscalls.
  • Loading branch information
gofman authored and Guy1524 committed Apr 6, 2020
1 parent f815210 commit be3694d
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 2 deletions.
1 change: 1 addition & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -7436,6 +7436,7 @@ for ac_header in \
linux/joystick.h \
linux/major.h \
linux/param.h \
linux/seccomp.h \
linux/serial.h \
linux/types.h \
linux/ucdrom.h \
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ AC_CHECK_HEADERS(\
linux/joystick.h \
linux/major.h \
linux/param.h \
linux/seccomp.h \
linux/serial.h \
linux/types.h \
linux/ucdrom.h \
Expand Down
90 changes: 90 additions & 0 deletions dlls/ntdll/signal_x86_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "wine/port.h"

#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
Expand Down Expand Up @@ -59,6 +60,13 @@
# include <mach/mach.h>
#endif

#if defined(HAVE_LINUX_FILTER_H) && defined(HAVE_LINUX_SECCOMP_H) && defined(HAVE_SYS_PRCTL_H)
#define HAVE_SECCOMP 1
# include <linux/filter.h>
# include <linux/seccomp.h>
# include <sys/prctl.h>
#endif

#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "ntstatus.h"
Expand Down Expand Up @@ -3096,6 +3104,38 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext )
restore_context( &context, ucontext );
}

extern unsigned int __wine_nb_syscalls;

#ifdef HAVE_SECCOMP
static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
unsigned int thunk_ret_offset;
ucontext_t *ctx = sigcontext;
unsigned int syscall_nr;
void ***rsp;

WARN("SIGSYS, rax %#llx.\n", ctx->uc_mcontext.gregs[REG_RAX]);

syscall_nr = ctx->uc_mcontext.gregs[REG_RAX] - 0xf000;
if (syscall_nr >= __wine_nb_syscalls)
{
ERR("Syscall %u is undefined.\n", syscall_nr);
return;
}

rsp = (void ***)&ctx->uc_mcontext.gregs[REG_RSP];
*rsp -= 1;

#ifdef __APPLE__
thunk_ret_offset = 0xb;
#else
thunk_ret_offset = 0xc;
#endif

**rsp = (void *)(ctx->uc_mcontext.gregs[REG_RIP] + thunk_ret_offset);
ctx->uc_mcontext.gregs[REG_RIP] = (ULONG64)__wine_syscall_dispatcher;
}
#endif

/***********************************************************************
* __wine_set_signal_handler (NTDLL.@)
Expand Down Expand Up @@ -3266,6 +3306,53 @@ void signal_init_thread( TEB *teb )
#endif
}

static void install_bpf(struct sigaction *sig_act)
{
#ifdef HAVE_SECCOMP
static struct sock_filter filter[] =
{
BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
(offsetof(struct seccomp_data, nr))),
BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0xf000, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
};
struct sock_fprog prog;
int ret;

memset(&prog, 0, sizeof(prog));
prog.len = ARRAY_SIZE(filter);
prog.filter = filter;

if (!(ret = prctl(PR_GET_SECCOMP, 0, NULL, 0, 0)))
{
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
{
perror("prctl(PR_SET_NO_NEW_PRIVS, ...)");
exit(1);
}

if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog, 0, 0))
{
perror("prctl(PR_SET_SECCOMP, ...)");
exit(1);
}
}
else
{
if (ret == 2)
TRACE("Seccomp filters already installed.\n");
else
ERR("Seccomp filters cannot be installed, ret %d, error %s.\n", ret, strerror(errno));
}

sig_act->sa_sigaction = sigsys_handler;
sigaction(SIGSYS, sig_act, NULL);
#else
WARN("Built without seccomp.\n");
#endif
}

/**********************************************************************
* signal_init_process
*/
Expand Down Expand Up @@ -3298,6 +3385,9 @@ void signal_init_process(void)
sig_act.sa_sigaction = trap_handler;
if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
#endif

install_bpf(&sig_act);

return;

error:
Expand Down
3 changes: 3 additions & 0 deletions include/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,9 @@
/* Define to 1 if you have the <linux/rtnetlink.h> header file. */
#undef HAVE_LINUX_RTNETLINK_H

/* Define to 1 if you have the <linux/seccomp.h> header file. */
#undef HAVE_LINUX_SECCOMP_H

/* Define to 1 if you have the <linux/serial.h> header file. */
#undef HAVE_LINUX_SERIAL_H

Expand Down
9 changes: 7 additions & 2 deletions tools/winebuild/spec32.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ static void output_syscall_thunks_x64( DLLSPEC *spec )
output_cfi( ".cfi_startproc" );
output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* mov r10, rcx */
output( "\t.byte 0xb8\n" ); /* mov eax, SYSCALL */
output( "\t.long %d\n", i );
output( "\t.long %d\n", i + 0xf000 );
output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* test byte ptr [0x7ffe0308], 1 */
output( "\t.byte 0x75,0x03\n" ); /* jne (over syscall) */
output( "\t.byte 0x0f,0x05\n" ); /* syscall */
Expand Down Expand Up @@ -576,6 +576,9 @@ static void output_syscall_thunks_x64( DLLSPEC *spec )
output( "\t.byte %d\n", max(get_args_size(odp), 32) - 32 );
}

output( "%s\n", asm_globl("__wine_nb_syscalls") );
output( "\t.long %u\n", spec->nb_syscalls );

output( "\n/* syscall dispatcher */\n\n" );
output( "\t.text\n" );
output( "\t.align %d\n", get_alignment(16) );
Expand All @@ -601,6 +604,8 @@ static void output_syscall_thunks_x64( DLLSPEC *spec )
else
output( "\tsubq $0xc,0x8(%%rbp)\n" );

output( "\tsub $0xf000,%%rax\n" );

/* copy over any arguments on the stack */
output( "\tleaq 0x38(%%rbp),%%rsi\n" );
if (UsePIC)
Expand Down Expand Up @@ -1233,7 +1238,7 @@ static void create_stub_exports_text_x64( DLLSPEC *spec )
align_output_rva( 16, 16 );
put_label( odp->link_name );
put_byte( 0x4c ); put_byte( 0x8b ); put_byte( 0xd1 ); /* mov r10, rcx */
put_byte( 0xb8 ); put_dword( i ); /* mov eax, SYSCALL */
put_byte( 0xb8 ); put_dword( i + 0xf000 ); /* mov eax, SYSCALL */
put_byte( 0xf6 ); put_byte( 0x04 ); put_byte( 0x25 ); /* test byte ptr [0x7ffe0308], 1 */
put_byte( 0x08 ); put_byte( 0x03 ); put_byte( 0xfe );
put_byte( 0x7f ); put_byte( 0x01 );
Expand Down

0 comments on commit be3694d

Please sign in to comment.