Commit 008c2e8f authored by Heiko Carstens's avatar Heiko Carstens Committed by Martin Schwidefsky

s390/mm: fix fault handling for page table walk case

Make sure the kernel does not incorrectly create a SIGBUS signal during
user space accesses:

For user space accesses in the switched addressing mode case the kernel
may walk page tables and access user address space via the kernel
mapping. If a page table entry is invalid the function __handle_fault()
gets called in order to emulate a page fault and trigger all the usual
actions like paging in a missing page etc. by calling handle_mm_fault().

If handle_mm_fault() returns with an error fixup handling is necessary.
For the switched addressing mode case all errors need to be mapped to
-EFAULT, so that the calling uaccess function can return -EFAULT to
user space.

Unfortunately the __handle_fault() incorrectly calls do_sigbus() if
VM_FAULT_SIGBUS is set. This however should only happen if a page fault
was triggered by a user space instruction. For kernel mode uaccesses
the correct action is to only return -EFAULT.
So user space may incorrectly see SIGBUS signals because of this bug.

For current machines this would only be possible for the switched
addressing mode case in conjunction with futex operations.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent f2c76e3b
...@@ -451,6 +451,7 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) ...@@ -451,6 +451,7 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
struct pt_regs regs; struct pt_regs regs;
int access, fault; int access, fault;
/* Emulate a uaccess fault from kernel mode. */
regs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK; regs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK;
if (!irqs_disabled()) if (!irqs_disabled())
regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT; regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
...@@ -460,12 +461,12 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write) ...@@ -460,12 +461,12 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
regs.int_parm_long = (uaddr & PAGE_MASK) | 2; regs.int_parm_long = (uaddr & PAGE_MASK) | 2;
access = write ? VM_WRITE : VM_READ; access = write ? VM_WRITE : VM_READ;
fault = do_exception(&regs, access); fault = do_exception(&regs, access);
if (unlikely(fault)) { /*
if (fault & VM_FAULT_OOM) * Since the fault happened in kernel mode while performing a uaccess
return -EFAULT; * all we need to do now is emulating a fixup in case "fault" is not
else if (fault & VM_FAULT_SIGBUS) * zero.
do_sigbus(&regs); * For the calling uaccess functions this results always in -EFAULT.
} */
return fault ? -EFAULT : 0; return fault ? -EFAULT : 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment