All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host
@ 2019-05-22 18:46 Aleksandar Markovic
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 1/5] linux-user: Fix sigismember() check Aleksandar Markovic
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: Aleksandar Markovic @ 2019-05-22 18:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: lvivier, milos.stojanovic, amarkovic

From: Aleksandar Markovic <amarkovic@wavecomp.com>

Most of the targets (including Intel) define 64 signals. This
creates difficulties for targets that define, for example, 128
signals. This series adds support for signal passing even if
the host defines less signals than the target.

Miloš Stojanović (5):
  linux-user: Fix sigismember() check
  linux-user: Add support for tracking the target signal mask
  linux-user: Add functionality for tracking target signal mask
  linux-user: Add support for multiplexing larger target signals
  linux-user: Add support for multiplexing signals in more syscalls

 linux-user/mips/signal.c   |  16 ++++
 linux-user/qemu.h          |  11 +++
 linux-user/signal-common.h |   5 ++
 linux-user/signal.c        | 217 ++++++++++++++++++++++++++++++++++++++++++++-
 linux-user/syscall.c       | 178 +++++++++++++++++++++++++++++++++++++
 linux-user/syscall_defs.h  |  32 +++++++
 6 files changed, 457 insertions(+), 2 deletions(-)

-- 
2.7.4



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 1/5] linux-user: Fix sigismember() check
  2019-05-22 18:46 [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Aleksandar Markovic
@ 2019-05-22 18:46 ` Aleksandar Markovic
  2019-06-14 13:03   ` Peter Maydell
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 2/5] linux-user: Add support for tracking the target signal mask Aleksandar Markovic
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: Aleksandar Markovic @ 2019-05-22 18:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: lvivier, Miloš Stojanović, amarkovic

From: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>

Fix copying between the host and target signal sets for the case when
the target set is larger than the host set.

sigismember() returns 1 if the specified signal number is a member of
the specified signal set, but it can also return -1 if an error occurs
(e.g. an out of range signal number is specified). All non-zero values
would cause the signal to be added, so a comparison with 1 is added to
assure that only the signals which are really in the set get added to
the other set.

Signed-off-by: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
---
 linux-user/signal.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/linux-user/signal.c b/linux-user/signal.c
index 44b2d3b..c08a7fe 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -116,7 +116,7 @@ void host_to_target_sigset_internal(target_sigset_t *d,
     int i;
     target_sigemptyset(d);
     for (i = 1; i <= TARGET_NSIG; i++) {
-        if (sigismember(s, i)) {
+        if (sigismember(s, i) == 1) {
             target_sigaddset(d, host_to_target_signal(i));
         }
     }
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 2/5] linux-user: Add support for tracking the target signal mask
  2019-05-22 18:46 [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Aleksandar Markovic
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 1/5] linux-user: Fix sigismember() check Aleksandar Markovic
@ 2019-05-22 18:46 ` Aleksandar Markovic
  2019-06-14 13:14   ` Peter Maydell
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 3/5] linux-user: Add functionality for tracking " Aleksandar Markovic
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 11+ messages in thread
From: Aleksandar Markovic @ 2019-05-22 18:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: lvivier, Miloš Stojanović, amarkovic

From: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>

If TRACK_TARGET_SIGMASK is defined, add fields in the TaskState structure
which will hold the target signal and suspend mask and add support for
initialization and forking. No functional changes are being introduced in
this commit. The TRACK_TARGET_SIGMASK will be defined in a later commit
where the target signal masks will be needed in order to implement
multiplexing of real-time target signals which are out of the host range.

Currently, QEMU has a copy of the host signal and suspend masks and that
is usually enough, since most of the time the signal mask of the target
architecture is either the same length or narrower. If however the signal
mask is wider, then part of it won't be tracked.

This commit enables adding support for separately tracking the target
signal masks in the following commits.

Signed-off-by: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
---
 linux-user/qemu.h    | 5 +++++
 linux-user/signal.c  | 3 +++
 linux-user/syscall.c | 3 +++
 3 files changed, 11 insertions(+)

diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index ef400cb..9f70996 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -141,6 +141,11 @@ typedef struct TaskState {
      * currently in the middle of such a syscall
      */
     sigset_t sigsuspend_mask;
+#ifdef TRACK_TARGET_SIGMASK
+    /* Track the target signal and suspend masks. */
+    target_sigset_t target_signal_mask;
+    target_sigset_t target_sigsuspend_mask;
+#endif
     /* Nonzero if we're leaving a sigsuspend and sigsuspend_mask is valid. */
     int in_sigsuspend;
 
diff --git a/linux-user/signal.c b/linux-user/signal.c
index c08a7fe..954aef8 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -499,6 +499,9 @@ void signal_init(void)
 
     /* Set the signal mask from the host mask. */
     sigprocmask(0, 0, &ts->signal_mask);
+#ifdef TRACK_TARGET_SIGMASK
+    host_to_target_sigset_internal(&ts->target_signal_mask, &ts->signal_mask);
+#endif
 
     /* set all host signal handlers. ALL signals are blocked during
        the handlers to serialize them. */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index efa3ec2..115ab13 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5540,6 +5540,9 @@ static int do_fork(CPUArchState *env, unsigned int flags, abi_ulong newsp,
         ts->bprm = parent_ts->bprm;
         ts->info = parent_ts->info;
         ts->signal_mask = parent_ts->signal_mask;
+#ifdef TRACK_TARGET_SIGMASK
+        ts->target_signal_mask = parent_ts->target_signal_mask;
+#endif
 
         if (flags & CLONE_CHILD_CLEARTID) {
             ts->child_tidptr = child_tidptr;
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 3/5] linux-user: Add functionality for tracking target signal mask
  2019-05-22 18:46 [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Aleksandar Markovic
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 1/5] linux-user: Fix sigismember() check Aleksandar Markovic
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 2/5] linux-user: Add support for tracking the target signal mask Aleksandar Markovic
@ 2019-05-22 18:46 ` Aleksandar Markovic
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 4/5] linux-user: Add support for multiplexing larger target signals Aleksandar Markovic
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Aleksandar Markovic @ 2019-05-22 18:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: lvivier, Miloš Stojanović, amarkovic

From: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>

Add two inline functions that work with the signal set of the target.

target_sigdelset() removes a signal from target_sigset_t.
target_sigorset() creates a union of two target_sigset_t.

These functions will be used for introducing support for tracking the
target signal set. Functions for emptying and adding into a target signal
set already exist so this commit will serve as a supplement.

Add functions tswapal_target_sigset(), target_to_abi_ulong_old_sigset()
and abi_ulong_to_target_old_sigset().

The tswapal_target_sigset() function transforms target signal sets
from target to host endianness. This is helpful for tracking and working
with the target signal masks in the host endianness rather then keeping
it in the target endianness.

The target_to_abi_ulong_old_sigset() and abi_ulong_to_target_old_sigset()
functions are used for translating the signal set between the old way of
storing it in abi_ulong and the new target_sigset_t structure. They can
be used for expanding old implementations of certain system calls to
include the tracking of the target signal masks.

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ć <Milos.Stojanovic@rt-rk.com>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
---
 linux-user/mips/signal.c   |  16 +++++
 linux-user/qemu.h          |   6 ++
 linux-user/signal-common.h |   5 ++
 linux-user/signal.c        | 158 ++++++++++++++++++++++++++++++++++++++++++++-
 linux-user/syscall.c       |  94 +++++++++++++++++++++++++++
 linux-user/syscall_defs.h  |   4 ++
 6 files changed, 282 insertions(+), 1 deletion(-)

diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c
index 6aa303e..37922d9 100644
--- a/linux-user/mips/signal.c
+++ b/linux-user/mips/signal.c
@@ -253,6 +253,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];
@@ -265,7 +268,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);
 
@@ -358,6 +366,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);
@@ -366,7 +377,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);
 
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 9f70996..75ba2a5 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -401,12 +401,18 @@ void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
 void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
 int target_to_host_signal(int sig);
 int host_to_target_signal(int sig);
+void tswapal_target_sigset(target_sigset_t *d, const target_sigset_t *s);
 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);
 abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
                         abi_ulong unew_ctx, abi_long ctx_size);
+#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-common.h b/linux-user/signal-common.h
index 51030a9..6332931 100644
--- a/linux-user/signal-common.h
+++ b/linux-user/signal-common.h
@@ -37,7 +37,12 @@ void target_to_host_sigset_internal(sigset_t *d,
                                     const target_sigset_t *s);
 void tswap_siginfo(target_siginfo_t *tinfo,
                    const target_siginfo_t *info);
+#ifndef TRACK_TARGET_SIGMASK
 void set_sigmask(const sigset_t *set);
+#else
+void target_set_sigmask(const sigset_t *set,
+                        const target_sigset_t *target_set);
+#endif
 void force_sig(int sig);
 void force_sigsegv(int oldsig);
 #if defined(TARGET_ARCH_HAS_SETUP_FRAME)
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 954aef8..9a73bfa 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -103,6 +103,12 @@ static inline void target_sigaddset(target_sigset_t *set, int signum)
     set->sig[signum / TARGET_NSIG_BPW] |= mask;
 }
 
+static inline void target_sigdelset(target_sigset_t *set, int signum)
+{
+    abi_ulong mask = (abi_ulong)1 << (--signum % TARGET_NSIG_BPW);
+    set->sig[signum / TARGET_NSIG_BPW] &= ~mask;
+}
+
 static inline int target_sigismember(const target_sigset_t *set, int signum)
 {
     signum--;
@@ -110,6 +116,16 @@ static inline int target_sigismember(const target_sigset_t *set, int signum)
     return ((set->sig[signum / TARGET_NSIG_BPW] & mask) != 0);
 }
 
+static inline void target_sigorset(target_sigset_t *set,
+                                   const target_sigset_t *left,
+                                   const target_sigset_t *right)
+{
+    int i;
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        set->sig[i] = left->sig[i] | right->sig[i];
+    }
+}
+
 void host_to_target_sigset_internal(target_sigset_t *d,
                                     const sigset_t *s)
 {
@@ -174,6 +190,33 @@ void target_to_host_old_sigset(sigset_t *sigset,
     target_to_host_sigset(sigset, &d);
 }
 
+void target_to_abi_ulong_old_sigset(abi_ulong *old_sigset,
+                                    const target_sigset_t *target_sigset)
+{
+    target_sigset_t d;
+    tswapal_target_sigset(&d, target_sigset);
+
+    memcpy(old_sigset, &d.sig, sizeof(target_sigset_t));
+}
+
+void abi_ulong_to_target_old_sigset(target_sigset_t *target_sigset,
+                                    const abi_ulong *old_sigset)
+{
+    target_sigset_t d;
+
+    memcpy(&d.sig, old_sigset, sizeof(target_sigset_t));
+    tswapal_target_sigset(target_sigset, &d);
+}
+
+void tswapal_target_sigset(target_sigset_t *d, const target_sigset_t *s)
+{
+    int i;
+
+    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
+        d->sig[i] = tswapal(s->sig[i]);
+    }
+}
+
 int block_signals(void)
 {
     TaskState *ts = (TaskState *)thread_cpu->opaque;
@@ -236,16 +279,84 @@ 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_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
 void set_sigmask(const sigset_t *set)
 {
     TaskState *ts = (TaskState *)thread_cpu->opaque;
 
     ts->signal_mask = *set;
 }
+#else
+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
 
 /* sigaltstack management */
@@ -849,6 +960,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;
 
@@ -886,21 +1000,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 */
@@ -934,7 +1066,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.  */
@@ -952,22 +1088,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 115ab13..dede443 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7871,6 +7871,17 @@ static abi_long do_syscall1(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);
@@ -7878,12 +7889,26 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                 host_to_target_old_sigset(&target_set, &cur_set);
                 ret = target_set;
             }
+#endif
         }
         return ret;
 #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);
@@ -7892,6 +7917,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                 host_to_target_old_sigset(&target_set, &oset);
                 ret = target_set;
             }
+#endif
         }
         return ret;
 #endif
@@ -7900,6 +7926,9 @@ static abi_long do_syscall1(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;
 
@@ -7919,14 +7948,26 @@ static abi_long do_syscall1(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) {
@@ -7946,17 +7987,32 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
                     return -TARGET_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)))
                     return -TARGET_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
@@ -7967,6 +8023,9 @@ static abi_long do_syscall1(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)) {
                 return -TARGET_EINVAL;
@@ -7989,17 +8048,32 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
                 if (!(p = lock_user(VERIFY_READ, arg2, sizeof(target_sigset_t), 1)))
                     return -TARGET_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)))
                     return -TARGET_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));
             }
         }
@@ -8047,10 +8121,16 @@ static abi_long do_syscall1(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)))
                 return -TARGET_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,
@@ -8071,6 +8151,9 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
             if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
                 return -TARGET_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));
@@ -10351,6 +10434,9 @@ static abi_long do_syscall1(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:
@@ -10367,9 +10453,17 @@ static abi_long do_syscall1(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;
             }
         }
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 1f5b2d1..64edec2 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -419,6 +419,10 @@ void host_to_target_old_sigset(abi_ulong *old_sigset,
                                const sigset_t *sigset);
 void target_to_host_old_sigset(sigset_t *sigset,
                                const abi_ulong *old_sigset);
+void target_to_abi_ulong_old_sigset(abi_ulong *old_sigset,
+                                    const target_sigset_t *target_sigset);
+void abi_ulong_to_target_old_sigset(target_sigset_t *target_sigset,
+                                    const abi_ulong *old_sigset);
 struct target_sigaction;
 int do_sigaction(int sig, const struct target_sigaction *act,
                  struct target_sigaction *oact);
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 4/5] linux-user: Add support for multiplexing larger target signals
  2019-05-22 18:46 [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Aleksandar Markovic
                   ` (2 preceding siblings ...)
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 3/5] linux-user: Add functionality for tracking " Aleksandar Markovic
@ 2019-05-22 18:46 ` Aleksandar Markovic
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 5/5] linux-user: Add support for multiplexing signals in more syscalls Aleksandar Markovic
  2019-05-23 13:26 ` [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Peter Maydell
  5 siblings, 0 replies; 11+ messages in thread
From: Aleksandar Markovic @ 2019-05-22 18:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: lvivier, Miloš Stojanović, amarkovic

From: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>

Add MUX_SIG as a multiplex signal number for all target signals which are
out of the host range. Add support for multiplexing in do_sigaction(),
process_pending_signals(), target_set_sigmask() and do_target_sigprocmask().

This patch solves the problem of unusable target signals which are out of
the host range. This is done by enabling the usage of one of the host
signals (MUX_SIG) as a multiplex for all the target signals that are out
of range. In order to have the target signal masks available
TRACK_TARGET_MASK is defined which enables the tracking of the target
signals masks.

The table of signal handlers already supports the whole range of target
signals. In the do_sigaction() function the signal number of signals which
are out of range are replaced by MUX_SIG which bypasses the error from the
host system and doesn't interfere with signal handling on the target.
Since the MUX_SIG is used as a multiplex, it must never be blocked on host,
so support for emulating the blocking of this signal is added. This is done
by only blocking MUX_SIG in the target mask and retrieving its status from
there when it's needed.

Signed-off-by: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
---
 linux-user/signal.c       | 32 ++++++++++++++++++++++++++++++++
 linux-user/syscall_defs.h | 20 ++++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/linux-user/signal.c b/linux-user/signal.c
index 9a73bfa..601de3e 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -291,6 +291,15 @@ int do_target_sigprocmask(int how, const target_sigset_t *target_set,
     }
     if (oldset) {
         *oldset = ts->signal_mask;
+#ifdef MUX_SIG
+        /*
+         * The emulation of MUX_SIG being blocked is done using the
+         * target_signal_mask, so the status of MUX_SIG is taken from there.
+         */
+        if (target_sigismember(&ts->target_signal_mask, MUX_SIG) == 1) {
+            sigaddset(oldset, MUX_SIG);
+        }
+#endif
     }
 
     if (target_set && set) {
@@ -331,6 +340,15 @@ int do_target_sigprocmask(int how, const target_sigset_t *target_set,
         target_sigdelset(&ts->target_signal_mask, SIGSTOP);
         sigdelset(&ts->signal_mask, SIGKILL);
         sigdelset(&ts->signal_mask, SIGSTOP);
+#ifdef MUX_SIG
+        /*
+         * Since MUX_SIG is used for all the target signals out of the host
+         * range it must never be blocked on host. The emulation of MUX_SIG
+         * being blocked is done using the target_signal_mask. The status
+         * of MUX_SIG is taken form the target_signal_mask.
+         */
+        sigdelset(&ts->signal_mask, MUX_SIG);
+#endif
     }
     return 0;
 }
@@ -355,6 +373,10 @@ void target_set_sigmask(const sigset_t *set,
 
     ts->signal_mask = *set;
     ts->target_signal_mask = *target_set;
+#ifdef MUX_SIG
+    /* MUX_SIG can't be blocked on host */
+    sigdelset(&ts->signal_mask, MUX_SIG);
+#endif
 }
 #endif
 #endif
@@ -929,6 +951,12 @@ int do_sigaction(int sig, const struct target_sigaction *act,
 
         /* we update the host linux signal state */
         host_sig = target_to_host_signal(sig);
+#ifdef MUX_SIG
+        /* put the out of host range signal into the multiplex */
+        if (sig >= _NSIG && sig < TARGET_NSIG) {
+            host_sig = MUX_SIG;
+        }
+#endif
         if (host_sig != SIGSEGV && host_sig != SIGBUS) {
             sigfillset(&act1.sa_mask);
             act1.sa_flags = SA_SIGINFO;
@@ -1141,6 +1169,10 @@ void process_pending_signals(CPUArchState *cpu_env)
         set = ts->signal_mask;
         sigdelset(&set, SIGSEGV);
         sigdelset(&set, SIGBUS);
+#ifdef MUX_SIG
+        /* MUX_SIG can't be blocked on host */
+        sigdelset(&ts->signal_mask, MUX_SIG);
+#endif
         sigprocmask(SIG_SETMASK, &set, 0);
     }
     ts->in_sigsuspend = 0;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 64edec2..0c72509 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -387,6 +387,26 @@ struct target_dirent64 {
 #define TARGET_NSIG_BPW	   TARGET_ABI_BITS
 #define TARGET_NSIG_WORDS  (TARGET_NSIG / TARGET_NSIG_BPW)
 
+#if _NSIG <= TARGET_NSIG
+/*
+ * MUX_SIG is used as a multiplex signal number - signals that are
+ * out of the host range and in the target range are sent through it.
+ * It is defined as the maximal available real-time signal in order to
+ * comply with the rule that low-numbered signals have highest priority.
+ * (signals using it will have the same priority but it will be smaller
+ * than all the other real-time signals)
+ * SIGRMTAX is avoided so it doesn't interfere with the hack of reversing
+ * __SIGRTMIN and __SIGRTMAX in the host_to_target_signal_table.
+ */
+#define MUX_SIG     (SIGRTMAX - 1)
+
+/*
+ * The target signal masks must be tracked since they are larger than
+ * the host signal masks.
+ */
+#define TRACK_TARGET_SIGMASK
+#endif
+
 typedef struct {
     abi_ulong sig[TARGET_NSIG_WORDS];
 } target_sigset_t;
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [Qemu-devel] [PATCH 5/5] linux-user: Add support for multiplexing signals in more syscalls
  2019-05-22 18:46 [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Aleksandar Markovic
                   ` (3 preceding siblings ...)
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 4/5] linux-user: Add support for multiplexing larger target signals Aleksandar Markovic
@ 2019-05-22 18:46 ` Aleksandar Markovic
  2019-05-23 13:26 ` [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Peter Maydell
  5 siblings, 0 replies; 11+ messages in thread
From: Aleksandar Markovic @ 2019-05-22 18:46 UTC (permalink / raw)
  To: qemu-devel; +Cc: lvivier, Miloš Stojanović, amarkovic

From: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>

Add support for multiplexing in the host_signal_handler() function and in
system calls rt_sigqueueinfo()/rt_tgsigqueueinfo(), tgkill(), kill() for
the case when pid > 0.

The rt_sigqueueinfo()/rt_tgsigqueueinfo() system calls multiplex target
signals which are out of the host range by setting the si_errno value to
the actual value of the signal and sending the signal to the MUX_SIG
signal number. The host_signal_handler() will pull out the multiplexed
signals and set their signal number to the correct value. That value
should be in the si_errno field of the siginfo_t structure. The si_errno
field is used here but this implementation can be replaced with any other
unused field in the uinfo structure.

The emulation of larger target signal range is done by spoofing the system
call info, adding the signal number to the si_errno field, and sending it
to the host multiplex queue via rt_sigqueueinfo()/rt_tgsigqueueinfo().
In order to send a signal using rt_sigqueueinfo()/rt_tgsigqueueinfo() with
si_code SI_USER or SI_TKILL to another thread or process, we need to
disguise it as some other signal from the kernel range because the host
kernel doesn't allow direct impersonations of those signals. This is done
with SIG_SPOOF which moves the si_code to the nearest unused kernel si_code
value. After the signal is successfully sent the host_signal_handler() of
the receiving thread/process will turn it back into the proper kill/tgkill
signal, before it gets processed.

The tkill() system call as well as kill() with the argument pid <= 0
couldn't be implemented simply using this method because it requires
acquiring information about, and sending simultaneous signals to multiple
threads or processes. These functionalities are out of the scope of
rt_sigqueueinfo()/rt_tgsigqueueinfo().

Signed-off-by: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>
Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
---
 linux-user/signal.c       | 22 +++++++++++++
 linux-user/syscall.c      | 81 +++++++++++++++++++++++++++++++++++++++++++++++
 linux-user/syscall_defs.h |  8 +++++
 3 files changed, 111 insertions(+)

diff --git a/linux-user/signal.c b/linux-user/signal.c
index 601de3e..885ceab 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -807,6 +807,28 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
     sig = host_to_target_signal(host_signum);
     if (sig < 1 || sig > TARGET_NSIG)
         return;
+
+#ifdef MUX_SIG
+    if (sig == MUX_SIG) {
+        /* return the spoofed kill/tgkill signals into standard form */
+        if (info->si_code == SIG_SPOOF(SI_USER)) {
+            info->si_code = SI_USER;
+        } else if (info->si_code == SIG_SPOOF(SI_TKILL)) {
+            info->si_code = SI_TKILL;
+        }
+
+        /*
+         * We assume that si_errno field will remain intact during signal
+         * processing on the host. If it changes, the signal will be sent to
+         * the wrong number (most likely to MUX_SIG).
+         */
+        /* get the actual target signal number */
+        int target_sig = info->si_errno;
+        if (target_sig >= _NSIG && target_sig < TARGET_NSIG) {
+            sig = target_sig;
+        }
+    }
+#endif
     trace_user_host_signal(env, host_signum, sig);
 
     rewind_if_in_safe_syscall(puc);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index dede443..2e3c951 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6448,6 +6448,24 @@ static inline abi_long host_to_target_stat64(void *cpu_env,
 }
 #endif
 
+#ifdef MUX_SIG
+static inline int multiplex(abi_long *arg, siginfo_t *uinfo)
+{
+    if (*arg >= _NSIG && *arg < TARGET_NSIG) {
+        /*
+         * Using si_errno to transfer the signal number assumes that the field
+         * doesn't change its value before it gets handled in the
+         * host_signal_handler().
+         */
+        uinfo->si_errno = *arg;
+        *arg = MUX_SIG;
+        uinfo->si_signo = MUX_SIG;
+    }
+
+    return 0;
+}
+#endif
+
 /* ??? Using host futex calls even when target atomic operations
    are not really atomic probably breaks things.  However implementing
    futexes locally would make futexes shared between multiple processes
@@ -7535,7 +7553,42 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
         return get_errno(syncfs(arg1));
 #endif
     case TARGET_NR_kill:
+#ifdef MUX_SIG
+        if (arg2 >= _NSIG && arg2 < TARGET_NSIG) {
+            siginfo_t info;
+
+            info.si_errno = arg2;
+            info.si_signo = MUX_SIG;
+            info.si_code = SIG_SPOOF(SI_USER);
+            info.si_pid = getpid();
+            info.si_uid = getuid();
+
+            /* pid > 0 */
+            if (arg1 > 0) {
+                return get_errno(sys_rt_sigqueueinfo(arg1, MUX_SIG, &info));
+            } else {
+                return -TARGET_EINVAL;
+            }
+            /*
+             * TODO: In order to implement kill with rt_tgsigqueueinfo() for
+             * cases where pid <= 0 one needs to get a list of all the relevant
+             * processes and simultaniously send the signal to them.
+             * Missing:
+             * (pid = 0):
+             *     send to every process in the process group of
+             *     the calling process
+             * (pid = -1):
+             *     send to every process for which the calling process
+             *     has permission to send signals, except for process 1 (init)
+             * (pid < -1):
+             *     send to every process in the process group whose ID is -pid
+             */
+        } else {
+            return get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
+        }
+#else
         return get_errno(safe_kill(arg1, target_to_host_signal(arg2)));
+#endif
 #ifdef TARGET_NR_rename
     case TARGET_NR_rename:
         {
@@ -8208,6 +8261,9 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
             }
             target_to_host_siginfo(&uinfo, p);
             unlock_user(p, arg3, 0);
+#ifdef MUX_SIG
+            multiplex(&arg2, &uinfo);
+#endif
             ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
         }
         return ret;
@@ -8221,6 +8277,9 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
             }
             target_to_host_siginfo(&uinfo, p);
             unlock_user(p, arg4, 0);
+#ifdef MUX_SIG
+            multiplex(&arg3, &uinfo);
+#endif
             ret = get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, arg3, &uinfo));
         }
         return ret;
@@ -11037,11 +11096,33 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
 #endif
 
     case TARGET_NR_tkill:
+        /*
+         * TODO: In order to implement tkill with rt_sigqueueinfo() one needs
+         * to get a list of all the threads with the specifiend tid and
+         * simultaniously send the signal to them.
+         */
         return get_errno(safe_tkill((int)arg1, target_to_host_signal(arg2)));
 
     case TARGET_NR_tgkill:
+#ifdef MUX_SIG
+        if (arg3 >= _NSIG && arg3 < TARGET_NSIG) {
+            siginfo_t info;
+
+            info.si_errno = arg3;
+            info.si_signo = MUX_SIG;
+            info.si_code = SIG_SPOOF(SI_TKILL);
+            info.si_pid = getpid();
+            info.si_uid = getuid();
+
+            return get_errno(sys_rt_tgsigqueueinfo(arg1, arg2, MUX_SIG, &info));
+        } else {
+            return get_errno(safe_tgkill((int)arg1, (int)arg2,
+                             target_to_host_signal(arg3)));
+        }
+#else
         return get_errno(safe_tgkill((int)arg1, (int)arg2,
                          target_to_host_signal(arg3)));
+#endif
 
 #ifdef TARGET_NR_set_robust_list
     case TARGET_NR_set_robust_list:
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 0c72509..ca97f67 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -405,6 +405,14 @@ struct target_dirent64 {
  * the host signal masks.
  */
 #define TRACK_TARGET_SIGMASK
+
+/*
+ * This macro is used to change a kill/tgkill signal so it can be sent through
+ * rt_sigqueueinfo()/rt_tgsigqueueinfo(), since the host kernel doesn't allow
+ * direct impersonations of those signals. Subtracting 8 from the code moves
+ * it to the nearest unused kernel si_code value.
+ */
+#define SIG_SPOOF(code)  ((code) - 8)
 #endif
 
 typedef struct {
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host
  2019-05-22 18:46 [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Aleksandar Markovic
                   ` (4 preceding siblings ...)
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 5/5] linux-user: Add support for multiplexing signals in more syscalls Aleksandar Markovic
@ 2019-05-23 13:26 ` Peter Maydell
  2019-05-23 14:03   ` Aleksandar Markovic
  2019-05-24 17:27   ` [Qemu-devel] ?==?utf-8?q? ?==?utf-8?q? [PATCH 0/5]?==?utf-8?q? " Milos Stojanovic
  5 siblings, 2 replies; 11+ messages in thread
From: Peter Maydell @ 2019-05-23 13:26 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Laurent Vivier, Miloš Stojanović,
	QEMU Developers, Aleksandar Markovic

On Wed, 22 May 2019 at 19:57, Aleksandar Markovic
<aleksandar.markovic@rt-rk.com> wrote:
>
> From: Aleksandar Markovic <amarkovic@wavecomp.com>
>
> Most of the targets (including Intel) define 64 signals. This
> creates difficulties for targets that define, for example, 128
> signals. This series adds support for signal passing even if
> the host defines less signals than the target.

Could you elaborate a bit on how much functionality
is provided for signal numbers which the target has
but the host does not? For instance, it seems likely
that attempts by the guest to kill(other_pid, sig) will
fail if sig is not in the supported-by-the-target range.
But is it possible for the guest process to deliver
one of these signals to itself ?

This patchset is interesting because in fact pretty much
every target supports more signals than our host code
can provide, because the host libc steals several
signals for its own purposes and QEMU can't use them.
Being able to multiplex several guest signals onto
one host signal might let us run some guest binaries
we currently can't handle correctly.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host
  2019-05-23 13:26 ` [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Peter Maydell
@ 2019-05-23 14:03   ` Aleksandar Markovic
  2019-05-24 17:27   ` [Qemu-devel] ?==?utf-8?q? ?==?utf-8?q? [PATCH 0/5]?==?utf-8?q? " Milos Stojanovic
  1 sibling, 0 replies; 11+ messages in thread
From: Aleksandar Markovic @ 2019-05-23 14:03 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Laurent Vivier, Aleksandar Markovic, Miloš Stojanović,
	QEMU Developers, Aleksandar Markovic

On May 23, 2019 3:46 PM, "Peter Maydell" <peter.maydell@linaro.org> wrote:
>
> On Wed, 22 May 2019 at 19:57, Aleksandar Markovic
> <aleksandar.markovic@rt-rk.com> wrote:
> >
> > From: Aleksandar Markovic <amarkovic@wavecomp.com>
> >
> > Most of the targets (including Intel) define 64 signals. This
> > creates difficulties for targets that define, for example, 128
> > signals. This series adds support for signal passing even if
> > the host defines less signals than the target.
>
> Could you elaborate a bit on how much functionality
> is provided for signal numbers which the target has
> but the host does not? For instance, it seems likely
> that attempts by the guest to kill(other_pid, sig) will
> fail if sig is not in the supported-by-the-target range.
> But is it possible for the guest process to deliver
> one of these signals to itself ?
>
> This patchset is interesting because in fact pretty much
> every target supports more signals than our host code
> can provide, because the host libc steals several
> signals for its own purposes and QEMU can't use them.
> Being able to multiplex several guest signals onto
> one host signal might let us run some guest binaries
> we currently can't handle correctly.
>

Hello, Peter.

I would ask the author, Milos Stojanovic, to provide us with details you
asked for.

I am here just the integrator and the submitter, and even though I could
perhaps answer your questions accurately, I would prefer Milos as the main
person to talk to.

I would like to add that this series is already in exploation here in Wave,
for some internal projects involving QEMU. People are happy with it, it
solved some long-standing problems, and there is no known open issue
related to this code.

The solution has its own limitations, as is spelled out in commit messages,
just to keep your expectations realistic, but overall I find it incredibly
useful, and very good, given the complex problem it tackles.

I would like now to pass the “floor” to Milos.

Yours,
Aleksandar

> thanks
> -- PMM
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel]  ?==?utf-8?q? ?==?utf-8?q? [PATCH 0/5]?==?utf-8?q? linux-user: Support signal passing for targets having more signals than host
  2019-05-23 13:26 ` [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Peter Maydell
  2019-05-23 14:03   ` Aleksandar Markovic
@ 2019-05-24 17:27   ` Milos Stojanovic
  1 sibling, 0 replies; 11+ messages in thread
From: Milos Stojanovic @ 2019-05-24 17:27 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Laurent Vivier, Aleksandar Markovic, QEMU Developers,
	Aleksandar Markovic


Hello, Peter.
For this implemenation rt_sigqueueinfo()/rt_tgsigqueueinfo() were used to multiplex signals that are out of the host range. This enabled the use of a wider signal range with rt_sigqueueinfo(), rt_tgsigqueueinfo(), as well as kill() (for pid > 0) and tgkill(). A process can now use these system calls to send a range of signals which weren't supporeted before to itself or others threads or processes.

The tkill() system call and kill() with the argument pid <= 0 couldn't be implemented simply using this method because it requires acquiring information about, and sending simultaneous signals to multiple threads or processes and these functionalities are out of the scope of rt_sigqueueinfo()/rt_tgsigqueueinfo().

This patch set was primarily focused on expanding the range of real-time signals and making them usable but some limitations still remain. For example, the priority of those real-time signals, as defined by POSIX, doesn't depend on the actual signal number but on the host signal nuber which is used for multiplexing.
As it now is, the functionaly is only enabled for signals that are higher-numbered then the host signals but I don't see a conceptual problem in expanding and testing the implenentation to include other signals (e.g. the signals that NPTL uses).

Regards,
Miloš

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 1/5] linux-user: Fix sigismember() check
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 1/5] linux-user: Fix sigismember() check Aleksandar Markovic
@ 2019-06-14 13:03   ` Peter Maydell
  0 siblings, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2019-06-14 13:03 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Laurent Vivier, Miloš Stojanović,
	QEMU Developers, Aleksandar Markovic

On Wed, 22 May 2019 at 20:00, Aleksandar Markovic
<aleksandar.markovic@rt-rk.com> wrote:
>
> From: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>
>
> Fix copying between the host and target signal sets for the case when
> the target set is larger than the host set.
>
> sigismember() returns 1 if the specified signal number is a member of
> the specified signal set, but it can also return -1 if an error occurs
> (e.g. an out of range signal number is specified). All non-zero values
> would cause the signal to be added, so a comparison with 1 is added to
> assure that only the signals which are really in the set get added to
> the other set.
>
> Signed-off-by: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>
> Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>
> ---
>  linux-user/signal.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/linux-user/signal.c b/linux-user/signal.c
> index 44b2d3b..c08a7fe 100644
> --- a/linux-user/signal.c
> +++ b/linux-user/signal.c
> @@ -116,7 +116,7 @@ void host_to_target_sigset_internal(target_sigset_t *d,
>      int i;
>      target_sigemptyset(d);
>      for (i = 1; i <= TARGET_NSIG; i++) {
> -        if (sigismember(s, i)) {
> +        if (sigismember(s, i) == 1) {
>              target_sigaddset(d, host_to_target_signal(i));
>          }
>      }

I think perhaps a better fix for this would be to correct
the loop termination condition to be "i < _NSIG". What
we're doing here is looking at all the host signals in
s to see if we should be adding them to d, so what we
should be looping over is the valid range of host
signal numbers, not the valid range of target signal numbers.
Then we don't need to care about what sigismember() does
if passed an invalid signal number, because we'll never do that.

I also think we may have some off-by-one errors in various
comparisons with TARGET_NSIG and _NSIG: sometimes we
compare with <=, ie taking _NSIG or TARGET_NSIG to be
the highest valid signal number, and sometimes we compare
with <, taking it to be one greater than the highest valid
signal number. For instance compare the signal_init() code loop
and the size of arrays like host_to_target_signal_table[]
versus the loop condition in host_to_target_sigset_internal()
and target_to_host_sigset_internal().

I *think* that the correct intepretation is "it's one
greater than the highest valid number" and we should fix
the conditions in:
 host_to_target_sigset_internal
 target_to_host_sigset_internal
 do_sigprocmask
 signal_init
 host_signal_handler
 do_sigaction
 process_pending_signals

but somebody should definitely check whether I'm right or not.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH 2/5] linux-user: Add support for tracking the target signal mask
  2019-05-22 18:46 ` [Qemu-devel] [PATCH 2/5] linux-user: Add support for tracking the target signal mask Aleksandar Markovic
@ 2019-06-14 13:14   ` Peter Maydell
  0 siblings, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2019-06-14 13:14 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Laurent Vivier, Miloš Stojanović,
	QEMU Developers, Aleksandar Markovic

On Wed, 22 May 2019 at 19:57, Aleksandar Markovic
<aleksandar.markovic@rt-rk.com> wrote:
>
> From: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>
>
> If TRACK_TARGET_SIGMASK is defined, add fields in the TaskState structure
> which will hold the target signal and suspend mask and add support for
> initialization and forking. No functional changes are being introduced in
> this commit. The TRACK_TARGET_SIGMASK will be defined in a later commit
> where the target signal masks will be needed in order to implement
> multiplexing of real-time target signals which are out of the host range.
>
> Currently, QEMU has a copy of the host signal and suspend masks and that
> is usually enough, since most of the time the signal mask of the target
> architecture is either the same length or narrower. If however the signal
> mask is wider, then part of it won't be tracked.
>
> This commit enables adding support for separately tracking the target
> signal masks in the following commits.
>
> Signed-off-by: Miloš Stojanović <Milos.Stojanovic@rt-rk.com>
> Signed-off-by: Aleksandar Markovic <amarkovic@wavecomp.com>

> ---
>  linux-user/qemu.h    | 5 +++++
>  linux-user/signal.c  | 3 +++
>  linux-user/syscall.c | 3 +++
>  3 files changed, 11 insertions(+)
>
> diff --git a/linux-user/qemu.h b/linux-user/qemu.h
> index ef400cb..9f70996 100644
> --- a/linux-user/qemu.h
> +++ b/linux-user/qemu.h
> @@ -141,6 +141,11 @@ typedef struct TaskState {
>       * currently in the middle of such a syscall
>       */
>      sigset_t sigsuspend_mask;
> +#ifdef TRACK_TARGET_SIGMASK
> +    /* Track the target signal and suspend masks. */
> +    target_sigset_t target_signal_mask;
> +    target_sigset_t target_sigsuspend_mask;
> +#endif

These basically do the same thing as the existing sigsuspend_mask
and signal_mask fields. Rather than having two struct fields
that do very similar things, my guess is that we'll end up
with cleaner code if we just always store these masks as
target_sigset_t, and refactor the code that currently treats
them as being host sigset_t to treat them as target_sigset_t.
After all, the signal_mask field is supposed to be "the signal
mask as requested by the guest program", so target_sigset_t
is the more natural way to represent it.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2019-06-14 13:15 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-22 18:46 [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Aleksandar Markovic
2019-05-22 18:46 ` [Qemu-devel] [PATCH 1/5] linux-user: Fix sigismember() check Aleksandar Markovic
2019-06-14 13:03   ` Peter Maydell
2019-05-22 18:46 ` [Qemu-devel] [PATCH 2/5] linux-user: Add support for tracking the target signal mask Aleksandar Markovic
2019-06-14 13:14   ` Peter Maydell
2019-05-22 18:46 ` [Qemu-devel] [PATCH 3/5] linux-user: Add functionality for tracking " Aleksandar Markovic
2019-05-22 18:46 ` [Qemu-devel] [PATCH 4/5] linux-user: Add support for multiplexing larger target signals Aleksandar Markovic
2019-05-22 18:46 ` [Qemu-devel] [PATCH 5/5] linux-user: Add support for multiplexing signals in more syscalls Aleksandar Markovic
2019-05-23 13:26 ` [Qemu-devel] [PATCH 0/5] linux-user: Support signal passing for targets having more signals than host Peter Maydell
2019-05-23 14:03   ` Aleksandar Markovic
2019-05-24 17:27   ` [Qemu-devel] ?==?utf-8?q? ?==?utf-8?q? [PATCH 0/5]?==?utf-8?q? " Milos Stojanovic

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.