diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-10-30 10:16:47 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-10-30 10:16:43 -0400 |
commit | 20b40a794baf3b4b0320c0a77ce944d5d1a01f25 (patch) | |
tree | fb5eb62f8f75d8f6a31aae4c3cff3371f41cdd6d /arch/s390/kernel/entry64.S | |
parent | 3ee49c8f123257c72b74f398ef99ac3348c493cc (diff) |
[S390] signal race with restarting system calls
For a ERESTARTNOHAND/ERESTARTSYS/ERESTARTNOINTR restarting system call
do_signal will prepare the restart of the system call with a rewind of
the PSW before calling get_signal_to_deliver (where the debugger might
take control). For A ERESTART_RESTARTBLOCK restarting system call
do_signal will set -EINTR as return code.
There are two issues with this approach:
1) strace never sees ERESTARTNOHAND, ERESTARTSYS, ERESTARTNOINTR or
ERESTART_RESTARTBLOCK as the rewinding already took place or the
return code has been changed to -EINTR
2) if get_signal_to_deliver does not return with a signal to deliver
the restart via the repeat of the svc instruction is left in place.
This opens a race if another signal is made pending before the
system call instruction can be reexecuted. The original system call
will be restarted even if the second signal would have ended the
system call with -EINTR.
These two issues can be solved by dropping the early rewind of the
system call before get_signal_to_deliver has been called and by using
the TIF_RESTART_SVC magic to do the restart if no signal has to be
delivered. The only situation where the system call restart via the
repeat of the svc instruction is appropriate is when a SA_RESTART
signal is delivered to user space.
Unfortunately this breaks inferior calls by the debugger again. The
system call number and the length of the system call instruction is
lost over the inferior call and user space will see ERESTARTNOHAND/
ERESTARTSYS/ERESTARTNOINTR/ERESTART_RESTARTBLOCK. To correct this a
new ptrace interface is added to save/restore the system call number
and system call instruction length.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/entry64.S')
-rw-r--r-- | arch/s390/kernel/entry64.S | 30 |
1 files changed, 15 insertions, 15 deletions
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 3257f7f55551..7ff07d3a29c1 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -43,8 +43,7 @@ SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104 | |||
43 | SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112 | 43 | SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112 |
44 | SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120 | 44 | SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120 |
45 | SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 | 45 | SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 |
46 | SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC | 46 | SP_SVC_CODE = STACK_FRAME_OVERHEAD + __PT_SVC_CODE |
47 | SP_SVCNR = STACK_FRAME_OVERHEAD + __PT_SVCNR | ||
48 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE | 47 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE |
49 | 48 | ||
50 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER | 49 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER |
@@ -250,7 +249,7 @@ sysc_saveall: | |||
250 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 249 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA |
251 | CREATE_STACK_FRAME __LC_SAVE_AREA | 250 | CREATE_STACK_FRAME __LC_SAVE_AREA |
252 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | 251 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW |
253 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | 252 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC |
254 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 253 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
255 | sysc_vtime: | 254 | sysc_vtime: |
256 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 255 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
@@ -260,14 +259,14 @@ sysc_update: | |||
260 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 259 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
261 | LAST_BREAK | 260 | LAST_BREAK |
262 | sysc_do_svc: | 261 | sysc_do_svc: |
263 | llgh %r7,SP_SVCNR(%r15) | 262 | llgh %r7,SP_SVC_CODE+2(%r15) |
264 | slag %r7,%r7,2 # shift and test for svc 0 | 263 | slag %r7,%r7,2 # shift and test for svc 0 |
265 | jnz sysc_nr_ok | 264 | jnz sysc_nr_ok |
266 | # svc 0: system call number in %r1 | 265 | # svc 0: system call number in %r1 |
267 | llgfr %r1,%r1 # clear high word in r1 | 266 | llgfr %r1,%r1 # clear high word in r1 |
268 | cghi %r1,NR_syscalls | 267 | cghi %r1,NR_syscalls |
269 | jnl sysc_nr_ok | 268 | jnl sysc_nr_ok |
270 | sth %r1,SP_SVCNR(%r15) | 269 | sth %r1,SP_SVC_CODE+2(%r15) |
271 | slag %r7,%r1,2 # shift and test for svc 0 | 270 | slag %r7,%r1,2 # shift and test for svc 0 |
272 | sysc_nr_ok: | 271 | sysc_nr_ok: |
273 | larl %r10,sys_call_table | 272 | larl %r10,sys_call_table |
@@ -358,11 +357,12 @@ sysc_notify_resume: | |||
358 | # | 357 | # |
359 | sysc_restart: | 358 | sysc_restart: |
360 | ni __TI_flags+7(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC | 359 | ni __TI_flags+7(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC |
361 | lg %r7,SP_R2(%r15) # load new svc number | ||
362 | mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument | ||
363 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments | 360 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments |
364 | sth %r7,SP_SVCNR(%r15) | 361 | lghi %r7,0 # svc 0 returns -ENOSYS |
365 | slag %r7,%r7,2 | 362 | lh %r1,SP_SVC_CODE+2(%r15) # load new svc number |
363 | cghi %r1,NR_syscalls | ||
364 | jnl sysc_nr_ok # invalid svc number -> do svc 0 | ||
365 | slag %r7,%r1,2 | ||
366 | j sysc_nr_ok # restart svc | 366 | j sysc_nr_ok # restart svc |
367 | 367 | ||
368 | # | 368 | # |
@@ -370,7 +370,7 @@ sysc_restart: | |||
370 | # | 370 | # |
371 | sysc_singlestep: | 371 | sysc_singlestep: |
372 | ni __TI_flags+7(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP | 372 | ni __TI_flags+7(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP |
373 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number | 373 | xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) # clear svc code |
374 | la %r2,SP_PTREGS(%r15) # address of register-save area | 374 | la %r2,SP_PTREGS(%r15) # address of register-save area |
375 | larl %r14,sysc_return # load adr. of system return | 375 | larl %r14,sysc_return # load adr. of system return |
376 | jg do_per_trap | 376 | jg do_per_trap |
@@ -382,7 +382,7 @@ sysc_singlestep: | |||
382 | sysc_tracesys: | 382 | sysc_tracesys: |
383 | la %r2,SP_PTREGS(%r15) # load pt_regs | 383 | la %r2,SP_PTREGS(%r15) # load pt_regs |
384 | la %r3,0 | 384 | la %r3,0 |
385 | llgh %r0,SP_SVCNR(%r15) | 385 | llgh %r0,SP_SVC_CODE+2(%r15) |
386 | stg %r0,SP_R2(%r15) | 386 | stg %r0,SP_R2(%r15) |
387 | brasl %r14,do_syscall_trace_enter | 387 | brasl %r14,do_syscall_trace_enter |
388 | lghi %r0,NR_syscalls | 388 | lghi %r0,NR_syscalls |
@@ -470,7 +470,7 @@ ENTRY(pgm_check_handler) | |||
470 | jnz pgm_per # got per exception -> special case | 470 | jnz pgm_per # got per exception -> special case |
471 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA | 471 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA |
472 | CREATE_STACK_FRAME __LC_SAVE_AREA | 472 | CREATE_STACK_FRAME __LC_SAVE_AREA |
473 | xc SP_ILC(4,%r15),SP_ILC(%r15) | 473 | xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) |
474 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW | 474 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW |
475 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 475 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
476 | HANDLE_SIE_INTERCEPT | 476 | HANDLE_SIE_INTERCEPT |
@@ -551,7 +551,7 @@ pgm_svcper: | |||
551 | SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 551 | SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA |
552 | CREATE_STACK_FRAME __LC_SAVE_AREA | 552 | CREATE_STACK_FRAME __LC_SAVE_AREA |
553 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | 553 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW |
554 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | 554 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC |
555 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 555 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
556 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 556 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
557 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 557 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
@@ -571,7 +571,7 @@ pgm_svcper: | |||
571 | # | 571 | # |
572 | kernel_per: | 572 | kernel_per: |
573 | REENABLE_IRQS | 573 | REENABLE_IRQS |
574 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number | 574 | xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) # clear svc number |
575 | la %r2,SP_PTREGS(%r15) # address of register-save area | 575 | la %r2,SP_PTREGS(%r15) # address of register-save area |
576 | brasl %r14,do_per_trap | 576 | brasl %r14,do_per_trap |
577 | j pgm_exit | 577 | j pgm_exit |
@@ -973,7 +973,7 @@ cleanup_system_call: | |||
973 | stg %r11,0(%r12) | 973 | stg %r11,0(%r12) |
974 | CREATE_STACK_FRAME __LC_SAVE_AREA | 974 | CREATE_STACK_FRAME __LC_SAVE_AREA |
975 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | 975 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW |
976 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | 976 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC |
977 | mvc 8(8,%r12),__LC_THREAD_INFO | 977 | mvc 8(8,%r12),__LC_THREAD_INFO |
978 | cleanup_vtime: | 978 | cleanup_vtime: |
979 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) | 979 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) |