Some initial work on ptrace/SIGEXC support

This commit is contained in:
Lubos Dolezel
2017-08-06 20:43:48 +02:00
parent 6d12808302
commit 47b51f004d
11 changed files with 209 additions and 22 deletions
+7 -1
View File
@@ -15,7 +15,11 @@ add_definitions(-DBSDTHREAD_WRAP_LINUX_PTHREAD
include_directories(${CMAKE_SOURCE_DIR}/src/startup)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
# include src/startup for rtsig.h
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/src/startup
)
set(emulation_sources
elfcalls_wrapper.c
@@ -132,6 +136,7 @@ set(emulation_sources
signal/sigprocmask.c
signal/sig_restorer.S
signal/sigsuspend.c
signal/sigexc.c
misc/ptrace.c
misc/getentropy.c
misc/syscall.c
@@ -291,6 +296,7 @@ set_source_files_properties(misc/sysctl.c PROPERTIES COMPILE_FLAGS
add_library(emulation OBJECT ${emulation_sources})
add_library(emulation_dyld OBJECT ${emulation_sources})
set_target_properties(emulation_dyld PROPERTIES COMPILE_FLAGS "-ffunction-sections -DVARIANT_DYLD")
add_dependencies(emulation rtsig_h)
make_fat(emulation)
make_fat(emulation_dyld)
@@ -518,6 +518,8 @@ kern_return_t syscall_thread_switch_impl(
};
// Sleep for 1ms
__linux_nanosleep(&tv, &tv);
// TODO: we could implement this with yield_to() in LKM
return KERN_SUCCESS;
}
+13 -14
View File
@@ -3,6 +3,8 @@
#include "../errno.h"
#include "../signal/duct_signals.h"
#include "../misc/ptrace.h"
#include "../mach/lkm.h"
#include "../../../../lkm/api.h"
#include <sys/signal.h>
#include <stddef.h>
#include <linux-syscalls/linux.h>
@@ -39,21 +41,18 @@ restart:
signal = signum_linux_to_bsd(signal);
*status = (*status & 0x7f) | (signal << 8);
switch (signal)
if (lkm_call(NR_get_tracer, (void*)(long) ret) == getpid())
{
case SIGCONT:
case SIGSTOP:
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
// It is standard behavior that these signals stop (resume) the process
break;
default:
// We are probably ptracing the target process.
// Allow the execution to continue so that the ptraced process can translate
// the signal into a Mach message.
sys_ptrace(PT_CONTINUE, ret, NULL, signal);
goto restart;
// We are ptracing the target process.
// Allow the execution to continue so that the ptraced process can translate
// the signal into a Mach message.
if (signal == SIGSTOP)
{
// TODO: notify target process it has been SIGSTOP'ed via sigqueue
}
sys_ptrace(PT_CONTINUE, ret, NULL, signal);
goto restart;
}
}
@@ -36,7 +36,6 @@
#define LINUX_SIGPWR 30
#define LINUX_SIGSYS 31
#define LINUX_SIGUNUSED 31
#define LINUX_SIGRTMIN 32
#define LINUX_SA_NOCLDSTOP 0x00000001u
#define LINUX_SA_NOCLDWAIT 0x00000002u
#define LINUX_SA_SIGINFO 0x00000004u
+13 -5
View File
@@ -4,9 +4,9 @@
#include "../simple.h"
#include <linux-syscalls/linux.h>
#include <stddef.h>
#include "sigexc.h"
#include "../../../../../platform-include/sys/errno.h"
static void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt);
static int sigflags_bsd_to_linux(int flags);
static int sigflags_linux_to_bsd(int flags);
extern void sig_restorer(void);
@@ -17,7 +17,9 @@ extern void* memset(void* dest, int v, __SIZE_TYPE__ len);
// Libc uses only one trampoline
void (*sa_tramp)(void*, int, int, struct bsd_siginfo*, void*) = 0;
static bsd_sig_handler* sig_handlers[32];
bsd_sig_handler* sig_handlers[32];
int sig_flags[32];
unsigned int sig_masks[32];
long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sigaction* osa)
{
@@ -42,7 +44,11 @@ long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sig
if (nsa != NULL)
{
sa_tramp = nsa->sa_tramp;
if (nsa->sa_sigaction != SIG_DFL && nsa->sa_sigaction != SIG_IGN
if (darling_am_i_ptraced())
{
sa.sa_sigaction = &sigexc_handler;
}
else if (nsa->sa_sigaction != SIG_DFL && nsa->sa_sigaction != SIG_IGN
&& nsa->sa_sigaction != SIG_ERR)
{
sa.sa_sigaction = &handler_linux_to_bsd;
@@ -71,10 +77,12 @@ long sys_sigaction(int signum, const struct bsd___sigaction* nsa, struct bsd_sig
osa->sa_flags = sigflags_linux_to_bsd(olsa.sa_flags);
}
if (nsa != NULL)
if (nsa != NULL && ret >= 0)
{
// __simple_printf("Saving handler for signal %d: %d\n", linux_signum, nsa->sa_sigaction);
sig_handlers[linux_signum] = nsa->sa_sigaction;
sig_flags[linux_signum] = sa.sa_flags;
sig_masks[linux_signum] = sa.sa_mask;
}
return 0;
@@ -120,7 +128,7 @@ static void ucontext_linux_to_bsd(const struct linux_ucontext* lc, struct bsd_uc
#undef copyreg
}
static void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt)
void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt)
{
int bsd_signum;
struct bsd_siginfo binfo;
@@ -51,6 +51,7 @@ struct linux_siginfo
union
{
int _pad[__SI_PAD_SIZE];
unsigned long si_value;
};
};
@@ -194,5 +195,10 @@ struct bsd_ucontext
struct bsd_mcontext* uc_mcontext;
};
void handler_linux_to_bsd(int linux_signum, struct linux_siginfo* info, void* ctxt);
extern bsd_sig_handler* sig_handlers[32];
extern int sig_flags[32];
extern unsigned int sig_masks[32];
#endif
+113
View File
@@ -0,0 +1,113 @@
#include "sigexc.h"
#include "../base.h"
#include <stddef.h>
#include <linux-syscalls/linux.h>
// Support for Darwin debugging.
// Unlike other Unix-like systems, macOS doesn't use wait() to handle events in the debugged process.
static bool am_i_ptraced = false;
static void handle_rt_signal(int signum);
extern void sig_restorer(void);
void darling_sigexc_uninstall(void);
void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt);
void sigexc_setup(void)
{
// Setup handler for SIGNAL_SIGEXC_TOGGLE and SIGNAL_SIGEXC_THUPDATE
handle_rt_signal(SIGNAL_SIGEXC_TOGGLE);
handle_rt_signal(SIGNAL_SIGEXC_THUPDATE);
}
static void handle_rt_signal(int signum)
{
struct linux_sigaction sa;
sa.sa_sigaction = sigrt_handler;
sa.sa_mask = 0;
sa.sa_flags = LINUX_SA_RESTORER | LINUX_SA_SIGINFO | LINUX_SA_RESTART;
sa.sa_restorer = sig_restorer;
LINUX_SYSCALL(__NR_rt_sigaction, signum,
&sa, NULL,
sizeof(sa.sa_mask));
}
bool darling_am_i_ptraced(void)
{
return am_i_ptraced;
}
void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt)
{
if (signum == SIGNAL_SIGEXC_TOGGLE)
{
if (info->si_value == SIGRT_MAGIC_ENABLE_SIGEXC)
{
am_i_ptraced = true;
darling_sigexc_self();
}
else if (info->si_value == SIGRT_MAGIC_DISABLE_SIGEXC)
{
am_i_ptraced = false;
darling_sigexc_uninstall();
}
}
else if (signum == SIGNAL_SIGEXC_THUPDATE)
{
// TODO: Change how a pending signal is handled
// Use TLS?
if (!am_i_ptraced)
return;
}
}
void darling_sigexc_self(void)
{
// Make sigexc_handler the handler for all signals in the process
for (int i = 1; i <= 31; i++)
{
struct linux_sigaction sa;
sa.sa_sigaction = sigrt_handler;
sa.sa_mask = sig_masks[i];
sa.sa_flags = LINUX_SA_RESTORER | LINUX_SA_SIGINFO | LINUX_SA_RESTART;
sa.sa_restorer = sig_restorer;
LINUX_SYSCALL(__NR_rt_sigaction, i,
&sa, NULL,
sizeof(sa.sa_mask));
}
}
void darling_sigexc_uninstall(void)
{
for (int i = 1; i <= 31; i++)
{
struct linux_sigaction sa;
if (sig_handlers[i] == SIG_DFL || sig_handlers[i] != SIG_IGN
|| sig_handlers[i] != SIG_ERR)
{
sa.sa_sigaction = (linux_sig_handler*) sig_handlers[i];
}
else
sa.sa_sigaction = &handler_linux_to_bsd;
sa.sa_mask = sig_masks[i];
sa.sa_flags = sig_flags[i];
sa.sa_restorer = sig_restorer;
LINUX_SYSCALL(__NR_rt_sigaction, i,
&sa, NULL,
sizeof(sa.sa_mask));
}
}
void sigexc_handler(int linux_signum, struct linux_siginfo* info, void* ctxt)
{
// SIGSEGV + SIGBUS -> EXC_BAD_ACCESS
// SIGTRAP -> EXC_BREAKPOINT
// * -> EXC_SOFTWARE with EXC_SOFT_SIGNAL (e.g. SIGSTOP
if (darling_am_i_ptraced())
{
}
}
@@ -0,0 +1,25 @@
#ifndef _SIGEXC_H
#define _SIGEXC_H
#include <stdbool.h>
#include "rtsig.h"
#include "sigaction.h"
#define SIGNAL_SIGEXC_TOGGLE LINUX_SIGRTMIN
#define SIGNAL_SIGEXC_THUPDATE (LINUX_SIGRTMIN + 1)
#define SIGRT_MAGIC_ENABLE_SIGEXC 0xdebdeb01
#define SIGRT_MAGIC_DISABLE_SIGEXC 0xdebdeb00
#define SIGRT_
// Initializes this module
void sigexc_setup(void);
// Is this process currently traced by a debugger?
bool darling_am_i_ptraced(void);
// for PT_SIGEXC to handle this operation synchronously
void darling_sigexc_self(void);
void sigexc_handler(int linux_signum, struct linux_siginfo* info, void* ctxt);
#endif
+1 -1
Submodule src/lkm updated: bb88121f91...622b9032ed
+4
View File
@@ -59,3 +59,7 @@ if (DEFINED WITH_PRINT_WRAPPED_ELF)
add_executable(print_wrapped_elf wrapgen/print_wrapped_elf.cpp)
endif (DEFINED WITH_PRINT_WRAPPED_ELF)
add_executable(rtsig rtsig.c)
add_custom_command(OUTPUT rtsig.h DEPENDS rtsig COMMAND ${CMAKE_CURRENT_BINARY_DIR}/rtsig rtsig.h COMMENT "Determining available RT signals")
add_custom_target(rtsig_h DEPENDS rtsig.h)
+25
View File
@@ -0,0 +1,25 @@
#include <signal.h>
#include <stdio.h>
// Determine RT signal ranges without polluting the build environment with Linux system headers
int main(int argc, char** argv)
{
FILE* output = stdout;
if (argc > 1)
{
output = fopen(argv[1], "w");
if (!output)
{
perror("fopen");
return 1;
}
}
fprintf(output, "#define LINUX_SIGRTMIN %d\n", SIGRTMIN);
fprintf(output, "#define LINUX_SIGRTMAX %d\n", SIGRTMAX);
fclose(output);
return 0;
}