diff options
author | Anton Ivanov <aivanov@brocade.com> | 2015-12-21 06:28:02 -0500 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2016-01-10 15:49:47 -0500 |
commit | d5e3f5cbe5cee7fe6da26566559a978547179b37 (patch) | |
tree | 7f40e2da3a070e811a412865ffbf5c317844e257 | |
parent | 0754fb298f2f2719f0393491d010d46cfb25d043 (diff) |
um: Prevent IRQ handler reentrancy
The existing IRQ handler design in UML does not prevent reentrancy
This is mitigated by fd-enable/fd-disable semantics for the IO
portion of the UML subsystem. The timer, however, can and is
re-entered resulting in very deep stack usage and occasional
stack exhaustion.
This patch prevents this by checking if there is a timer
interrupt in-flight before processing any pending timer interrupts.
Signed-off-by: Anton Ivanov <aivanov@brocade.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r-- | arch/um/os-Linux/signal.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index c211153ca69a..7801666514ed 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c | |||
@@ -62,6 +62,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc) | |||
62 | 62 | ||
63 | static int signals_enabled; | 63 | static int signals_enabled; |
64 | static unsigned int signals_pending; | 64 | static unsigned int signals_pending; |
65 | static unsigned int signals_active = 0; | ||
65 | 66 | ||
66 | void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) | 67 | void sig_handler(int sig, struct siginfo *si, mcontext_t *mc) |
67 | { | 68 | { |
@@ -101,7 +102,12 @@ void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc) | |||
101 | 102 | ||
102 | block_signals(); | 103 | block_signals(); |
103 | 104 | ||
105 | signals_active |= SIGALRM_MASK; | ||
106 | |||
104 | timer_real_alarm_handler(mc); | 107 | timer_real_alarm_handler(mc); |
108 | |||
109 | signals_active &= ~SIGALRM_MASK; | ||
110 | |||
105 | set_signals(enabled); | 111 | set_signals(enabled); |
106 | } | 112 | } |
107 | 113 | ||
@@ -286,8 +292,16 @@ void unblock_signals(void) | |||
286 | if (save_pending & SIGIO_MASK) | 292 | if (save_pending & SIGIO_MASK) |
287 | sig_handler_common(SIGIO, NULL, NULL); | 293 | sig_handler_common(SIGIO, NULL, NULL); |
288 | 294 | ||
289 | if (save_pending & SIGALRM_MASK) | 295 | /* Do not reenter the handler */ |
296 | |||
297 | if ((save_pending & SIGALRM_MASK) && (!(signals_active & SIGALRM_MASK))) | ||
290 | timer_real_alarm_handler(NULL); | 298 | timer_real_alarm_handler(NULL); |
299 | |||
300 | /* Rerun the loop only if there is still pending SIGIO and not in TIMER handler */ | ||
301 | |||
302 | if (!(signals_pending & SIGIO_MASK) && (signals_active & SIGALRM_MASK)) | ||
303 | return; | ||
304 | |||
291 | } | 305 | } |
292 | } | 306 | } |
293 | 307 | ||