Commit 55bb9480f9159b229ac3c3454c97b62d1e0a7e80
1 parent
5c39c0ab5e
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
ARC: [Review] Prevent incorrect syscall restarts
Per Al Viro's "signals for dummies" https://lkml.org/lkml/2012/12/6/366 there are 3 golden rules for (not) restarting syscalls: " What we need to guarantee is * restarts do not happen on signals caught in interrupts or exceptions * restarts do not happen on signals caught in sigreturn() * restart should happen only once, even if we get through do_signal() many times." ARC Port already handled #1, this patch fixes #2 and #3. We use the additional state in pt_regs->orig_r8 to ckh if restarting has already been done once. Thanks to Al Viro for spotting this. Signed-off-by: Vineet Gupta <vgupta@synopsys.com> Cc: Al Viro <viro@ZenIV.linux.org.uk>
Showing 2 changed files with 11 additions and 4 deletions Side-by-side Diff
arch/arc/include/asm/ptrace.h
... | ... | @@ -100,6 +100,9 @@ |
100 | 100 | #define in_syscall(regs) (regs->event & orig_r8_IS_SCALL) |
101 | 101 | #define in_brkpt_trap(regs) (regs->event & orig_r8_IS_BRKPT) |
102 | 102 | |
103 | +#define syscall_wont_restart(regs) (regs->event |= orig_r8_IS_SCALL_RESTARTED) | |
104 | +#define syscall_restartable(regs) !(regs->event & orig_r8_IS_SCALL_RESTARTED) | |
105 | + | |
103 | 106 | #define current_pt_regs() \ |
104 | 107 | ({ \ |
105 | 108 | /* open-coded current_thread_info() */ \ |
arch/arc/kernel/signal.c
... | ... | @@ -128,6 +128,9 @@ |
128 | 128 | if (restore_altstack(&sf->uc.uc_stack)) |
129 | 129 | goto badframe; |
130 | 130 | |
131 | + /* Don't restart from sigreturn */ | |
132 | + syscall_wont_restart(regs); | |
133 | + | |
131 | 134 | return regs->r0; |
132 | 135 | |
133 | 136 | badframe: |
134 | 137 | |
135 | 138 | |
... | ... | @@ -318,13 +321,13 @@ |
318 | 321 | |
319 | 322 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
320 | 323 | |
321 | - /* Are we from a system call? */ | |
322 | - restart_scall = in_syscall(regs); | |
324 | + restart_scall = in_syscall(regs) && syscall_restartable(regs); | |
323 | 325 | |
324 | 326 | if (signr > 0) { |
325 | - if (restart_scall) | |
327 | + if (restart_scall) { | |
326 | 328 | arc_restart_syscall(&ka, regs); |
327 | - | |
329 | + syscall_wont_restart(regs); /* No more restarts */ | |
330 | + } | |
328 | 331 | handle_signal(signr, &ka, &info, regs); |
329 | 332 | return; |
330 | 333 | } |
... | ... | @@ -339,6 +342,7 @@ |
339 | 342 | regs->r8 = __NR_restart_syscall; |
340 | 343 | regs->ret -= 4; |
341 | 344 | } |
345 | + syscall_wont_restart(regs); /* No more restarts */ | |
342 | 346 | } |
343 | 347 | |
344 | 348 | /* If there's no signal to deliver, restore the saved sigmask back */ |