Close alarm FDs on fork()
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 30 Sep 2016 20:11:51 +0000 (16:11 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 6 Oct 2016 19:41:48 +0000 (15:41 -0400)
If a parent has alarm FDs, forks, but doesn't exec, then its child will
inherit its alarm FDs.  Other than the child being able to mess with the
parent's alarms, which is bad, the parent is unable to fully be freed (as
in __proc_free()) until the child closes the FD - usually by exiting.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/benchutil/alarm.c

index 0d5bc59..e7ecc14 100644 (file)
@@ -39,6 +39,7 @@
 #include <parlib/spinlock.h>
 #include <parlib/timing.h>
 #include <sys/plan9_helpers.h>
+#include <sys/fork_cb.h>
 
 /* Helper to get your own alarm.   If you don't care about a return value, pass
  * 0 and it'll be ignored.  The alarm is built, but has no evq or timer set. */
@@ -136,10 +137,21 @@ static void reset_tchain_times(struct timer_chain *tchain)
        }
 }
 
+static void devalarm_forked(void)
+{
+       /* We need to poison the FDs too, in case the child attempts to use the
+        * alarms.  It'd be chaos if they read/wrote to an arbitrary open FD. */
+       close(global_tchain.ctlfd);
+       global_tchain.ctlfd = -42;
+       close(global_tchain.timerfd);
+       global_tchain.timerfd = -42;
+}
+
 static void __attribute__((constructor)) init_alarm_service(void)
 {
        int ctlfd, timerfd, alarmid;
        struct event_queue *ev_q;
+       static struct fork_cb devalarm_fork_cb = {.func = devalarm_forked};
 
        /* Sets up timer chain (only one chain per process) */
        spin_pdr_init(&global_tchain.lock);
@@ -172,6 +184,7 @@ static void __attribute__((constructor)) init_alarm_service(void)
        global_tchain.ctlfd = ctlfd;
        global_tchain.timerfd = timerfd;
        global_tchain.ev_q = ev_q;      /* mostly for debugging */
+       register_fork_cb(&devalarm_fork_cb);
 }
 
 /* Initializes a new awaiter.  Pass 0 for the function if you want it to be a