aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2011-10-30 10:16:47 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2011-10-30 10:16:43 -0400
commit20b40a794baf3b4b0320c0a77ce944d5d1a01f25 (patch)
treefb5eb62f8f75d8f6a31aae4c3cff3371f41cdd6d
parent3ee49c8f123257c72b74f398ef99ac3348c493cc (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>
-rw-r--r--arch/s390/include/asm/ptrace.h5
-rw-r--r--arch/s390/include/asm/syscall.h5
-rw-r--r--arch/s390/include/asm/thread_info.h1
-rw-r--r--arch/s390/kernel/asm-offsets.c3
-rw-r--r--arch/s390/kernel/compat_signal.c2
-rw-r--r--arch/s390/kernel/entry.S28
-rw-r--r--arch/s390/kernel/entry64.S30
-rw-r--r--arch/s390/kernel/ptrace.c51
-rw-r--r--arch/s390/kernel/signal.c107
-rw-r--r--include/linux/elf.h1
10 files changed, 142 insertions, 91 deletions
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 62fd80c9e98c..93c907b4776f 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -328,8 +328,7 @@ struct pt_regs
328 psw_t psw; 328 psw_t psw;
329 unsigned long gprs[NUM_GPRS]; 329 unsigned long gprs[NUM_GPRS];
330 unsigned long orig_gpr2; 330 unsigned long orig_gpr2;
331 unsigned short ilc; 331 unsigned int svc_code;
332 unsigned short svcnr;
333}; 332};
334 333
335/* 334/*
@@ -487,6 +486,8 @@ typedef struct
487#define PTRACE_POKETEXT_AREA 0x5004 486#define PTRACE_POKETEXT_AREA 0x5004
488#define PTRACE_POKEDATA_AREA 0x5005 487#define PTRACE_POKEDATA_AREA 0x5005
489#define PTRACE_GET_LAST_BREAK 0x5006 488#define PTRACE_GET_LAST_BREAK 0x5006
489#define PTRACE_PEEK_SYSTEM_CALL 0x5007
490#define PTRACE_POKE_SYSTEM_CALL 0x5008
490 491
491/* 492/*
492 * PT_PROT definition is loosely based on hppa bsd definition in 493 * PT_PROT definition is loosely based on hppa bsd definition in
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h
index 5c0246b955d8..614267f60713 100644
--- a/arch/s390/include/asm/syscall.h
+++ b/arch/s390/include/asm/syscall.h
@@ -13,6 +13,7 @@
13#define _ASM_SYSCALL_H 1 13#define _ASM_SYSCALL_H 1
14 14
15#include <linux/sched.h> 15#include <linux/sched.h>
16#include <linux/err.h>
16#include <asm/ptrace.h> 17#include <asm/ptrace.h>
17 18
18/* 19/*
@@ -25,7 +26,7 @@ extern const unsigned int sys_call_table[];
25static inline long syscall_get_nr(struct task_struct *task, 26static inline long syscall_get_nr(struct task_struct *task,
26 struct pt_regs *regs) 27 struct pt_regs *regs)
27{ 28{
28 return regs->svcnr ? regs->svcnr : -1; 29 return regs->svc_code ? (regs->svc_code & 0xffff) : -1;
29} 30}
30 31
31static inline void syscall_rollback(struct task_struct *task, 32static inline void syscall_rollback(struct task_struct *task,
@@ -37,7 +38,7 @@ static inline void syscall_rollback(struct task_struct *task,
37static inline long syscall_get_error(struct task_struct *task, 38static inline long syscall_get_error(struct task_struct *task,
38 struct pt_regs *regs) 39 struct pt_regs *regs)
39{ 40{
40 return (regs->gprs[2] >= -4096UL) ? -regs->gprs[2] : 0; 41 return IS_ERR_VALUE(regs->gprs[2]) ? regs->gprs[2] : 0;
41} 42}
42 43
43static inline long syscall_get_return_value(struct task_struct *task, 44static inline long syscall_get_return_value(struct task_struct *task,
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h
index f9a9a10979c9..0c4788eb5a65 100644
--- a/arch/s390/include/asm/thread_info.h
+++ b/arch/s390/include/asm/thread_info.h
@@ -48,6 +48,7 @@ struct thread_info {
48 unsigned int cpu; /* current CPU */ 48 unsigned int cpu; /* current CPU */
49 int preempt_count; /* 0 => preemptable, <0 => BUG */ 49 int preempt_count; /* 0 => preemptable, <0 => BUG */
50 struct restart_block restart_block; 50 struct restart_block restart_block;
51 unsigned int system_call;
51 __u64 user_timer; 52 __u64 user_timer;
52 __u64 system_timer; 53 __u64 system_timer;
53 unsigned long last_break; /* last breaking-event-address. */ 54 unsigned long last_break; /* last breaking-event-address. */
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 1140035b1cd8..751318765e2e 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -45,8 +45,7 @@ int main(void)
45 DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); 45 DEFINE(__PT_PSW, offsetof(struct pt_regs, psw));
46 DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); 46 DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
47 DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); 47 DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
48 DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc)); 48 DEFINE(__PT_SVC_CODE, offsetof(struct pt_regs, svc_code));
49 DEFINE(__PT_SVCNR, offsetof(struct pt_regs, svcnr));
50 DEFINE(__PT_SIZE, sizeof(struct pt_regs)); 49 DEFINE(__PT_SIZE, sizeof(struct pt_regs));
51 BLANK(); 50 BLANK();
52 DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain)); 51 DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index a9a285b8c4ad..d7c8e54c32e7 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -342,7 +342,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
342 return err; 342 return err;
343 343
344 restore_fp_regs(&current->thread.fp_regs); 344 restore_fp_regs(&current->thread.fp_regs);
345 regs->svcnr = 0; /* disable syscall checks */ 345 regs->svc_code = 0; /* disable syscall checks */
346 return 0; 346 return 0;
347} 347}
348 348
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 195387ab7c98..afe3685d30e7 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -43,8 +43,7 @@ SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52
43SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56 43SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
44SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60 44SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60
45SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 45SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
46SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC 46SP_SVC_CODE = STACK_FRAME_OVERHEAD + __PT_SVC_CODE
47SP_SVCNR = STACK_FRAME_OVERHEAD + __PT_SVCNR
48SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE 47SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
49 48
50_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ 49_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
@@ -229,7 +228,7 @@ sysc_saveall:
229 SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA 228 SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
230 CREATE_STACK_FRAME __LC_SAVE_AREA 229 CREATE_STACK_FRAME __LC_SAVE_AREA
231 mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW 230 mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW
232 mvc SP_ILC(4,%r15),__LC_SVC_ILC 231 mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC
233 l %r12,__LC_THREAD_INFO # load pointer to thread_info struct 232 l %r12,__LC_THREAD_INFO # load pointer to thread_info struct
234sysc_vtime: 233sysc_vtime:
235 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER 234 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
@@ -239,12 +238,12 @@ sysc_update:
239 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER 238 mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
240sysc_do_svc: 239sysc_do_svc:
241 xr %r7,%r7 240 xr %r7,%r7
242 icm %r7,3,SP_SVCNR(%r15) # load svc number and test for svc 0 241 icm %r7,3,SP_SVC_CODE+2(%r15)# load svc number and test for svc 0
243 bnz BASED(sysc_nr_ok) # svc number > 0 242 bnz BASED(sysc_nr_ok) # svc number > 0
244 # svc 0: system call number in %r1 243 # svc 0: system call number in %r1
245 cl %r1,BASED(.Lnr_syscalls) 244 cl %r1,BASED(.Lnr_syscalls)
246 bnl BASED(sysc_nr_ok) 245 bnl BASED(sysc_nr_ok)
247 sth %r1,SP_SVCNR(%r15) 246 sth %r1,SP_SVC_CODE+2(%r15)
248 lr %r7,%r1 # copy svc number to %r7 247 lr %r7,%r1 # copy svc number to %r7
249sysc_nr_ok: 248sysc_nr_ok:
250 sll %r7,2 # svc number *4 249 sll %r7,2 # svc number *4
@@ -335,10 +334,11 @@ sysc_notify_resume:
335# 334#
336sysc_restart: 335sysc_restart:
337 ni __TI_flags+3(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC 336 ni __TI_flags+3(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
338 l %r7,SP_R2(%r15) # load new svc number
339 mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
340 lm %r2,%r6,SP_R2(%r15) # load svc arguments 337 lm %r2,%r6,SP_R2(%r15) # load svc arguments
341 sth %r7,SP_SVCNR(%r15) 338 xr %r7,%r7 # svc 0 returns -ENOSYS
339 clc SP_SVC_CODE+2(%r15),BASED(.Lnr_syscalls+2)
340 bnl BASED(sysc_nr_ok) # invalid svc number -> do svc 0
341 icm %r7,3,SP_SVC_CODE+2(%r15)# load new svc number
342 b BASED(sysc_nr_ok) # restart svc 342 b BASED(sysc_nr_ok) # restart svc
343 343
344# 344#
@@ -346,7 +346,7 @@ sysc_restart:
346# 346#
347sysc_singlestep: 347sysc_singlestep:
348 ni __TI_flags+3(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP 348 ni __TI_flags+3(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP
349 xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number 349 xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) # clear svc code
350 la %r2,SP_PTREGS(%r15) # address of register-save area 350 la %r2,SP_PTREGS(%r15) # address of register-save area
351 l %r1,BASED(.Lhandle_per) # load adr. of per handler 351 l %r1,BASED(.Lhandle_per) # load adr. of per handler
352 la %r14,BASED(sysc_return) # load adr. of system return 352 la %r14,BASED(sysc_return) # load adr. of system return
@@ -361,7 +361,7 @@ sysc_tracesys:
361 la %r2,SP_PTREGS(%r15) # load pt_regs 361 la %r2,SP_PTREGS(%r15) # load pt_regs
362 la %r3,0 362 la %r3,0
363 xr %r0,%r0 363 xr %r0,%r0
364 icm %r0,3,SP_SVCNR(%r15) 364 icm %r0,3,SP_SVC_CODE(%r15)
365 st %r0,SP_R2(%r15) 365 st %r0,SP_R2(%r15)
366 basr %r14,%r1 366 basr %r14,%r1
367 cl %r2,BASED(.Lnr_syscalls) 367 cl %r2,BASED(.Lnr_syscalls)
@@ -454,7 +454,7 @@ ENTRY(pgm_check_handler)
454 bnz BASED(pgm_per) # got per exception -> special case 454 bnz BASED(pgm_per) # got per exception -> special case
455 SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA 455 SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA
456 CREATE_STACK_FRAME __LC_SAVE_AREA 456 CREATE_STACK_FRAME __LC_SAVE_AREA
457 xc SP_ILC(4,%r15),SP_ILC(%r15) 457 xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15)
458 mvc SP_PSW(8,%r15),__LC_PGM_OLD_PSW 458 mvc SP_PSW(8,%r15),__LC_PGM_OLD_PSW
459 l %r12,__LC_THREAD_INFO # load pointer to thread_info struct 459 l %r12,__LC_THREAD_INFO # load pointer to thread_info struct
460 tm SP_PSW+1(%r15),0x01 # interrupting from user ? 460 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
@@ -531,7 +531,7 @@ pgm_svcper:
531 SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA 531 SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA
532 CREATE_STACK_FRAME __LC_SAVE_AREA 532 CREATE_STACK_FRAME __LC_SAVE_AREA
533 mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW 533 mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW
534 mvc SP_ILC(4,%r15),__LC_SVC_ILC 534 mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC
535 l %r12,__LC_THREAD_INFO # load pointer to thread_info struct 535 l %r12,__LC_THREAD_INFO # load pointer to thread_info struct
536 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER 536 UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER
537 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER 537 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
@@ -550,7 +550,7 @@ pgm_svcper:
550# 550#
551kernel_per: 551kernel_per:
552 REENABLE_IRQS 552 REENABLE_IRQS
553 xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) 553 xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15)
554 la %r2,SP_PTREGS(%r15) # address of register-save area 554 la %r2,SP_PTREGS(%r15) # address of register-save area
555 l %r1,BASED(.Lhandle_per) # load adr. of per handler 555 l %r1,BASED(.Lhandle_per) # load adr. of per handler
556 basr %r14,%r1 # branch to do_single_step 556 basr %r14,%r1 # branch to do_single_step
@@ -966,7 +966,7 @@ cleanup_system_call:
966 st %r15,12(%r12) 966 st %r15,12(%r12)
967 CREATE_STACK_FRAME __LC_SAVE_AREA 967 CREATE_STACK_FRAME __LC_SAVE_AREA
968 mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW 968 mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW
969 mvc SP_ILC(4,%r15),__LC_SVC_ILC 969 mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC
970 mvc 0(4,%r12),__LC_THREAD_INFO 970 mvc 0(4,%r12),__LC_THREAD_INFO
971cleanup_vtime: 971cleanup_vtime:
972 clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12) 972 clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12)
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
43SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112 43SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112
44SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120 44SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120
45SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 45SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
46SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC 46SP_SVC_CODE = STACK_FRAME_OVERHEAD + __PT_SVC_CODE
47SP_SVCNR = STACK_FRAME_OVERHEAD + __PT_SVCNR
48SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE 47SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
49 48
50STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER 49STACK_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
255sysc_vtime: 254sysc_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
262sysc_do_svc: 261sysc_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
272sysc_nr_ok: 271sysc_nr_ok:
273 larl %r10,sys_call_table 272 larl %r10,sys_call_table
@@ -358,11 +357,12 @@ sysc_notify_resume:
358# 357#
359sysc_restart: 358sysc_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#
371sysc_singlestep: 371sysc_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:
382sysc_tracesys: 382sysc_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#
572kernel_per: 572kernel_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
978cleanup_vtime: 978cleanup_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)
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index ae0e14b8880c..bae1cc49fe96 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -42,6 +42,7 @@ enum s390_regset {
42 REGSET_GENERAL, 42 REGSET_GENERAL,
43 REGSET_FP, 43 REGSET_FP,
44 REGSET_LAST_BREAK, 44 REGSET_LAST_BREAK,
45 REGSET_SYSTEM_CALL,
45 REGSET_GENERAL_EXTENDED, 46 REGSET_GENERAL_EXTENDED,
46}; 47};
47 48
@@ -303,6 +304,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data)
303 high order bit but older gdb's rely on it */ 304 high order bit but older gdb's rely on it */
304 data |= PSW_ADDR_AMODE; 305 data |= PSW_ADDR_AMODE;
305#endif 306#endif
307 if (addr == (addr_t) &dummy->regs.psw.addr)
308 /*
309 * The debugger changed the instruction address,
310 * reset system call restart, see signal.c:do_signal
311 */
312 task_thread_info(child)->system_call = 0;
313
306 *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; 314 *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data;
307 315
308 } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { 316 } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
@@ -610,6 +618,11 @@ static int __poke_user_compat(struct task_struct *child,
610 /* Build a 64 bit psw address from 31 bit address. */ 618 /* Build a 64 bit psw address from 31 bit address. */
611 task_pt_regs(child)->psw.addr = 619 task_pt_regs(child)->psw.addr =
612 (__u64) tmp & PSW32_ADDR_INSN; 620 (__u64) tmp & PSW32_ADDR_INSN;
621 /*
622 * The debugger changed the instruction address,
623 * reset system call restart, see signal.c:do_signal
624 */
625 task_thread_info(child)->system_call = 0;
613 } else { 626 } else {
614 /* gpr 0-15 */ 627 /* gpr 0-15 */
615 *(__u32*)((addr_t) &task_pt_regs(child)->psw 628 *(__u32*)((addr_t) &task_pt_regs(child)->psw
@@ -737,7 +750,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
737 * debugger stored an invalid system call number. Skip 750 * debugger stored an invalid system call number. Skip
738 * the system call and the system call restart handling. 751 * the system call and the system call restart handling.
739 */ 752 */
740 regs->svcnr = 0; 753 regs->svc_code = 0;
741 ret = -1; 754 ret = -1;
742 } 755 }
743 756
@@ -899,6 +912,26 @@ static int s390_last_break_get(struct task_struct *target,
899 912
900#endif 913#endif
901 914
915static int s390_system_call_get(struct task_struct *target,
916 const struct user_regset *regset,
917 unsigned int pos, unsigned int count,
918 void *kbuf, void __user *ubuf)
919{
920 unsigned int *data = &task_thread_info(target)->system_call;
921 return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
922 data, 0, sizeof(unsigned int));
923}
924
925static int s390_system_call_set(struct task_struct *target,
926 const struct user_regset *regset,
927 unsigned int pos, unsigned int count,
928 const void *kbuf, const void __user *ubuf)
929{
930 unsigned int *data = &task_thread_info(target)->system_call;
931 return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
932 data, 0, sizeof(unsigned int));
933}
934
902static const struct user_regset s390_regsets[] = { 935static const struct user_regset s390_regsets[] = {
903 [REGSET_GENERAL] = { 936 [REGSET_GENERAL] = {
904 .core_note_type = NT_PRSTATUS, 937 .core_note_type = NT_PRSTATUS,
@@ -925,6 +958,14 @@ static const struct user_regset s390_regsets[] = {
925 .get = s390_last_break_get, 958 .get = s390_last_break_get,
926 }, 959 },
927#endif 960#endif
961 [REGSET_SYSTEM_CALL] = {
962 .core_note_type = NT_S390_SYSTEM_CALL,
963 .n = 1,
964 .size = sizeof(unsigned int),
965 .align = sizeof(unsigned int),
966 .get = s390_system_call_get,
967 .set = s390_system_call_set,
968 },
928}; 969};
929 970
930static const struct user_regset_view user_s390_view = { 971static const struct user_regset_view user_s390_view = {
@@ -1104,6 +1145,14 @@ static const struct user_regset s390_compat_regsets[] = {
1104 .align = sizeof(long), 1145 .align = sizeof(long),
1105 .get = s390_compat_last_break_get, 1146 .get = s390_compat_last_break_get,
1106 }, 1147 },
1148 [REGSET_SYSTEM_CALL] = {
1149 .core_note_type = NT_S390_SYSTEM_CALL,
1150 .n = 1,
1151 .size = sizeof(compat_uint_t),
1152 .align = sizeof(compat_uint_t),
1153 .get = s390_system_call_get,
1154 .set = s390_system_call_set,
1155 },
1107 [REGSET_GENERAL_EXTENDED] = { 1156 [REGSET_GENERAL_EXTENDED] = {
1108 .core_note_type = NT_S390_HIGH_GPRS, 1157 .core_note_type = NT_S390_HIGH_GPRS,
1109 .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), 1158 .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t),
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 9a40e1cc5ec3..e751cab80e04 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -30,6 +30,7 @@
30#include <asm/ucontext.h> 30#include <asm/ucontext.h>
31#include <asm/uaccess.h> 31#include <asm/uaccess.h>
32#include <asm/lowcore.h> 32#include <asm/lowcore.h>
33#include <asm/compat.h>
33#include "entry.h" 34#include "entry.h"
34 35
35#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 36#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -156,7 +157,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
156 current->thread.fp_regs.fpc &= FPC_VALID_MASK; 157 current->thread.fp_regs.fpc &= FPC_VALID_MASK;
157 158
158 restore_fp_regs(&current->thread.fp_regs); 159 restore_fp_regs(&current->thread.fp_regs);
159 regs->svcnr = 0; /* disable syscall checks */ 160 regs->svc_code = 0; /* disable syscall checks */
160 return 0; 161 return 0;
161} 162}
162 163
@@ -401,7 +402,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
401 */ 402 */
402void do_signal(struct pt_regs *regs) 403void do_signal(struct pt_regs *regs)
403{ 404{
404 unsigned long retval = 0, continue_addr = 0, restart_addr = 0;
405 siginfo_t info; 405 siginfo_t info;
406 int signr; 406 int signr;
407 struct k_sigaction ka; 407 struct k_sigaction ka;
@@ -421,54 +421,43 @@ void do_signal(struct pt_regs *regs)
421 else 421 else
422 oldset = &current->blocked; 422 oldset = &current->blocked;
423 423
424 /* Are we from a system call? */ 424 /*
425 if (regs->svcnr) { 425 * Get signal to deliver. When running under ptrace, at this point
426 continue_addr = regs->psw.addr; 426 * the debugger may change all our registers, including the system
427 restart_addr = continue_addr - regs->ilc; 427 * call information.
428 retval = regs->gprs[2]; 428 */
429 429 current_thread_info()->system_call = regs->svc_code;
430 /* Prepare for system call restart. We do this here so that a
431 debugger will see the already changed PSW. */
432 switch (retval) {
433 case -ERESTARTNOHAND:
434 case -ERESTARTSYS:
435 case -ERESTARTNOINTR:
436 regs->gprs[2] = regs->orig_gpr2;
437 regs->psw.addr = restart_addr;
438 break;
439 case -ERESTART_RESTARTBLOCK:
440 regs->gprs[2] = -EINTR;
441 }
442 regs->svcnr = 0; /* Don't deal with this again. */
443 }
444
445 /* Get signal to deliver. When running under ptrace, at this point
446 the debugger may change all our registers ... */
447 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 430 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
448 431 regs->svc_code = current_thread_info()->system_call;
449 /* Depending on the signal settings we may need to revert the
450 decision to restart the system call. */
451 if (signr > 0 && regs->psw.addr == restart_addr) {
452 if (retval == -ERESTARTNOHAND
453 || (retval == -ERESTARTSYS
454 && !(current->sighand->action[signr-1].sa.sa_flags
455 & SA_RESTART))) {
456 regs->gprs[2] = -EINTR;
457 regs->psw.addr = continue_addr;
458 }
459 }
460 432
461 if (signr > 0) { 433 if (signr > 0) {
462 /* Whee! Actually deliver the signal. */ 434 /* Whee! Actually deliver the signal. */
463 int ret; 435 if (regs->svc_code > 0) {
464#ifdef CONFIG_COMPAT 436 /* Check for system call restarting. */
465 if (is_compat_task()) { 437 switch (regs->gprs[2]) {
466 ret = handle_signal32(signr, &ka, &info, oldset, regs); 438 case -ERESTART_RESTARTBLOCK:
467 } 439 case -ERESTARTNOHAND:
468 else 440 regs->gprs[2] = -EINTR;
469#endif 441 break;
470 ret = handle_signal(signr, &ka, &info, oldset, regs); 442 case -ERESTARTSYS:
471 if (!ret) { 443 if (!(ka.sa.sa_flags & SA_RESTART)) {
444 regs->gprs[2] = -EINTR;
445 break;
446 }
447 /* fallthrough */
448 case -ERESTARTNOINTR:
449 regs->gprs[2] = regs->orig_gpr2;
450 regs->psw.addr = regs->psw.addr -
451 (regs->svc_code >> 16);
452 break;
453 }
454 /* No longer in a system call */
455 regs->svc_code = 0;
456 }
457
458 if ((is_compat_task() ?
459 handle_signal32(signr, &ka, &info, oldset, regs) :
460 handle_signal(signr, &ka, &info, oldset, regs)) == 0) {
472 /* 461 /*
473 * A signal was successfully delivered; the saved 462 * A signal was successfully delivered; the saved
474 * sigmask will have been stored in the signal frame, 463 * sigmask will have been stored in the signal frame,
@@ -482,11 +471,28 @@ void do_signal(struct pt_regs *regs)
482 * Let tracing know that we've done the handler setup. 471 * Let tracing know that we've done the handler setup.
483 */ 472 */
484 tracehook_signal_handler(signr, &info, &ka, regs, 473 tracehook_signal_handler(signr, &info, &ka, regs,
485 test_thread_flag(TIF_SINGLE_STEP)); 474 test_thread_flag(TIF_SINGLE_STEP));
486 } 475 }
487 return; 476 return;
488 } 477 }
489 478
479 /* No handlers present - check for system call restart */
480 if (regs->svc_code > 0) {
481 switch (regs->gprs[2]) {
482 case -ERESTART_RESTARTBLOCK:
483 /* Restart with sys_restart_syscall */
484 regs->svc_code = __NR_restart_syscall;
485 /* fallthrough */
486 case -ERESTARTNOHAND:
487 case -ERESTARTSYS:
488 case -ERESTARTNOINTR:
489 /* Restart system call with magic TIF bit. */
490 regs->gprs[2] = regs->orig_gpr2;
491 set_thread_flag(TIF_RESTART_SVC);
492 break;
493 }
494 }
495
490 /* 496 /*
491 * If there's no signal to deliver, we just put the saved sigmask back. 497 * If there's no signal to deliver, we just put the saved sigmask back.
492 */ 498 */
@@ -494,13 +500,6 @@ void do_signal(struct pt_regs *regs)
494 clear_thread_flag(TIF_RESTORE_SIGMASK); 500 clear_thread_flag(TIF_RESTORE_SIGMASK);
495 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL); 501 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
496 } 502 }
497
498 /* Restart a different system call. */
499 if (retval == -ERESTART_RESTARTBLOCK
500 && regs->psw.addr == continue_addr) {
501 regs->gprs[2] = __NR_restart_syscall;
502 set_thread_flag(TIF_RESTART_SVC);
503 }
504} 503}
505 504
506void do_notify_resume(struct pt_regs *regs) 505void do_notify_resume(struct pt_regs *regs)
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 110821cb6ea5..31f0508d7da7 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -395,6 +395,7 @@ typedef struct elf64_shdr {
395#define NT_S390_CTRS 0x304 /* s390 control registers */ 395#define NT_S390_CTRS 0x304 /* s390 control registers */
396#define NT_S390_PREFIX 0x305 /* s390 prefix register */ 396#define NT_S390_PREFIX 0x305 /* s390 prefix register */
397#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ 397#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */
398#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
398#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ 399#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
399 400
400 401