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


Reply via email to