Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 59da2139 authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

[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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent ed313489
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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

+16 −12
Original line number Diff line number Diff line
@@ -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, &regs->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(&regs->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 */
+1 −1
Original line number Diff line number Diff line
@@ -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));
+1 −1
Original line number Diff line number Diff line
@@ -340,7 +340,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
		return err;

	restore_fp_regs(&current->thread.fp_regs);
	regs->trap = -1;	/* disable syscall checks */
	regs->svcnr = 0;	/* disable syscall checks */
	return 0;
}

+11 −10
Original line number Diff line number Diff line
@@ -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
Loading