summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2010-08-02 19:54:08 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2010-08-02 19:54:08 +0000
commita625e136b7a7dffe00dec15e6a7e483df3fd33be (patch)
tree3c907bffd1eac9154218208e7c253ffddf50e85f /sys/kern
parentd5946e6e400083e7d659a2e414a328cd2582df92 (diff)
Fix knote handling for exiting processes: when triggering a NOTE_EXIT
knote, remove it from the process's klist; after handling those, remove and drop any remaining knotes from the process's klist. Ban attaching knotes to processes that have started exiting or attaching them via the pid of a thread other than the main thread. ok tedu@, deraadt@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_event.c25
-rw-r--r--sys/kern/kern_exit.c6
2 files changed, 26 insertions, 5 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 6538129fa1f..19c250de2fc 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_event.c,v 1.37 2010/07/28 21:44:41 nicm Exp $ */
+/* $OpenBSD: kern_event.c,v 1.38 2010/08/02 19:54:07 guenther Exp $ */
/*-
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
@@ -198,6 +198,10 @@ filt_procattach(struct knote *kn)
if (p == NULL)
return (ESRCH);
+ /* threads and exiting processes can't be specified */
+ if (p->p_flag & (P_THREAD|P_WEXIT))
+ return (ESRCH);
+
/*
* Fail if it's not owned by you, or the last exec gave us
* setuid/setgid privs (unless you're root).
@@ -262,11 +266,15 @@ filt_proc(struct knote *kn, long hint)
kn->kn_fflags |= event;
/*
- * process is gone, so flag the event as finished.
+ * process is gone, so flag the event as finished and remove it
+ * from the process's klist
*/
if (event == NOTE_EXIT) {
+ struct process *pr = kn->kn_ptr.p_proc->p_p;
+
kn->kn_status |= KN_DETACHED;
kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+ SLIST_REMOVE(&pr->ps_klist, kn, knote, kn_selnext);
return (1);
}
@@ -938,6 +946,19 @@ knote_fdclose(struct proc *p, int fd)
knote_remove(p, list);
}
+/*
+ * handle a process exiting, including the triggering of NOTE_EXIT notes
+ * XXX this could be more efficient, doing a single pass down the klist
+ */
+void
+knote_processexit(struct process *pr)
+{
+ KNOTE(&pr->ps_klist, NOTE_EXIT);
+
+ /* remove other knotes hanging off the process */
+ knote_remove(pr->ps_mainproc, &pr->ps_klist);
+}
+
void
knote_attach(struct knote *kn, struct filedesc *fdp)
{
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 3302bc6eb00..792f8391340 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exit.c,v 1.96 2010/07/26 01:56:27 guenther Exp $ */
+/* $OpenBSD: kern_exit.c,v 1.97 2010/08/02 19:54:07 guenther Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
@@ -298,8 +298,8 @@ exit1(struct proc *p, int rv, int flags)
p->p_pctcpu = 0;
if ((p->p_flag & P_THREAD) == 0) {
- /* notify interested parties of our demise */
- KNOTE(&pr->ps_klist, NOTE_EXIT);
+ /* notify interested parties of our demise and clean up */
+ knote_processexit(pr);
/*
* Notify parent that we're gone. If we have P_NOZOMBIE