[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>
This commit is contained in:
parent
ed313489ba
commit
59da21398e
@ -321,8 +321,8 @@ struct pt_regs
|
||||
psw_t psw;
|
||||
unsigned long gprs[NUM_GPRS];
|
||||
unsigned long orig_gpr2;
|
||||
unsigned short svcnr;
|
||||
unsigned short ilc;
|
||||
unsigned short trap;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -17,9 +17,7 @@
|
||||
static inline long syscall_get_nr(struct task_struct *task,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
if (regs->trap != __LC_SVC_OLD_PSW)
|
||||
return -1;
|
||||
return regs->gprs[2];
|
||||
return regs->svcnr ? regs->svcnr : -1;
|
||||
}
|
||||
|
||||
static inline void syscall_rollback(struct task_struct *task,
|
||||
@ -52,18 +50,20 @@ static inline void syscall_get_arguments(struct task_struct *task,
|
||||
unsigned int i, unsigned int n,
|
||||
unsigned long *args)
|
||||
{
|
||||
unsigned long mask = -1UL;
|
||||
|
||||
BUG_ON(i + n > 6);
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (test_tsk_thread_flag(task, TIF_31BIT)) {
|
||||
if (i + n == 6)
|
||||
args[--n] = (u32) regs->args[0];
|
||||
while (n-- > 0)
|
||||
args[n] = (u32) regs->gprs[2 + i + n];
|
||||
}
|
||||
if (test_tsk_thread_flag(task, TIF_31BIT))
|
||||
mask = 0xffffffff;
|
||||
#endif
|
||||
if (i + n == 6)
|
||||
args[--n] = regs->args[0];
|
||||
memcpy(args, ®s->gprs[2 + i], n * sizeof(args[0]));
|
||||
args[--n] = regs->args[0] & mask;
|
||||
while (n-- > 0)
|
||||
if (i + n > 0)
|
||||
args[n] = regs->gprs[2 + i + n] & mask;
|
||||
if (i == 0)
|
||||
args[0] = regs->orig_gpr2 & mask;
|
||||
}
|
||||
|
||||
static inline void syscall_set_arguments(struct task_struct *task,
|
||||
@ -74,7 +74,11 @@ static inline void syscall_set_arguments(struct task_struct *task,
|
||||
BUG_ON(i + n > 6);
|
||||
if (i + n == 6)
|
||||
regs->args[0] = args[--n];
|
||||
memcpy(®s->gprs[2 + i], args, n * sizeof(args[0]));
|
||||
while (n-- > 0)
|
||||
if (i + n > 0)
|
||||
regs->gprs[2 + i + n] = args[n];
|
||||
if (i == 0)
|
||||
regs->orig_gpr2 = args[0];
|
||||
}
|
||||
|
||||
#endif /* _ASM_SYSCALL_H */
|
||||
|
@ -32,7 +32,7 @@ int main(void)
|
||||
DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
|
||||
DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
|
||||
DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc));
|
||||
DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap));
|
||||
DEFINE(__PT_SVCNR, offsetof(struct pt_regs, svcnr));
|
||||
DEFINE(__PT_SIZE, sizeof(struct pt_regs));
|
||||
BLANK();
|
||||
DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
|
||||
|
@ -340,7 +340,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
|
||||
return err;
|
||||
|
||||
restore_fp_regs(¤t->thread.fp_regs);
|
||||
regs->trap = -1; /* disable syscall checks */
|
||||
regs->svcnr = 0; /* disable syscall checks */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
|
||||
SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60
|
||||
SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
|
||||
SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
|
||||
SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
|
||||
SP_SVCNR = STACK_FRAME_OVERHEAD + __PT_SVCNR
|
||||
SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
|
||||
|
||||
_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
|
||||
@ -183,11 +183,10 @@ STACK_SIZE = 1 << STACK_SHIFT
|
||||
.macro CREATE_STACK_FRAME psworg,savearea
|
||||
s %r15,BASED(.Lc_spsize) # make room for registers & psw
|
||||
mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack
|
||||
la %r12,\psworg
|
||||
st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
|
||||
icm %r12,12,__LC_SVC_ILC
|
||||
icm %r12,3,__LC_SVC_ILC
|
||||
stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
|
||||
st %r12,SP_ILC(%r15)
|
||||
st %r12,SP_SVCNR(%r15)
|
||||
mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack
|
||||
la %r12,0
|
||||
st %r12,__SF_BACKCHAIN(%r15) # clear back chain
|
||||
@ -264,16 +263,17 @@ sysc_update:
|
||||
#endif
|
||||
sysc_do_svc:
|
||||
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
|
||||
sla %r7,2 # *4 and test for svc 0
|
||||
ltr %r7,%r7 # test for svc 0
|
||||
bnz BASED(sysc_nr_ok) # svc number > 0
|
||||
# svc 0: system call number in %r1
|
||||
cl %r1,BASED(.Lnr_syscalls)
|
||||
bnl BASED(sysc_nr_ok)
|
||||
lr %r7,%r1 # copy svc number to %r7
|
||||
sla %r7,2 # *4
|
||||
sysc_nr_ok:
|
||||
mvc SP_ARGS(4,%r15),SP_R7(%r15)
|
||||
sysc_do_restart:
|
||||
sth %r7,SP_SVCNR(%r15)
|
||||
sll %r7,2 # svc number *4
|
||||
l %r8,BASED(.Lsysc_table)
|
||||
tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
|
||||
l %r8,0(%r7,%r8) # get system call addr.
|
||||
@ -376,7 +376,6 @@ sysc_notify_resume:
|
||||
sysc_restart:
|
||||
ni __TI_flags+3(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
|
||||
l %r7,SP_R2(%r15) # load new svc number
|
||||
sla %r7,2
|
||||
mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
|
||||
lm %r2,%r6,SP_R2(%r15) # load svc arguments
|
||||
b BASED(sysc_do_restart) # restart svc
|
||||
@ -386,7 +385,8 @@ sysc_restart:
|
||||
#
|
||||
sysc_singlestep:
|
||||
ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
|
||||
mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check
|
||||
mvi SP_SVCNR(%r15),0xff # set trap indication to pgm check
|
||||
mvi SP_SVCNR+1(%r15),0xff
|
||||
la %r2,SP_PTREGS(%r15) # address of register-save area
|
||||
l %r1,BASED(.Lhandle_per) # load adr. of per handler
|
||||
la %r14,BASED(sysc_return) # load adr. of system return
|
||||
@ -407,7 +407,7 @@ sysc_tracesys:
|
||||
bnl BASED(sysc_tracenogo)
|
||||
l %r8,BASED(.Lsysc_table)
|
||||
lr %r7,%r2
|
||||
sll %r7,2 # *4
|
||||
sll %r7,2 # svc number *4
|
||||
l %r8,0(%r7,%r8)
|
||||
sysc_tracego:
|
||||
lm %r3,%r6,SP_R3(%r15)
|
||||
@ -586,7 +586,8 @@ pgm_svcper:
|
||||
# per was called from kernel, must be kprobes
|
||||
#
|
||||
kernel_per:
|
||||
mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check
|
||||
mvi SP_SVCNR(%r15),0xff # set trap indication to pgm check
|
||||
mvi SP_SVCNR+1(%r15),0xff
|
||||
la %r2,SP_PTREGS(%r15) # address of register-save area
|
||||
l %r1,BASED(.Lhandle_per) # load adr. of per handler
|
||||
la %r14,BASED(sysc_restore)# load adr. of system return
|
||||
|
@ -46,7 +46,7 @@ SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112
|
||||
SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120
|
||||
SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
|
||||
SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
|
||||
SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
|
||||
SP_SVCNR = STACK_FRAME_OVERHEAD + __PT_SVCNR
|
||||
SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
|
||||
|
||||
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
|
||||
@ -171,11 +171,10 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
|
||||
.macro CREATE_STACK_FRAME psworg,savearea
|
||||
aghi %r15,-SP_SIZE # make room for registers & psw
|
||||
mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
|
||||
la %r12,\psworg
|
||||
stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
|
||||
icm %r12,12,__LC_SVC_ILC
|
||||
icm %r12,3,__LC_SVC_ILC
|
||||
stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack
|
||||
st %r12,SP_ILC(%r15)
|
||||
st %r12,SP_SVCNR(%r15)
|
||||
mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack
|
||||
la %r12,0
|
||||
stg %r12,__SF_BACKCHAIN(%r15)
|
||||
@ -250,16 +249,17 @@ sysc_update:
|
||||
#endif
|
||||
sysc_do_svc:
|
||||
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
|
||||
slag %r7,%r7,2 # *4 and test for svc 0
|
||||
ltgr %r7,%r7 # test for svc 0
|
||||
jnz sysc_nr_ok
|
||||
# svc 0: system call number in %r1
|
||||
cl %r1,BASED(.Lnr_syscalls)
|
||||
jnl sysc_nr_ok
|
||||
lgfr %r7,%r1 # clear high word in r1
|
||||
slag %r7,%r7,2 # svc 0: system call number in %r1
|
||||
sysc_nr_ok:
|
||||
mvc SP_ARGS(8,%r15),SP_R7(%r15)
|
||||
sysc_do_restart:
|
||||
sth %r7,SP_SVCNR(%r15)
|
||||
sllg %r7,%r7,2 # svc number * 4
|
||||
larl %r10,sys_call_table
|
||||
#ifdef CONFIG_COMPAT
|
||||
tm __TI_flags+5(%r9),(_TIF_31BIT>>16) # running in 31 bit mode ?
|
||||
@ -363,7 +363,6 @@ sysc_notify_resume:
|
||||
sysc_restart:
|
||||
ni __TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
|
||||
lg %r7,SP_R2(%r15) # load new svc number
|
||||
slag %r7,%r7,2 # *4
|
||||
mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument
|
||||
lmg %r2,%r6,SP_R2(%r15) # load svc arguments
|
||||
j sysc_do_restart # restart svc
|
||||
@ -372,9 +371,8 @@ sysc_restart:
|
||||
# _TIF_SINGLE_STEP is set, call do_single_step
|
||||
#
|
||||
sysc_singlestep:
|
||||
ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
|
||||
lhi %r0,__LC_PGM_OLD_PSW
|
||||
sth %r0,SP_TRAP(%r15) # set trap indication to pgm check
|
||||
ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
|
||||
xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number
|
||||
la %r2,SP_PTREGS(%r15) # address of register-save area
|
||||
larl %r14,sysc_return # load adr. of system return
|
||||
jg do_single_step # branch to do_sigtrap
|
||||
@ -392,7 +390,7 @@ sysc_tracesys:
|
||||
lghi %r0,NR_syscalls
|
||||
clgr %r0,%r2
|
||||
jnh sysc_tracenogo
|
||||
slag %r7,%r2,2 # *4
|
||||
sllg %r7,%r2,2 # svc number *4
|
||||
lgf %r8,0(%r7,%r10)
|
||||
sysc_tracego:
|
||||
lmg %r3,%r6,SP_R3(%r15)
|
||||
@ -567,8 +565,7 @@ pgm_svcper:
|
||||
# per was called from kernel, must be kprobes
|
||||
#
|
||||
kernel_per:
|
||||
lhi %r0,__LC_PGM_OLD_PSW
|
||||
sth %r0,SP_TRAP(%r15) # set trap indication to pgm check
|
||||
xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number
|
||||
la %r2,SP_PTREGS(%r15) # address of register-save area
|
||||
larl %r14,sysc_restore # load adr. of system ret, no work
|
||||
jg do_single_step # branch to do_single_step
|
||||
|
@ -657,7 +657,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
|
||||
* debugger stored an invalid system call number. Skip
|
||||
* the system call and the system call restart handling.
|
||||
*/
|
||||
regs->trap = -1;
|
||||
regs->svcnr = 0;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
|
||||
current->thread.fp_regs.fpc &= FPC_VALID_MASK;
|
||||
|
||||
restore_fp_regs(¤t->thread.fp_regs);
|
||||
regs->trap = -1; /* disable syscall checks */
|
||||
regs->svcnr = 0; /* disable syscall checks */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -445,7 +445,7 @@ void do_signal(struct pt_regs *regs)
|
||||
oldset = ¤t->blocked;
|
||||
|
||||
/* Are we from a system call? */
|
||||
if (regs->trap == __LC_SVC_OLD_PSW) {
|
||||
if (regs->svcnr) {
|
||||
continue_addr = regs->psw.addr;
|
||||
restart_addr = continue_addr - regs->ilc;
|
||||
retval = regs->gprs[2];
|
||||
@ -462,7 +462,7 @@ void do_signal(struct pt_regs *regs)
|
||||
case -ERESTART_RESTARTBLOCK:
|
||||
regs->gprs[2] = -EINTR;
|
||||
}
|
||||
regs->trap = -1; /* Don't deal with this again. */
|
||||
regs->svcnr = 0; /* Don't deal with this again. */
|
||||
}
|
||||
|
||||
/* Get signal to deliver. When running under ptrace, at this point
|
||||
|
Loading…
Reference in New Issue
Block a user