diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-11-21 16:36:27 +0100 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-11-23 11:14:33 +0100 |
commit | 39efd4ec9a2967e9720be7b66d9a4b31a58dbf61 (patch) | |
tree | 084c2ba72e4ffaf2dcc3d3c89f7ce32ab93d9827 /arch/s390/mm | |
parent | c68dba202f54a4c9c68a8bb83d426bf8a00c99f8 (diff) | |
download | linux-39efd4ec9a2967e9720be7b66d9a4b31a58dbf61.tar.gz linux-39efd4ec9a2967e9720be7b66d9a4b31a58dbf61.tar.bz2 linux-39efd4ec9a2967e9720be7b66d9a4b31a58dbf61.zip |
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.c | 19 |
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) unsigned int flags; int fault; + tsk = current; + /* + * The instruction that caused the program check has + * been nullified. Don't signal single step via SIGTRAP. + */ + clear_tsk_thread_flag(tsk, TIF_PER_TRAP); + if (notify_page_fault(regs)) return 0; - tsk = current; mm = tsk->mm; trans_exc_code = regs->int_parm_long; @@ -376,11 +382,6 @@ retry: goto retry; } } - /* - * The instruction that caused the program check will - * be repeated. Don't signal single step via SIGTRAP. - */ - clear_tsk_thread_flag(tsk, TIF_PER_TRAP); fault = 0; out_up: up_read(&mm->mmap_sem); @@ -427,6 +428,12 @@ void __kprobes do_asce_exception(struct pt_regs *regs) struct vm_area_struct *vma; unsigned long trans_exc_code; + /* + * The instruction that caused the program check has + * been nullified. Don't signal single step via SIGTRAP. + */ + clear_tsk_thread_flag(current, TIF_PER_TRAP); + trans_exc_code = regs->int_parm_long; if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm)) goto no_context; |