Source-Changes-HG archive

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

[src/trunk]: src/sys/compat Rework Mach exceptions and softignals



details:   https://anonhg.NetBSD.org/src/rev/77b84525857d
branches:  trunk
changeset: 555885:77b84525857d
user:      manu <manu%NetBSD.org@localhost>
date:      Wed Dec 03 18:40:07 2003 +0000

description:
Rework Mach exceptions and softignals

Exceptions coming from a trap are generated from darwin_trapsignal()
softsignals are from darwin_sigfilter(), a function that is called
from darwin_trapsignal() and from kpsignal2() [the latter from a
emulation specific hook which is not yet committed]

Make some sanity checks to avoid sending data to a port with no receiver.

See http://mail-index.netbsd.org/tech-kern/2003/12/01/0008.html and
follow-ups for details.

diffstat:

 sys/compat/darwin/darwin_signal.c |  77 ++++++++++++++++++++++++++++----------
 sys/compat/darwin/darwin_signal.h |   3 +-
 sys/compat/mach/mach_notify.c     |  71 +++++++++++++++++++++++++++--------
 3 files changed, 112 insertions(+), 39 deletions(-)

diffs (262 lines):

diff -r 17a5ee6225d2 -r 77b84525857d sys/compat/darwin/darwin_signal.c
--- a/sys/compat/darwin/darwin_signal.c Wed Dec 03 18:25:44 2003 +0000
+++ b/sys/compat/darwin/darwin_signal.c Wed Dec 03 18:40:07 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: darwin_signal.c,v 1.9 2003/11/20 07:12:34 manu Exp $ */
+/*     $NetBSD: darwin_signal.c,v 1.10 2003/12/03 18:40:07 manu Exp $ */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: darwin_signal.c,v 1.9 2003/11/20 07:12:34 manu Exp $");
+__KERNEL_RCSID(0, "$NetBSD: darwin_signal.c,v 1.10 2003/12/03 18:40:07 manu Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -130,28 +130,63 @@
        struct lwp *l;
        const struct ksiginfo *ksi;
 {
-       struct darwin_emuldata *ded;
-       int code[2];
+       if (darwin_sigfilter(l, ksi) == 0)
+               return;
 
-       /* 
-        * Send signals as software exception if the process requested that
-        * XXX this skips various checks (signal masks...)
-        */
-       ded = (struct darwin_emuldata *)l->l_proc->p_emuldata;
-       if (ded->ded_flags & DARWIN_DED_SIGEXC) {
-               code[0] = MACH_SOFT_SIGNAL;
-               code[1] = ksi->ksi_signo;
-               mach_exception(l, MACH_EXC_SOFTWARE, code);
-               return;
-       }
-
-       /* 
-        * If mach_trapsignal1 returns 0, the exception was intercepted at
-        * the Mach level, no signal is to be sent. if it returns an error,
-        * we call native trapsignal to fire a UNIX signal.
-        */
        if (mach_trapsignal1(l, ksi) != 0)
                trapsignal(l, ksi);
 
        return;
 }
+
+int
+darwin_sigfilter(l, ksi)
+       struct lwp *l;
+       const struct ksiginfo *ksi;
+{
+       struct proc *p = l->l_proc;
+       struct darwin_emuldata *ded;
+       int code[2];
+       int error;
+       int signo;
+
+       signo = ksi->ksi_signo;
+
+       /* 
+        * Don't generate Mach exeption for non 
+        * maskable, stop and continue signals 
+        */
+       if (sigprop[signo] & (SA_CANTMASK | SA_STOP | SA_CONT | SA_TTYSTOP))
+               return EINVAL;
+
+       /* Don't send an exception if the signal is masked or ignored */
+       if ((p->p_flag & P_TRACED) == 0) {
+               if ((sigismember(&p->p_sigctx.ps_sigignore, signo)) ||
+                   (sigismember(&p->p_sigctx.ps_sigmask, signo)))
+                       return EINVAL;
+       }
+
+       /* 
+        * Send signals as software exception if the process requested that.
+        */
+       ded = (struct darwin_emuldata *)p->p_emuldata;
+       if (ded->ded_flags & DARWIN_DED_SIGEXC) {
+               code[0] = MACH_SOFT_SIGNAL;
+               code[1] = signo;
+               error = mach_exception(l, MACH_EXC_SOFTWARE, code);
+
+               /* Like if the signal was sent, wakeup any waiting process */
+               if ((error == 0) &&
+                   p->p_sigctx.ps_sigwaited &&
+                   sigismember(p->p_sigctx.ps_sigwait, signo) &&
+                   p->p_stat != SSTOP) {
+                       p->p_sigctx.ps_sigwaited->ksi_info = ksi->ksi_info;
+                       p->p_sigctx.ps_sigwaited = NULL;
+                       wakeup_one(&p->p_sigctx.ps_sigwait);
+               }
+
+               return error;
+       }
+
+       return EINVAL;
+}
diff -r 17a5ee6225d2 -r 77b84525857d sys/compat/darwin/darwin_signal.h
--- a/sys/compat/darwin/darwin_signal.h Wed Dec 03 18:25:44 2003 +0000
+++ b/sys/compat/darwin/darwin_signal.h Wed Dec 03 18:40:07 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: darwin_signal.h,v 1.9 2003/11/17 01:52:14 manu Exp $ */
+/*     $NetBSD: darwin_signal.h,v 1.10 2003/12/03 18:40:07 manu Exp $ */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -81,6 +81,7 @@
 
 void darwin_sendsig(const ksiginfo_t *, const sigset_t *);
 void darwin_trapsignal(struct lwp *, const struct ksiginfo *);
+int darwin_sigfilter(struct lwp *, const struct ksiginfo *);
 
 #endif /* _DARWIN_SIGNAL_H_ */
 
diff -r 17a5ee6225d2 -r 77b84525857d sys/compat/mach/mach_notify.c
--- a/sys/compat/mach/mach_notify.c     Wed Dec 03 18:25:44 2003 +0000
+++ b/sys/compat/mach/mach_notify.c     Wed Dec 03 18:40:07 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: mach_notify.c,v 1.9 2003/11/25 23:17:40 manu Exp $ */
+/*     $NetBSD: mach_notify.c,v 1.10 2003/12/03 18:40:07 manu Exp $ */
 
 /*-
  * Copyright (c) 2003 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mach_notify.c,v 1.9 2003/11/25 23:17:40 manu Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mach_notify.c,v 1.10 2003/12/03 18:40:07 manu Exp $");
 
 #include "opt_ktrace.h"
 #include "opt_compat_mach.h" /* For COMPAT_MACH in <sys/ktrace.h> */
@@ -58,6 +58,8 @@
 #include <compat/mach/mach_message.h>
 #include <compat/mach/mach_services.h>
 
+#include <machine/mach_machdep.h>
+
 static void mach_siginfo_to_exception(const struct ksiginfo *, int *);
 
 void
@@ -72,9 +74,9 @@
                return;
        mp = mr->mr_notify_destroyed->mr_port;
 
-#ifdef DEBUG_MACH
-       if (mp == NULL) {
-               printf("Warning: notification right without a port\n");
+#ifdef DIAGNOSTIC
+       if ((mp == NULL) || (mp->mp_recv == NULL)) {
+               printf("mach_notify_port_destroyed: bad port or receiver\n");
                return;
        }
 #endif
@@ -114,9 +116,11 @@
                return;
        mp = mr->mr_notify_no_senders->mr_port;
 
-#ifdef DEBUG_MACH
-       if ((mp == NULL) || (mp->mp_datatype != MACH_MP_NOTIFY_SYNC)) {
-               printf("Warning: notification right without a port\n");
+#ifdef DIAGNOSTIC
+       if ((mp == NULL) || 
+           (mp->mp_recv == NULL) ||
+           (mp->mp_datatype != MACH_MP_NOTIFY_SYNC)) {
+               printf("mach_notify_port_no_senders: bad port or reciever\n");
                return;
        }
 #endif
@@ -157,9 +161,9 @@
                return;
        mp = mr->mr_notify_no_senders->mr_port;
 
-#ifdef DEBUG_MACH
-       if (mp == NULL) {
-               printf("Warning: notification right without a port\n");
+#ifdef DIAGNOSTIC
+       if ((mp == NULL) || (mp->mp_recv)) {
+               printf("mach_notify_port_dead_name: bad port or reciever\n");
                return;
        }
 #endif
@@ -191,10 +195,9 @@
 
 /* 
  * Exception handler 
- * Mach does not use signals, so mach_trapsignal will not try to send
- * any signal. But systems based on Mach (e.g.: Darwin), can use both 
- * Mach exceptions and UNIX signals. In order to allow the Mach layer 
- * to intercept the exception and inhibit UNIX signals, we have 
+ * Mach does not use signals. But systems based on Mach (e.g.: Darwin), 
+ * can use both Mach exceptions and UNIX signals. In order to allow the 
+ * Mach layer to intercept the exception and inhibit UNIX signals, we have 
  * mach_trapsignal1 returning an error. If it returns 0, then the 
  * exception was intercepted at the Mach level, and no signal should 
  * be produced. Else, a signal might be sent. darwin_trapinfo calls
@@ -205,7 +208,8 @@
        struct lwp *l;
        const struct ksiginfo *ksi;
 {
-       (void)mach_trapsignal1(l, ksi);
+       if (mach_trapsignal1(l, ksi) != 0)
+               trapsignal(l, ksi);
        return;
 }
 
@@ -219,6 +223,10 @@
        int exc_no;
        int code[2];
 
+       /* Don't inhinbit non maskable signals */
+       if (sigprop[ksi->ksi_signo] & SA_CANTMASK)
+               return EINVAL;
+
        med = (struct mach_emuldata *)p->p_emuldata;
 
        switch (ksi->ksi_signo) {
@@ -264,10 +272,39 @@
        struct mach_port *exc_port;
        int error;
 
+       /* 
+        * No exception if there is no exception port or if it has no receiver
+        */
        med = l->l_proc->p_emuldata;
-       if ((exc_port = med->med_exc[exc]) == NULL)
+       if (((exc_port = med->med_exc[exc]) == NULL) ||
+           (exc_port->mp_recv == NULL))
                return EINVAL;
 
+       /* 
+        * XXX Avoid a nasty deadlock because process in TX state 
+        * (traced and suspended) are invulnerable to kill -9. 
+        *
+        * The scenario:
+        * - the parent gets Child's signals though Mach exceptions
+        * - the parent is killed. Before calling the emulation hook
+        *   mach_exit(), it will wait for the child
+        * - the child receives SIGHUP, which is turned into a Mach
+        *   exception. The child sleeps awaiting for the parent
+        *   to tell it to continue. 
+        *   For some reason I do not understand, it goes in the
+        *   suspended state instead of the sleeping state.
+        * - Parents waits for the child, child is suspended, we
+        *   are stuck.
+        *
+        * By preventing exception to traced processes with
+        * a dying parent, a signal is sent instead of the 
+        * notification, this fixes the problem.
+        */
+       if ((l->l_proc->p_flag & P_TRACED) &&
+           (l->l_proc->p_pptr->p_flag & P_WEXIT)) {
+               return EINVAL;
+       }
+
 #ifdef DIAGNOSTIC
        if (exc_port->mp_datatype != MACH_MP_EXC_FLAGS)
                printf("mach_exception: unexpected datatype");



Home | Main Index | Thread Index | Old Index