From 5ebf250dabbae83ad875f0dda5a108503cf78f3b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 16 Oct 2013 09:58:01 +0200 Subject: s390: fix handling of runtime instrumentation psw bit Fix the following bugs: - When returning from a signal the signal handler copies the saved psw mask from user space and uses parts of it. Especially it restores the RI bit unconditionally. If however the machine doesn't support RI, or RI is disabled for the task, the last lpswe instruction which returns to user space will generate a specification exception. To fix this check if the RI bit is allowed to be set and kill the task if not. - In the compat mode signal handler code the RI bit of the psw mask gets propagated to the mask of the return psw: if user space enables RI in the signal handler, RI will also be enabled after the signal handler is finished. This is a different behaviour than with 64 bit tasks. So change this to match the 64 bit semantics, which restores the original RI bit value. - Fix similar oddities within the ptrace code as well. Reviewed-by: Martin Schwidefsky Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/signal.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'arch/s390/kernel/signal.c') diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 4c28c39e3718..fb535874a246 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -58,7 +58,7 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) /* Copy a 'clean' PSW mask to the user to avoid leaking information about whether PER is currently on. */ user_sregs.regs.psw.mask = PSW_USER_BITS | - (regs->psw.mask & PSW_MASK_USER); + (regs->psw.mask & (PSW_MASK_USER | PSW_MASK_RI)); user_sregs.regs.psw.addr = regs->psw.addr; memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs)); memcpy(&user_sregs.regs.acrs, current->thread.acrs, @@ -86,13 +86,16 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) if (__copy_from_user(&user_sregs, sregs, sizeof(user_sregs))) return -EFAULT; + if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI)) + return -EINVAL; + /* Loading the floating-point-control word can fail. Do that first. */ if (restore_fp_ctl(&user_sregs.fpregs.fpc)) return -EINVAL; /* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */ regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) | - (user_sregs.regs.psw.mask & PSW_MASK_USER); + (user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI)); /* Check for invalid user address space control. */ if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME) regs->psw.mask = PSW_ASC_PRIMARY | -- cgit v1.2.3-58-ga151