Fix knote handling for exiting processes: when triggering a NOTE_EXIT
authorguenther <guenther@openbsd.org>
Mon, 2 Aug 2010 19:54:07 +0000 (19:54 +0000)
committerguenther <guenther@openbsd.org>
Mon, 2 Aug 2010 19:54:07 +0000 (19:54 +0000)
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@

sys/kern/kern_event.c
sys/kern/kern_exit.c
sys/sys/event.h

index 6538129..19c250d 100644 (file)
@@ -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)
 {
index 3302bc6..792f839 100644 (file)
@@ -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
index c528d66..89fa08b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: event.h,v 1.14 2010/07/28 21:44:41 nicm Exp $ */
+/*     $OpenBSD: event.h,v 1.15 2010/08/02 19:54:07 guenther Exp $     */
 
 /*-
  * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
@@ -169,6 +169,7 @@ struct proc;
 extern void    knote(struct klist *list, long hint);
 extern void    knote_remove(struct proc *p, struct klist *list);
 extern void    knote_fdclose(struct proc *p, int fd);
+extern void    knote_processexit(struct process *);
 extern int     kqueue_register(struct kqueue *kq,
                    struct kevent *kev, struct proc *p);
 extern int     filt_seltrue(struct knote *kn, long hint);