aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2012-11-21 10:36:27 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-11-23 05:14:33 -0500
commit39efd4ec9a2967e9720be7b66d9a4b31a58dbf61 (patch)
tree084c2ba72e4ffaf2dcc3d3c89f7ce32ab93d9827 /arch/s390/mm
parentc68dba202f54a4c9c68a8bb83d426bf8a00c99f8 (diff)
s390/ptrace: race of single stepping vs signal delivery
The current single step code is racy in regard to concurrent delivery of signals. If a signal is delivered after a PER program check occurred but before the TIF_PER_TRAP bit has been checked in entry[64].S the code clears TIF_PER_TRAP and then calls do_signal. This is wrong, if the instruction completed (or has been suppressed) a SIGTRAP should be delivered to the debugger in any case. Only if the instruction has been nullified the SIGTRAP may not be send. The new logic always sets TIF_PER_TRAP if the program check indicates PER tracing but removes it again for all program checks that are nullifying. The effect is that for each change in the PSW address we now get a single SIGTRAP. Reported-by: Andreas Arnez <arnez@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/mm')
-rw-r--r--arch/s390/mm/fault.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 870a644895f0..42601d6e166f 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -277,10 +277,16 @@ static inline int do_exception(struct pt_regs *regs, int access)
277 unsigned int flags; 277 unsigned int flags;
278 int fault; 278 int fault;
279 279
280 tsk = current;
281 /*
282 * The instruction that caused the program check has
283 * been nullified. Don't signal single step via SIGTRAP.
284 */
285 clear_tsk_thread_flag(tsk, TIF_PER_TRAP);
286
280 if (notify_page_fault(regs)) 287 if (notify_page_fault(regs))
281 return 0; 288 return 0;
282 289
283 tsk = current;
284 mm = tsk->mm; 290 mm = tsk->mm;
285 trans_exc_code = regs->int_parm_long; 291 trans_exc_code = regs->int_parm_long;
286 292
@@ -376,11 +382,6 @@ retry:
376 goto retry; 382 goto retry;
377 } 383 }
378 } 384 }
379 /*
380 * The instruction that caused the program check will
381 * be repeated. Don't signal single step via SIGTRAP.
382 */
383 clear_tsk_thread_flag(tsk, TIF_PER_TRAP);
384 fault = 0; 385 fault = 0;
385out_up: 386out_up:
386 up_read(&mm->mmap_sem); 387 up_read(&mm->mmap_sem);
@@ -427,6 +428,12 @@ void __kprobes do_asce_exception(struct pt_regs *regs)
427 struct vm_area_struct *vma; 428 struct vm_area_struct *vma;
428 unsigned long trans_exc_code; 429 unsigned long trans_exc_code;
429 430
431 /*
432 * The instruction that caused the program check has
433 * been nullified. Don't signal single step via SIGTRAP.
434 */
435 clear_tsk_thread_flag(current, TIF_PER_TRAP);
436
430 trans_exc_code = regs->int_parm_long; 437 trans_exc_code = regs->int_parm_long;
431 if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm)) 438 if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
432 goto no_context; 439 goto no_context;