summaryrefslogtreecommitdiff
path: root/sys-libs/libnih/files/libnih-1.0.3-signal-race.patch
blob: 364af7f5383e51224e06248913afe4a844784c8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
--- a/nih/signal.c
+++ b/nih/signal.c
@@ -337,17 +337,37 @@
 
 	nih_signal_init ();
 
+	/* Since this poller runs w/out signals masked, we do not want to try
+	 * and clear any other signals (like zeroing the caught array at the
+	 * end).  If we do that, we open a race:
+	 * - Walk the list of signals.
+	 * - First one is not set so we move on to the second one.
+	 * - First signal comes in while processing second and increments the
+	 *   caught array entry.
+	 * - Finish walking the whole list.
+	 * - Zero out the whole list and thus throw away the first signal.
+	 * Since the signal handlers can take any length of time, this race
+	 * can be open for a variable amount of time.
+	 */
+
 	NIH_LIST_FOREACH_SAFE (nih_signals, iter) {
 		NihSignal *signal = (NihSignal *)iter;
 
 		if (! signals_caught[signal->signum])
 			continue;
 
+		/* Now that we know we're going to process this signal, clear
+		 * out all pending counts for it.  There is a slight race here
+		 * where the same signal can come in, but the API has never
+		 * guaranteed exact coverage since POSIX does not provide it --
+		 * more than one signal can be collapsed into one event.  All
+		 * we can guarantee is that we'll notice signals that come in
+		 * once the handler runs.
+		 */
+		signals_caught[signal->signum] = 0;
+
 		signal->handler (signal->data, signal);
 	}
-
-	for (s = 0; s < NUM_SIGNALS; s++)
-		signals_caught[s] = 0;
 }