qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 14/16] [RFC] linux-user: add functionality for track


From: Miloš Stojanović
Subject: [Qemu-devel] [PATCH 14/16] [RFC] linux-user: add functionality for tracking target signal mask
Date: Fri, 12 May 2017 13:02:22 +0200

Add support for tracking the larger target signal mask in system calls
sigprocmask()/rt_sigprocmask(), sigsuspend()/rt_sigsuspend(),
sgetmask()/ssetmask() and in functions do_sigreturn(), do_rt_sigreturn(),
handle_pending_signal(), process_pending_signals().
Add a new function do_target_sigprocmask() which is based on
do_sigprocmask() and extends its functionallity.

It can happen that the host machine has a smaller range of signals
compared to the target machine that it's emulating. Currently the signals
that are in the target range but out of the host range are treated like
faulty signals and can't be used. In this patch, support is added for
tracking the target signal mask, alongside and in the same manner as the
host signal mask.

Signed-off-by: Miloš Stojanović <address@hidden>
---
 linux-user/qemu.h    |   5 ++
 linux-user/signal.c  | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 linux-user/syscall.c |  94 ++++++++++++++++++++++++++++++++++++
 3 files changed, 229 insertions(+), 1 deletion(-)

diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 6ce0811..bf13db6 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -395,6 +395,11 @@ long do_sigreturn(CPUArchState *env);
 long do_rt_sigreturn(CPUArchState *env);
 abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
 int do_sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
+#ifdef TRACK_TARGET_SIGMASK
+int do_target_sigprocmask(int how, const target_sigset_t *target_set,
+                          target_sigset_t *target_oldset,
+                          const sigset_t *set, sigset_t *oldset);
+#endif
 /**
  * block_signals: block all signals while handling this guest syscall
  *
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 0c1e231..9d4ad43 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -296,17 +296,85 @@ int do_sigprocmask(int how, const sigset_t *set, sigset_t 
*oldset)
     return 0;
 }
 
+#ifdef TRACK_TARGET_SIGMASK
+int do_target_sigprocmask(int how, const target_sigset_t *target_set,
+                          target_sigset_t *target_oldset,
+                          const sigset_t *set, sigset_t *oldset)
+{
+    TaskState *ts = (TaskState *)thread_cpu->opaque;
+
+    if (target_oldset) {
+        *target_oldset = ts->target_signal_mask;
+    }
+    if (oldset) {
+        *oldset = ts->signal_mask;
+    }
+
+    if (target_set && set) {
+        int i;
+
+        if (block_signals()) {
+            return -TARGET_ERESTARTSYS;
+        }
+
+        switch (how) {
+        case SIG_BLOCK:
+            target_sigorset(&ts->target_signal_mask, &ts->target_signal_mask,
+                            target_set);
+            sigorset(&ts->signal_mask, &ts->signal_mask, set);
+            break;
+        case SIG_UNBLOCK:
+            for (i = 1; i <= TARGET_NSIG; ++i) {
+                if (target_sigismember(target_set, i) == 1) {
+                    target_sigdelset(&ts->target_signal_mask, i);
+                }
+            }
+            for (i = 1; i <= NSIG; ++i) {
+                if (sigismember(set, i) == 1) {
+                    sigdelset(&ts->signal_mask, i);
+                }
+            }
+            break;
+        case SIG_SETMASK:
+            ts->target_signal_mask = *target_set;
+            ts->signal_mask = *set;
+            break;
+        default:
+            g_assert_not_reached();
+        }
+
+        /* Silently ignore attempts to change blocking status of KILL or STOP 
*/
+        target_sigdelset(&ts->target_signal_mask, SIGKILL);
+        target_sigdelset(&ts->target_signal_mask, SIGSTOP);
+        sigdelset(&ts->signal_mask, SIGKILL);
+        sigdelset(&ts->signal_mask, SIGSTOP);
+    }
+    return 0;
+}
+#endif
+
 #if !defined(TARGET_OPENRISC) && !defined(TARGET_UNICORE32) && \
     !defined(TARGET_NIOS2)
 /* Just set the guest's signal mask to the specified value; the
  * caller is assumed to have called block_signals() already.
  */
+#ifndef TRACK_TARGET_SIGMASK
 static void set_sigmask(const sigset_t *set)
 {
     TaskState *ts = (TaskState *)thread_cpu->opaque;
 
     ts->signal_mask = *set;
 }
+#else
+static void target_set_sigmask(const sigset_t *set,
+                               const target_sigset_t *target_set)
+{
+    TaskState *ts = (TaskState *)thread_cpu->opaque;
+
+    ts->signal_mask = *set;
+    ts->target_signal_mask = *target_set;
+}
+#endif
 #endif
 
 /* siginfo conversion */
@@ -3315,6 +3383,9 @@ long do_sigreturn(CPUMIPSState *regs)
     abi_ulong frame_addr;
     sigset_t blocked;
     target_sigset_t target_set;
+#ifdef TRACK_TARGET_SIGMASK
+    target_sigset_t target_blocked;
+#endif
     int i;
 
     frame_addr = regs->active_tc.gpr[29];
@@ -3327,7 +3398,12 @@ long do_sigreturn(CPUMIPSState *regs)
     }
 
     target_to_host_sigset_internal(&blocked, &target_set);
+#ifdef TRACK_TARGET_SIGMASK
+    tswapal_target_sigset(&target_blocked, &target_set);
+    target_set_sigmask(&blocked, &target_blocked);
+#else
     set_sigmask(&blocked);
+#endif
 
     restore_sigcontext(regs, &frame->sf_sc);
 
@@ -3423,6 +3499,9 @@ long do_rt_sigreturn(CPUMIPSState *env)
     struct target_rt_sigframe *frame;
     abi_ulong frame_addr;
     sigset_t blocked;
+#ifdef TRACK_TARGET_SIGMASK
+    target_sigset_t target_blocked;
+#endif
 
     frame_addr = env->active_tc.gpr[29];
     trace_user_do_rt_sigreturn(env, frame_addr);
@@ -3431,7 +3510,12 @@ long do_rt_sigreturn(CPUMIPSState *env)
     }
 
     target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
+#ifdef TRACK_TARGET_SIGMASK
+    tswapal_target_sigset(&target_blocked, &frame->rs_uc.tuc_sigmask);
+    target_set_sigmask(&blocked, &target_blocked);
+#else
     set_sigmask(&blocked);
+#endif
 
     restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
 
@@ -6574,6 +6658,9 @@ static void handle_pending_signal(CPUArchState *cpu_env, 
int sig,
     abi_ulong handler;
     sigset_t set;
     target_sigset_t target_old_set;
+#ifdef TRACK_TARGET_SIGMASK
+    target_sigset_t target_set;
+#endif
     struct target_sigaction *sa;
     TaskState *ts = cpu->opaque;
 
@@ -6611,21 +6698,39 @@ static void handle_pending_signal(CPUArchState 
*cpu_env, int sig,
     } else {
         /* compute the blocked signals during the handler execution */
         sigset_t *blocked_set;
+#ifdef TRACK_TARGET_SIGMASK
+        target_sigset_t *target_blocked_set;
 
+        tswapal_target_sigset(&target_set, &sa->sa_mask);
+#endif
         target_to_host_sigset(&set, &sa->sa_mask);
         /* SA_NODEFER indicates that the current signal should not be
            blocked during the handler */
-        if (!(sa->sa_flags & TARGET_SA_NODEFER))
+        if (!(sa->sa_flags & TARGET_SA_NODEFER)) {
+#ifdef TRACK_TARGET_SIGMASK
+            target_sigaddset(&target_set, sig);
+#endif
             sigaddset(&set, target_to_host_signal(sig));
+        }
 
         /* save the previous blocked signal state to restore it at the
            end of the signal execution (see do_sigreturn) */
+#ifdef TRACK_TARGET_SIGMASK
+        target_old_set = ts->target_signal_mask;
+#else
         host_to_target_sigset_internal(&target_old_set, &ts->signal_mask);
+#endif
 
         /* block signals in the handler */
         blocked_set = ts->in_sigsuspend ?
             &ts->sigsuspend_mask : &ts->signal_mask;
         sigorset(&ts->signal_mask, blocked_set, &set);
+#ifdef TRACK_TARGET_SIGMASK
+        target_blocked_set = ts->in_sigsuspend ?
+            &ts->target_sigsuspend_mask : &ts->target_signal_mask;
+        target_sigorset(&ts->target_signal_mask, target_blocked_set,
+                        &target_set);
+#endif
         ts->in_sigsuspend = 0;
 
         /* if the CPU is in VM86 mode, we restore the 32 bit values */
@@ -6661,7 +6766,11 @@ void process_pending_signals(CPUArchState *cpu_env)
     int sig;
     TaskState *ts = cpu->opaque;
     sigset_t set;
+#ifdef TRACK_TARGET_SIGMASK
+    target_sigset_t *target_blocked_set;
+#else
     sigset_t *blocked_set;
+#endif
 
     while (atomic_read(&ts->signal_pending)) {
         /* FIXME: This is not threadsafe.  */
@@ -6679,22 +6788,42 @@ void process_pending_signals(CPUArchState *cpu_env)
              * to block a synchronous signal since it could then just end up
              * looping round and round indefinitely.
              */
+#ifdef TRACK_TARGET_SIGMASK
+            if (sigismember(&ts->signal_mask, target_to_host_signal(sig)) == 1
+                || target_sigismember(&ts->target_signal_mask, sig) == 1
+                || sigact_table[sig - 1]._sa_handler == TARGET_SIG_IGN) {
+                sigdelset(&ts->signal_mask, target_to_host_signal(sig));
+                target_sigdelset(&ts->target_signal_mask, sig);
+                sigact_table[sig - 1]._sa_handler = TARGET_SIG_DFL;
+            }
+#else
             if (sigismember(&ts->signal_mask, target_to_host_signal_table[sig])
                 || sigact_table[sig - 1]._sa_handler == TARGET_SIG_IGN) {
                 sigdelset(&ts->signal_mask, target_to_host_signal_table[sig]);
                 sigact_table[sig - 1]._sa_handler = TARGET_SIG_DFL;
             }
+#endif
 
             handle_pending_signal(cpu_env, sig, &ts->sync_signal);
         }
 
         for (sig = 1; sig <= TARGET_NSIG; sig++) {
+#ifdef TRACK_TARGET_SIGMASK
+            target_blocked_set = ts->in_sigsuspend ?
+                &ts->target_sigsuspend_mask : &ts->target_signal_mask;
+#else
             blocked_set = ts->in_sigsuspend ?
                 &ts->sigsuspend_mask : &ts->signal_mask;
+#endif
 
+#ifdef TRACK_TARGET_SIGMASK
+            if (ts->sigtab[sig - 1].pending &&
+                (!target_sigismember(target_blocked_set, sig))) {
+#else
             if (ts->sigtab[sig - 1].pending &&
                 (!sigismember(blocked_set,
                               target_to_host_signal_table[sig]))) {
+#endif
                 handle_pending_signal(cpu_env, sig, &ts->sigtab[sig - 1]);
                 /* Restart scan from the beginning, as handle_pending_signal
                  * might have resulted in a new synchronous signal (eg 
SIGSEGV).
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 94ecae3..f4ce6a8 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8585,6 +8585,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
 #ifdef TARGET_NR_sgetmask /* not on alpha */
     case TARGET_NR_sgetmask:
         {
+#ifdef TRACK_TARGET_SIGMASK
+            sigset_t cur_set;
+            target_sigset_t target_set_mask;
+            abi_ulong target_set;
+            ret = do_target_sigprocmask(0, NULL, &target_set_mask,
+                                        NULL, &cur_set);
+            if (!ret) {
+                target_to_abi_ulong_old_sigset(&target_set, &target_set_mask);
+                ret = target_set;
+            }
+#else
             sigset_t cur_set;
             abi_ulong target_set;
             ret = do_sigprocmask(0, NULL, &cur_set);
@@ -8592,12 +8603,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
                 host_to_target_old_sigset(&target_set, &cur_set);
                 ret = target_set;
             }
+#endif
         }
         break;
 #endif
 #ifdef TARGET_NR_ssetmask /* not on alpha */
     case TARGET_NR_ssetmask:
         {
+#ifdef TRACK_TARGET_SIGMASK
+            sigset_t set, oset;
+            target_sigset_t target_set_mask, target_oset;
+            abi_ulong target_set = arg1;
+            target_to_host_old_sigset(&set, &target_set);
+            abi_ulong_to_target_old_sigset(&target_set_mask, &target_set);
+            ret = do_target_sigprocmask(SIG_SETMASK, &target_set_mask,
+                                        &target_oset, &set, &oset);
+            if (!ret) {
+                target_to_abi_ulong_old_sigset(&target_set, &target_oset);
+                ret = target_set;
+            }
+#else
             sigset_t set, oset;
             abi_ulong target_set = arg1;
             target_to_host_old_sigset(&set, &target_set);
@@ -8606,6 +8631,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
                 host_to_target_old_sigset(&target_set, &oset);
                 ret = target_set;
             }
+#endif
         }
         break;
 #endif
@@ -8614,6 +8640,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         {
 #if defined(TARGET_ALPHA)
             sigset_t set, oldset;
+#ifdef TRACK_TARGET_SIGMASK
+            target_sigset_t target_set, target_oldset;
+#endif
             abi_ulong mask;
             int how;
 
@@ -8634,14 +8663,26 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
             mask = arg2;
             target_to_host_old_sigset(&set, &mask);
 
+#ifdef TRACK_TARGET_SIGMASK
+            abi_ulong_to_target_old_sigset(&target_set, &mask);
+
+            ret = do_target_sigprocmask(how, &target_set, &target_oldset,
+                                        &set, &oldset);
+            if (!is_error(ret)) {
+                target_to_abi_ulong_old_sigset(&mask, &target_oldset);
+#else
             ret = do_sigprocmask(how, &set, &oldset);
             if (!is_error(ret)) {
                 host_to_target_old_sigset(&mask, &oldset);
+#endif
                 ret = mask;
                 ((CPUAlphaState *)cpu_env)->ir[IR_V0] = 0; /* force no error */
             }
 #else
             sigset_t set, oldset, *set_ptr;
+#ifdef TRACK_TARGET_SIGMASK
+            target_sigset_t target_set, target_oldset, *target_set_ptr;
+#endif
             int how;
 
             if (arg2) {
@@ -8662,17 +8703,32 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
                 if (!(p = lock_user(VERIFY_READ, arg2, 
sizeof(target_sigset_t), 1)))
                     goto efault;
                 target_to_host_old_sigset(&set, p);
+#ifdef TRACK_TARGET_SIGMASK
+                abi_ulong_to_target_old_sigset(&target_set, p);
+                target_set_ptr = &target_set;
+#endif
                 unlock_user(p, arg2, 0);
                 set_ptr = &set;
             } else {
                 how = 0;
                 set_ptr = NULL;
+#ifdef TRACK_TARGET_SIGMASK
+                target_set_ptr = NULL;
+            }
+            ret = do_target_sigprocmask(how, target_set_ptr, &target_oldset,
+                                        set_ptr, &oldset);
+#else
             }
             ret = do_sigprocmask(how, set_ptr, &oldset);
+#endif
             if (!is_error(ret) && arg3) {
                 if (!(p = lock_user(VERIFY_WRITE, arg3, 
sizeof(target_sigset_t), 0)))
                     goto efault;
+#ifdef TRACK_TARGET_SIGMASK
+                target_to_abi_ulong_old_sigset(p, &target_oldset);
+#else
                 host_to_target_old_sigset(p, &oldset);
+#endif
                 unlock_user(p, arg3, sizeof(target_sigset_t));
             }
 #endif
@@ -8683,6 +8739,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
         {
             int how = arg1;
             sigset_t set, oldset, *set_ptr;
+#ifdef TRACK_TARGET_SIGMASK
+            target_sigset_t target_set, target_oldset, *target_set_ptr;
+#endif
 
             if (arg4 != sizeof(target_sigset_t)) {
                 ret = -TARGET_EINVAL;
@@ -8707,17 +8766,32 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
                 if (!(p = lock_user(VERIFY_READ, arg2, 
sizeof(target_sigset_t), 1)))
                     goto efault;
                 target_to_host_sigset(&set, p);
+#ifdef TRACK_TARGET_SIGMASK
+                tswapal_target_sigset(&target_set, p);
+                target_set_ptr = &target_set;
+#endif
                 unlock_user(p, arg2, 0);
                 set_ptr = &set;
             } else {
                 how = 0;
                 set_ptr = NULL;
+#ifdef TRACK_TARGET_SIGMASK
+                target_set_ptr = NULL;
+            }
+            ret = do_target_sigprocmask(how, target_set_ptr, &target_oldset,
+                                        set_ptr, &oldset);
+#else
             }
             ret = do_sigprocmask(how, set_ptr, &oldset);
+#endif
             if (!is_error(ret) && arg3) {
                 if (!(p = lock_user(VERIFY_WRITE, arg3, 
sizeof(target_sigset_t), 0)))
                     goto efault;
+#ifdef TRACK_TARGET_SIGMASK
+                tswapal_target_sigset(p, &target_oldset);
+#else
                 host_to_target_sigset(p, &oldset);
+#endif
                 unlock_user(p, arg3, sizeof(target_sigset_t));
             }
         }
@@ -8766,10 +8840,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
 #if defined(TARGET_ALPHA)
             abi_ulong mask = arg1;
             target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
+#ifdef TRACK_TARGET_SIGMASK
+            abi_ulong_to_target_old_sigset(&ts->target_sigsuspend_mask, &mask);
+#endif
 #else
             if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 
1)))
                 goto efault;
             target_to_host_old_sigset(&ts->sigsuspend_mask, p);
+#ifdef TRACK_TARGET_SIGMASK
+            abi_ulong_to_target_old_sigset(&ts->target_sigsuspend_mask, p);
+#endif
             unlock_user(p, arg1, 0);
 #endif
             ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
@@ -8791,6 +8871,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
             if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 
1)))
                 goto efault;
             target_to_host_sigset(&ts->sigsuspend_mask, p);
+#ifdef TRACK_TARGET_SIGMASK
+            tswapal_target_sigset(&ts->target_sigsuspend_mask, p);
+#endif
             unlock_user(p, arg1, 0);
             ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
                                                SIGSET_T_SIZE));
@@ -11030,6 +11113,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
             abi_ulong mask;
             int how;
             sigset_t set, oldset;
+#ifdef TRACK_TARGET_SIGMASK
+            target_sigset_t target_set, target_oldset;
+#endif
 
             switch(arg1) {
             case TARGET_SIG_BLOCK:
@@ -11047,9 +11133,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
             }
             mask = arg2;
             target_to_host_old_sigset(&set, &mask);
+#ifdef TRACK_TARGET_SIGMASK
+            abi_ulong_to_target_old_sigset(&target_set, &mask);
+            ret = do_target_sigprocmask(how, &target_set, &target_oldset,
+                                        &set, &oldset);
+            if (!ret) {
+                target_to_abi_ulong_old_sigset(&mask, &target_oldset);
+#else
             ret = do_sigprocmask(how, &set, &oldset);
             if (!ret) {
                 host_to_target_old_sigset(&mask, &oldset);
+#endif
                 ret = mask;
             }
         }
-- 
1.9.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]