There are some situations where the guest application changes the SIGSEGV and messes with qemu-user way of handling self-modifying code.
In case of qemu-system, this happens. Emulation of qemu-system inside qemu-user doesn't work because of this. This patch doesn't aim to do a complete signal protection and achieve bulletproof signal management for every test case, instead it is a small easy-to-understand patch that resolves the most common problem. Signed-off-by: Alex Barcelo <abarc...@ac.upc.edu> --- linux-user/syscall.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 6257a04..95bb818 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -5897,6 +5897,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif + +/* + * Use SETSIGNAL and GETSIGNAL macros for SIGSEGV protection. + * + * This should protect SIGSEGV unconscious manipulations from guest apps + * (but we still do not let the emulated software play the signal game) + */ +#define SETSIGNAL(set) sigdelset( (set), SIGSEGV) +#define GETSIGNAL(get) sigaddset( (get), SIGSEGV) + #ifdef TARGET_NR_sigprocmask case TARGET_NR_sigprocmask: { @@ -5952,6 +5962,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, target_to_host_old_sigset(&set, p); unlock_user(p, arg2, 0); set_ptr = &set; + // override SIGSEGV when changing mask + SETSIGNAL(set_ptr); } else { how = 0; set_ptr = NULL; @@ -5960,6 +5972,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!is_error(ret) && arg3) { if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) goto efault; + // ignore real SIGSEGV state in mask + GETSIGNAL(&oldset); host_to_target_old_sigset(p, &oldset); unlock_user(p, arg3, sizeof(target_sigset_t)); } @@ -5992,6 +6006,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, target_to_host_sigset(&set, p); unlock_user(p, arg2, 0); set_ptr = &set; + // override SIGSEGV when changing mask + SETSIGNAL(set_ptr); } else { how = 0; set_ptr = NULL; @@ -6001,6 +6017,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_sigset_t), 0))) goto efault; host_to_target_sigset(p, &oldset); + // ignore real SIGSEGV state in mask + GETSIGNAL(&oldset); unlock_user(p, arg3, sizeof(target_sigset_t)); } } -- 1.7.5.4