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