Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[S390] fix system call parameter functions.

syscall_get_nr() currently returns a valid result only if the call
chain of the traced process includes do_syscall_trace_enter(). But
collect_syscall() can be called for any sleeping task, the result of
syscall_get_nr() in general is completely bogus.

To make syscall_get_nr() work for any sleeping task the traps field
in pt_regs is replace with svcnr - the system call number the process
is executing. If svcnr == 0 the process is not on a system call path.

The syscall_get_arguments and syscall_set_arguments use regs->gprs[2]
for the first system call parameter. This is incorrect since gprs[2]
may have been overwritten with the system call number if the call
chain includes do_syscall_trace_enter. Use regs->orig_gprs2 instead.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

+44 -42
+1 -1
arch/s390/include/asm/ptrace.h
··· 321 321 psw_t psw; 322 322 unsigned long gprs[NUM_GPRS]; 323 323 unsigned long orig_gpr2; 324 + unsigned short svcnr; 324 325 unsigned short ilc; 325 - unsigned short trap; 326 326 }; 327 327 #endif 328 328
+16 -12
arch/s390/include/asm/syscall.h
··· 17 17 static inline long syscall_get_nr(struct task_struct *task, 18 18 struct pt_regs *regs) 19 19 { 20 - if (regs->trap != __LC_SVC_OLD_PSW) 21 - return -1; 22 - return regs->gprs[2]; 20 + return regs->svcnr ? regs->svcnr : -1; 23 21 } 24 22 25 23 static inline void syscall_rollback(struct task_struct *task, ··· 50 52 unsigned int i, unsigned int n, 51 53 unsigned long *args) 52 54 { 55 + unsigned long mask = -1UL; 56 + 53 57 BUG_ON(i + n > 6); 54 58 #ifdef CONFIG_COMPAT 55 - if (test_tsk_thread_flag(task, TIF_31BIT)) { 56 - if (i + n == 6) 57 - args[--n] = (u32) regs->args[0]; 58 - while (n-- > 0) 59 - args[n] = (u32) regs->gprs[2 + i + n]; 60 - } 59 + if (test_tsk_thread_flag(task, TIF_31BIT)) 60 + mask = 0xffffffff; 61 61 #endif 62 62 if (i + n == 6) 63 - args[--n] = regs->args[0]; 64 - memcpy(args, &regs->gprs[2 + i], n * sizeof(args[0])); 63 + args[--n] = regs->args[0] & mask; 64 + while (n-- > 0) 65 + if (i + n > 0) 66 + args[n] = regs->gprs[2 + i + n] & mask; 67 + if (i == 0) 68 + args[0] = regs->orig_gpr2 & mask; 65 69 } 66 70 67 71 static inline void syscall_set_arguments(struct task_struct *task, ··· 74 74 BUG_ON(i + n > 6); 75 75 if (i + n == 6) 76 76 regs->args[0] = args[--n]; 77 - memcpy(&regs->gprs[2 + i], args, n * sizeof(args[0])); 77 + while (n-- > 0) 78 + if (i + n > 0) 79 + regs->gprs[2 + i + n] = args[n]; 80 + if (i == 0) 81 + regs->orig_gpr2 = args[0]; 78 82 } 79 83 80 84 #endif /* _ASM_SYSCALL_H */
+1 -1
arch/s390/kernel/asm-offsets.c
··· 32 32 DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); 33 33 DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); 34 34 DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc)); 35 - DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap)); 35 + DEFINE(__PT_SVCNR, offsetof(struct pt_regs, svcnr)); 36 36 DEFINE(__PT_SIZE, sizeof(struct pt_regs)); 37 37 BLANK(); 38 38 DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
+1 -1
arch/s390/kernel/compat_signal.c
··· 340 340 return err; 341 341 342 342 restore_fp_regs(&current->thread.fp_regs); 343 - regs->trap = -1; /* disable syscall checks */ 343 + regs->svcnr = 0; /* disable syscall checks */ 344 344 return 0; 345 345 } 346 346
+11 -10
arch/s390/kernel/entry.S
··· 46 46 SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60 47 47 SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 48 48 SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC 49 - SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP 49 + SP_SVCNR = STACK_FRAME_OVERHEAD + __PT_SVCNR 50 50 SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE 51 51 52 52 _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ ··· 183 183 .macro CREATE_STACK_FRAME psworg,savearea 184 184 s %r15,BASED(.Lc_spsize) # make room for registers & psw 185 185 mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack 186 - la %r12,\psworg 187 186 st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 188 - icm %r12,12,__LC_SVC_ILC 187 + icm %r12,3,__LC_SVC_ILC 189 188 stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack 190 - st %r12,SP_ILC(%r15) 189 + st %r12,SP_SVCNR(%r15) 191 190 mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack 192 191 la %r12,0 193 192 st %r12,__SF_BACKCHAIN(%r15) # clear back chain ··· 263 264 #endif 264 265 sysc_do_svc: 265 266 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct 266 - sla %r7,2 # *4 and test for svc 0 267 + ltr %r7,%r7 # test for svc 0 267 268 bnz BASED(sysc_nr_ok) # svc number > 0 268 269 # svc 0: system call number in %r1 269 270 cl %r1,BASED(.Lnr_syscalls) 270 271 bnl BASED(sysc_nr_ok) 271 272 lr %r7,%r1 # copy svc number to %r7 272 - sla %r7,2 # *4 273 273 sysc_nr_ok: 274 274 mvc SP_ARGS(4,%r15),SP_R7(%r15) 275 275 sysc_do_restart: 276 + sth %r7,SP_SVCNR(%r15) 277 + sll %r7,2 # svc number *4 276 278 l %r8,BASED(.Lsysc_table) 277 279 tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) 278 280 l %r8,0(%r7,%r8) # get system call addr. ··· 376 376 sysc_restart: 377 377 ni __TI_flags+3(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC 378 378 l %r7,SP_R2(%r15) # load new svc number 379 - sla %r7,2 380 379 mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument 381 380 lm %r2,%r6,SP_R2(%r15) # load svc arguments 382 381 b BASED(sysc_do_restart) # restart svc ··· 385 386 # 386 387 sysc_singlestep: 387 388 ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP 388 - mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check 389 + mvi SP_SVCNR(%r15),0xff # set trap indication to pgm check 390 + mvi SP_SVCNR+1(%r15),0xff 389 391 la %r2,SP_PTREGS(%r15) # address of register-save area 390 392 l %r1,BASED(.Lhandle_per) # load adr. of per handler 391 393 la %r14,BASED(sysc_return) # load adr. of system return ··· 407 407 bnl BASED(sysc_tracenogo) 408 408 l %r8,BASED(.Lsysc_table) 409 409 lr %r7,%r2 410 - sll %r7,2 # *4 410 + sll %r7,2 # svc number *4 411 411 l %r8,0(%r7,%r8) 412 412 sysc_tracego: 413 413 lm %r3,%r6,SP_R3(%r15) ··· 586 586 # per was called from kernel, must be kprobes 587 587 # 588 588 kernel_per: 589 - mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check 589 + mvi SP_SVCNR(%r15),0xff # set trap indication to pgm check 590 + mvi SP_SVCNR+1(%r15),0xff 590 591 la %r2,SP_PTREGS(%r15) # address of register-save area 591 592 l %r1,BASED(.Lhandle_per) # load adr. of per handler 592 593 la %r14,BASED(sysc_restore)# load adr. of system return
+10 -13
arch/s390/kernel/entry64.S
··· 46 46 SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120 47 47 SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 48 48 SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC 49 - SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP 49 + SP_SVCNR = STACK_FRAME_OVERHEAD + __PT_SVCNR 50 50 SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE 51 51 52 52 STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER ··· 171 171 .macro CREATE_STACK_FRAME psworg,savearea 172 172 aghi %r15,-SP_SIZE # make room for registers & psw 173 173 mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack 174 - la %r12,\psworg 175 174 stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 176 - icm %r12,12,__LC_SVC_ILC 175 + icm %r12,3,__LC_SVC_ILC 177 176 stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack 178 - st %r12,SP_ILC(%r15) 177 + st %r12,SP_SVCNR(%r15) 179 178 mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack 180 179 la %r12,0 181 180 stg %r12,__SF_BACKCHAIN(%r15) ··· 249 250 #endif 250 251 sysc_do_svc: 251 252 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct 252 - slag %r7,%r7,2 # *4 and test for svc 0 253 + ltgr %r7,%r7 # test for svc 0 253 254 jnz sysc_nr_ok 254 255 # svc 0: system call number in %r1 255 256 cl %r1,BASED(.Lnr_syscalls) 256 257 jnl sysc_nr_ok 257 258 lgfr %r7,%r1 # clear high word in r1 258 - slag %r7,%r7,2 # svc 0: system call number in %r1 259 259 sysc_nr_ok: 260 260 mvc SP_ARGS(8,%r15),SP_R7(%r15) 261 261 sysc_do_restart: 262 + sth %r7,SP_SVCNR(%r15) 263 + sllg %r7,%r7,2 # svc number * 4 262 264 larl %r10,sys_call_table 263 265 #ifdef CONFIG_COMPAT 264 266 tm __TI_flags+5(%r9),(_TIF_31BIT>>16) # running in 31 bit mode ? ··· 363 363 sysc_restart: 364 364 ni __TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC 365 365 lg %r7,SP_R2(%r15) # load new svc number 366 - slag %r7,%r7,2 # *4 367 366 mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument 368 367 lmg %r2,%r6,SP_R2(%r15) # load svc arguments 369 368 j sysc_do_restart # restart svc ··· 371 372 # _TIF_SINGLE_STEP is set, call do_single_step 372 373 # 373 374 sysc_singlestep: 374 - ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP 375 - lhi %r0,__LC_PGM_OLD_PSW 376 - sth %r0,SP_TRAP(%r15) # set trap indication to pgm check 375 + ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP 376 + xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number 377 377 la %r2,SP_PTREGS(%r15) # address of register-save area 378 378 larl %r14,sysc_return # load adr. of system return 379 379 jg do_single_step # branch to do_sigtrap ··· 390 392 lghi %r0,NR_syscalls 391 393 clgr %r0,%r2 392 394 jnh sysc_tracenogo 393 - slag %r7,%r2,2 # *4 395 + sllg %r7,%r2,2 # svc number *4 394 396 lgf %r8,0(%r7,%r10) 395 397 sysc_tracego: 396 398 lmg %r3,%r6,SP_R3(%r15) ··· 565 567 # per was called from kernel, must be kprobes 566 568 # 567 569 kernel_per: 568 - lhi %r0,__LC_PGM_OLD_PSW 569 - sth %r0,SP_TRAP(%r15) # set trap indication to pgm check 570 + xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number 570 571 la %r2,SP_PTREGS(%r15) # address of register-save area 571 572 larl %r14,sysc_restore # load adr. of system ret, no work 572 573 jg do_single_step # branch to do_single_step
+1 -1
arch/s390/kernel/ptrace.c
··· 657 657 * debugger stored an invalid system call number. Skip 658 658 * the system call and the system call restart handling. 659 659 */ 660 - regs->trap = -1; 660 + regs->svcnr = 0; 661 661 ret = -1; 662 662 } 663 663
+3 -3
arch/s390/kernel/signal.c
··· 160 160 current->thread.fp_regs.fpc &= FPC_VALID_MASK; 161 161 162 162 restore_fp_regs(&current->thread.fp_regs); 163 - regs->trap = -1; /* disable syscall checks */ 163 + regs->svcnr = 0; /* disable syscall checks */ 164 164 return 0; 165 165 } 166 166 ··· 445 445 oldset = &current->blocked; 446 446 447 447 /* Are we from a system call? */ 448 - if (regs->trap == __LC_SVC_OLD_PSW) { 448 + if (regs->svcnr) { 449 449 continue_addr = regs->psw.addr; 450 450 restart_addr = continue_addr - regs->ilc; 451 451 retval = regs->gprs[2]; ··· 462 462 case -ERESTART_RESTARTBLOCK: 463 463 regs->gprs[2] = -EINTR; 464 464 } 465 - regs->trap = -1; /* Don't deal with this again. */ 465 + regs->svcnr = 0; /* Don't deal with this again. */ 466 466 } 467 467 468 468 /* Get signal to deliver. When running under ptrace, at this point