diff --git a/src/external/darlingserver b/src/external/darlingserver index 71a247e51..7e1dd74cd 160000 --- a/src/external/darlingserver +++ b/src/external/darlingserver @@ -1 +1 @@ -Subproject commit 71a247e51e61808dba7ca216fcb4449e118192a1 +Subproject commit 7e1dd74cd2aca7a188b8c73694e7425dd673da46 diff --git a/src/kernel/emulation/linux/mach/mach_traps.c b/src/kernel/emulation/linux/mach/mach_traps.c index 9ce8eec96..e7007b7fa 100644 --- a/src/kernel/emulation/linux/mach/mach_traps.c +++ b/src/kernel/emulation/linux/mach/mach_traps.c @@ -287,11 +287,8 @@ kern_return_t _kernelrpc_mach_vm_protect_trap_impl( int prot = 0; int ret; - // mach_vm_protect() on a remote process is not trivial to implement - // in a LKM. We simulate success. At the same time, we allow mach_vm_write() - // to work even if the target page is R/O (like ptrace(POKE_DATA)). if (target != 0 && target != mach_task_self()) - return KERN_SUCCESS; + return MACH_SEND_INVALID_DEST; if (new_protection & VM_PROT_READ) prot |= PROT_READ; diff --git a/src/kernel/emulation/linux/process/execve.c b/src/kernel/emulation/linux/process/execve.c index 32957f170..3787c5893 100644 --- a/src/kernel/emulation/linux/process/execve.c +++ b/src/kernel/emulation/linux/process/execve.c @@ -205,7 +205,7 @@ long sys_execve(const char* fname, const char** argvp, const char** envp) linux_sigset_t set; set = (1ull << (SIGNAL_SIGEXC_SUSPEND-1)); - //set |= (1ull << (SIGNAL_SIGEXC_THUPDATE-1)); + set |= (1ull << (SIGNAL_S2C-1)); // darlingserver needs to know whether the execve completes successfully or not. // since pidfds don't notify on execve, we have to use a pipe with close-on-exec diff --git a/src/kernel/emulation/linux/resources/dserver-rpc-defs.h b/src/kernel/emulation/linux/resources/dserver-rpc-defs.h index d8ea7487d..88126a5cd 100644 --- a/src/kernel/emulation/linux/resources/dserver-rpc-defs.h +++ b/src/kernel/emulation/linux/resources/dserver-rpc-defs.h @@ -11,9 +11,12 @@ #include "../elfcalls_wrapper.h" #include "../simple.h" #include "../signal/sigprocmask.h" +#include "../unistd/close.h" #include +#include + #ifndef DSERVER_RPC_HOOKS_ARCHITECTURE #define DSERVER_RPC_HOOKS_ARCHITECTURE 1 enum dserver_rpc_architecture { @@ -111,12 +114,28 @@ retry: .errno_result = 0, }; + if (mmap_call->fd == 0) { + dserver_rpc_hooks_cmsghdr_t* reply_cmsg = DSERVER_RPC_HOOKS_CMSG_FIRSTHDR(out_message); + if (!reply_cmsg || reply_cmsg->cmsg_level != DSERVER_RPC_HOOKS_SOL_SOCKET || reply_cmsg->cmsg_type != DSERVER_RPC_HOOKS_SCM_RIGHTS || reply_cmsg->cmsg_len != DSERVER_RPC_HOOKS_CMSG_LEN(sizeof(int))) { + __simple_printf("Bad S2C call: no FD, but expected one"); + __simple_abort(); + } + dserver_rpc_hooks_memcpy(&mmap_call->fd, DSERVER_RPC_HOOKS_CMSG_DATA(reply_cmsg), sizeof(int)); + } else if (mmap_call->fd != -1) { + __simple_printf("Bad S2C call: invalid FD number"); + __simple_abort(); + } + #ifdef __NR_mmap2 call_ret = (void*)LINUX_SYSCALL(__NR_mmap2, mmap_call->address, mmap_call->length, mmap_call->protection, mmap_call->flags, mmap_call->fd, mmap_call->offset / 4096); #else call_ret = (void*)LINUX_SYSCALL(__NR_mmap, mmap_call->address, mmap_call->length, mmap_call->protection, mmap_call->flags, mmap_call->fd, mmap_call->offset); #endif + if (mmap_call->fd >= 0) { + close_internal(mmap_call->fd); + } + if ((unsigned long)call_ret > (unsigned long)-4096) { // this is actually an errno reply.errno_result = -(int)call_ret; @@ -157,6 +176,38 @@ retry: reply.return_value = call_ret; } +#ifdef __NR_socketcall + ret = LINUX_SYSCALL(__NR_socketcall, LINUX_SYS_SENDTO, ((long[6]) { socket, &reply, sizeof(reply), 0, dserver_rpc_hooks_get_server_address(), dserver_rpc_hooks_get_server_address_length() })); +#else + ret = LINUX_SYSCALL(__NR_sendto, socket, &reply, sizeof(reply), 0, dserver_rpc_hooks_get_server_address(), dserver_rpc_hooks_get_server_address_length()); +#endif + if (ret < 0) { + return ret; + } + } break; + + case dserver_s2c_msgnum_mprotect: { + dserver_s2c_call_mprotect_t* mprotect_call = out_message->msg_iov->iov_base; + int call_ret; + dserver_s2c_reply_mprotect_t reply = { + .header.call_number = 0x52cca11, + .header.pid = dserver_rpc_hooks_get_pid(), + .header.tid = dserver_rpc_hooks_get_tid(), + .header.architecture = dserver_rpc_hooks_get_architecture(), + .header.s2c_number = dserver_s2c_msgnum_mprotect, + .return_value = 0, + .errno_result = 0, + }; + + call_ret = LINUX_SYSCALL3(__NR_mprotect, mprotect_call->address, mprotect_call->length, mprotect_call->protection); + + if (call_ret < 0) { + reply.return_value = -1; + reply.errno_result = -call_ret; + } else { + reply.return_value = call_ret; + } + #ifdef __NR_socketcall ret = LINUX_SYSCALL(__NR_socketcall, LINUX_SYS_SENDTO, ((long[6]) { socket, &reply, sizeof(reply), 0, dserver_rpc_hooks_get_server_address(), dserver_rpc_hooks_get_server_address_length() })); #else @@ -196,8 +247,8 @@ retry: #define dserver_rpc_hooks_atomic_save_t sigset_t static void dserver_rpc_hooks_atomic_begin(dserver_rpc_hooks_atomic_save_t* atomic_save) { - // see sys_disable_threadsignal() - sigset_t set = ~0; + // block standard unix signals (not real-time signals, though) + sigset_t set = 0x7fffffff; sys_sigprocmask(SIG_BLOCK, &set, atomic_save); }; diff --git a/src/kernel/emulation/linux/signal/sigexc.c b/src/kernel/emulation/linux/signal/sigexc.c index 9f5f2bf06..5c293d8c9 100644 --- a/src/kernel/emulation/linux/signal/sigexc.c +++ b/src/kernel/emulation/linux/signal/sigexc.c @@ -69,13 +69,14 @@ static void state_to_kernel(struct linux_ucontext* ctxt, void* tstate, void* fst void sigexc_setup1(void) { handle_rt_signal(SIGNAL_SIGEXC_SUSPEND); + handle_rt_signal(SIGNAL_S2C); } void sigexc_setup2(void) { linux_sigset_t set; set = (1ull << (SIGNAL_SIGEXC_SUSPEND-1)); - //set |= (1ull << (SIGNAL_SIGEXC_THUPDATE-1)); + set |= (1ull << (SIGNAL_S2C-1)); LINUX_SYSCALL(__NR_rt_sigprocmask, 1 /* LINUX_SIG_UNBLOCK */, &set, NULL, sizeof(linux_sigset_t)); @@ -96,7 +97,7 @@ static void handle_rt_signal(int signum) struct linux_sigaction sa; sa.sa_sigaction = (linux_sig_handler*)sigrt_handler; - sa.sa_mask = (1ull << (SIGNAL_SIGEXC_SUSPEND-1)); + sa.sa_mask = (1ull << (SIGNAL_SIGEXC_SUSPEND-1)) | (1ull << (signum-1)); sa.sa_flags = LINUX_SA_RESTORER | LINUX_SA_SIGINFO | LINUX_SA_RESTART | LINUX_SA_ONSTACK; sa.sa_restorer = sig_restorer; @@ -147,6 +148,7 @@ void sigrt_handler(int signum, struct linux_siginfo* info, struct linux_ucontext { dserver_rpc_interrupt_enter(); + if (signum == SIGNAL_SIGEXC_SUSPEND) { #if defined(__x86_64__) x86_thread_state64_t tstate; x86_float_state64_t fstate; @@ -167,6 +169,17 @@ void sigrt_handler(int signum, struct linux_siginfo* info, struct linux_ucontext } state_from_kernel(ctxt, &tstate, &fstate); + } else if (signum == SIGNAL_S2C) { + __simple_kprintf("sigexc: sigrt_handler S2C"); + + int ret = dserver_rpc_s2c_perform(); + if (ret < 0) { + __simple_printf("dserver_rpc_s2c_perform failed internally: %d", ret); + __simple_abort(); + } + } else { + __simple_printf("Unknown/unrecognized real-time signal: %d", signum); + } dserver_rpc_interrupt_exit(); } diff --git a/src/kernel/emulation/linux/signal/sigexc.h b/src/kernel/emulation/linux/signal/sigexc.h index 1c1034828..59b680df9 100644 --- a/src/kernel/emulation/linux/signal/sigexc.h +++ b/src/kernel/emulation/linux/signal/sigexc.h @@ -7,6 +7,7 @@ // NOTE: Keep these definitions up to date with lkm/darling/binfmt.c! // Uses one of the below magic values to toggle the debugging state #define SIGNAL_SIGEXC_SUSPEND LINUX_SIGRTMIN +#define SIGNAL_S2C (LINUX_SIGRTMIN + 1) void sigexc_setup(void); diff --git a/src/startup/mldr/CMakeLists.txt b/src/startup/mldr/CMakeLists.txt index b4b024208..6899cbcaf 100644 --- a/src/startup/mldr/CMakeLists.txt +++ b/src/startup/mldr/CMakeLists.txt @@ -13,6 +13,8 @@ add_library(mldr_dserver_rpc ${CMAKE_BINARY_DIR}/src/external/darlingserver/src/ add_dependencies(mldr_dserver_rpc generate_dserver_rpc_wrappers) target_compile_options(mldr_dserver_rpc PRIVATE -include ${CMAKE_CURRENT_SOURCE_DIR}/resources/dserver-rpc-defs.h) +add_dependencies(mldr_dserver_rpc rtsig_h) +target_include_directories(mldr_dserver_rpc PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..) set(mldr_sources mldr.c @@ -42,6 +44,8 @@ if (BUILD_TARGET_32BIT) target_compile_options(mldr32_dserver_rpc PRIVATE -include ${CMAKE_CURRENT_SOURCE_DIR}/resources/dserver-rpc-defs.h) target_compile_options(mldr32_dserver_rpc PRIVATE -m32) target_link_options(mldr32_dserver_rpc PRIVATE -m32) + add_dependencies(mldr32_dserver_rpc rtsig_h) + target_include_directories(mldr32_dserver_rpc PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..) add_executable(mldr32 ${mldr_sources}) target_compile_options(mldr32 PRIVATE -m32) diff --git a/src/startup/mldr/resources/dserver-rpc-defs.h b/src/startup/mldr/resources/dserver-rpc-defs.h index 1907c6992..cd7196c6d 100644 --- a/src/startup/mldr/resources/dserver-rpc-defs.h +++ b/src/startup/mldr/resources/dserver-rpc-defs.h @@ -10,6 +10,8 @@ #include +#include + #define dserver_rpc_hooks_msghdr_t struct msghdr #define dserver_rpc_hooks_iovec_t struct iovec #define dserver_rpc_hooks_cmsghdr_t struct cmsghdr @@ -91,6 +93,8 @@ extern int __dserver_main_thread_socket_fd; static void dserver_rpc_hooks_atomic_begin(dserver_rpc_hooks_atomic_save_t* atomic_save) { sigset_t set; sigfillset(&set); + sigdelset(&set, LINUX_SIGRTMIN); + sigdelset(&set, LINUX_SIGRTMIN + 1); pthread_sigmask(SIG_BLOCK, &set, atomic_save); };