aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
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')
-rw-r--r--arch/s390/kernel/entry.S7
-rw-r--r--arch/s390/kernel/entry64.S7
-rw-r--r--arch/s390/kernel/signal.c2
-rw-r--r--arch/s390/mm/fault.c19
4 files changed, 21 insertions, 14 deletions
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index ef46f66bc0d6..f954b37740c0 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -231,12 +231,12 @@ sysc_work:
231 jo sysc_mcck_pending 231 jo sysc_mcck_pending
232 tm __TI_flags+3(%r12),_TIF_NEED_RESCHED 232 tm __TI_flags+3(%r12),_TIF_NEED_RESCHED
233 jo sysc_reschedule 233 jo sysc_reschedule
234 tm __TI_flags+3(%r12),_TIF_PER_TRAP
235 jo sysc_singlestep
234 tm __TI_flags+3(%r12),_TIF_SIGPENDING 236 tm __TI_flags+3(%r12),_TIF_SIGPENDING
235 jo sysc_sigpending 237 jo sysc_sigpending
236 tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME 238 tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME
237 jo sysc_notify_resume 239 jo sysc_notify_resume
238 tm __TI_flags+3(%r12),_TIF_PER_TRAP
239 jo sysc_singlestep
240 j sysc_return # beware of critical section cleanup 240 j sysc_return # beware of critical section cleanup
241 241
242# 242#
@@ -259,7 +259,6 @@ sysc_mcck_pending:
259# _TIF_SIGPENDING is set, call do_signal 259# _TIF_SIGPENDING is set, call do_signal
260# 260#
261sysc_sigpending: 261sysc_sigpending:
262 ni __TI_flags+3(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP
263 lr %r2,%r11 # pass pointer to pt_regs 262 lr %r2,%r11 # pass pointer to pt_regs
264 l %r1,BASED(.Ldo_signal) 263 l %r1,BASED(.Ldo_signal)
265 basr %r14,%r1 # call do_signal 264 basr %r14,%r1 # call do_signal
@@ -286,7 +285,7 @@ sysc_notify_resume:
286# _TIF_PER_TRAP is set, call do_per_trap 285# _TIF_PER_TRAP is set, call do_per_trap
287# 286#
288sysc_singlestep: 287sysc_singlestep:
289 ni __TI_flags+3(%r12),255-(_TIF_SYSCALL | _TIF_PER_TRAP) 288 ni __TI_flags+3(%r12),255-_TIF_PER_TRAP
290 lr %r2,%r11 # pass pointer to pt_regs 289 lr %r2,%r11 # pass pointer to pt_regs
291 l %r1,BASED(.Ldo_per_trap) 290 l %r1,BASED(.Ldo_per_trap)
292 la %r14,BASED(sysc_return) 291 la %r14,BASED(sysc_return)
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index e42842a3072b..7a2d22dda9ef 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -262,12 +262,12 @@ sysc_work:
262 jo sysc_mcck_pending 262 jo sysc_mcck_pending
263 tm __TI_flags+7(%r12),_TIF_NEED_RESCHED 263 tm __TI_flags+7(%r12),_TIF_NEED_RESCHED
264 jo sysc_reschedule 264 jo sysc_reschedule
265 tm __TI_flags+7(%r12),_TIF_PER_TRAP
266 jo sysc_singlestep
265 tm __TI_flags+7(%r12),_TIF_SIGPENDING 267 tm __TI_flags+7(%r12),_TIF_SIGPENDING
266 jo sysc_sigpending 268 jo sysc_sigpending
267 tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME 269 tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME
268 jo sysc_notify_resume 270 jo sysc_notify_resume
269 tm __TI_flags+7(%r12),_TIF_PER_TRAP
270 jo sysc_singlestep
271 j sysc_return # beware of critical section cleanup 271 j sysc_return # beware of critical section cleanup
272 272
273# 273#
@@ -288,7 +288,6 @@ sysc_mcck_pending:
288# _TIF_SIGPENDING is set, call do_signal 288# _TIF_SIGPENDING is set, call do_signal
289# 289#
290sysc_sigpending: 290sysc_sigpending:
291 ni __TI_flags+7(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP
292 lgr %r2,%r11 # pass pointer to pt_regs 291 lgr %r2,%r11 # pass pointer to pt_regs
293 brasl %r14,do_signal 292 brasl %r14,do_signal
294 tm __TI_flags+7(%r12),_TIF_SYSCALL 293 tm __TI_flags+7(%r12),_TIF_SYSCALL
@@ -313,7 +312,7 @@ sysc_notify_resume:
313# _TIF_PER_TRAP is set, call do_per_trap 312# _TIF_PER_TRAP is set, call do_per_trap
314# 313#
315sysc_singlestep: 314sysc_singlestep:
316 ni __TI_flags+7(%r12),255-(_TIF_SYSCALL | _TIF_PER_TRAP) 315 ni __TI_flags+7(%r12),255-_TIF_PER_TRAP
317 lgr %r2,%r11 # pass pointer to pt_regs 316 lgr %r2,%r11 # pass pointer to pt_regs
318 larl %r14,sysc_return 317 larl %r14,sysc_return
319 jg do_per_trap 318 jg do_per_trap
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index d1259d875074..c3ff70a7b247 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -461,6 +461,8 @@ void do_signal(struct pt_regs *regs)
461 /* Restart system call with magic TIF bit. */ 461 /* Restart system call with magic TIF bit. */
462 regs->gprs[2] = regs->orig_gpr2; 462 regs->gprs[2] = regs->orig_gpr2;
463 set_thread_flag(TIF_SYSCALL); 463 set_thread_flag(TIF_SYSCALL);
464 if (test_thread_flag(TIF_SINGLE_STEP))
465 set_thread_flag(TIF_PER_TRAP);
464 break; 466 break;
465 } 467 }
466 } 468 }
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;