aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2012-07-27 03:45:39 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-07-30 05:03:09 -0400
commit008c2e8f247f0a8db1e8e26139da12f3a3abcda0 (patch)
tree2c3178fe37a4c4fb0dea576bef14b18802309476 /arch/s390/mm
parentf2c76e3b6f72c3fda290998109594dc490b8b087 (diff)
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: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/mm')
-rw-r--r--arch/s390/mm/fault.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 2a34a1c35a7c..dc659da2fac9 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -451,6 +451,7 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
451 struct pt_regs regs; 451 struct pt_regs regs;
452 int access, fault; 452 int access, fault;
453 453
454 /* Emulate a uaccess fault from kernel mode. */
454 regs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK; 455 regs.psw.mask = psw_kernel_bits | PSW_MASK_DAT | PSW_MASK_MCHECK;
455 if (!irqs_disabled()) 456 if (!irqs_disabled())
456 regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT; 457 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 regs.int_parm_long = (uaddr & PAGE_MASK) | 2; 461 regs.int_parm_long = (uaddr & PAGE_MASK) | 2;
461 access = write ? VM_WRITE : VM_READ; 462 access = write ? VM_WRITE : VM_READ;
462 fault = do_exception(&regs, access); 463 fault = do_exception(&regs, access);
463 if (unlikely(fault)) { 464 /*
464 if (fault & VM_FAULT_OOM) 465 * Since the fault happened in kernel mode while performing a uaccess
465 return -EFAULT; 466 * all we need to do now is emulating a fixup in case "fault" is not
466 else if (fault & VM_FAULT_SIGBUS) 467 * zero.
467 do_sigbus(&regs); 468 * For the calling uaccess functions this results always in -EFAULT.
468 } 469 */
469 return fault ? -EFAULT : 0; 470 return fault ? -EFAULT : 0;
470} 471}
471 472