From: Eugeniy Paltsev <eugeniy.palt...@synopsys.com>

commit a8c715b4dd73c26a81a9cc8dc792aa715d8b4bb2 upstream.

As of today if userspace process tries to access a kernel virtual addres
(0x7000_0000 to 0x7ffff_ffff) such that a legit kernel mapping already
exists, that process hangs instead of being killed with SIGSEGV

Fix that by ensuring that do_page_fault() handles kenrel vaddr only if
in kernel mode.

And given this, we can also simplify the code a bit. Now a vmalloc fault
implies kernel mode so its failure (for some reason) can reuse the
@no_context label and we can remove @bad_area_nosemaphore.

Reproduce user test for original problem:

------------------------>8-----------------
 #include <stdlib.h>
 #include <stdint.h>

 int main(int argc, char *argv[])
 {
        volatile uint32_t temp;

        temp = *(uint32_t *)(0x70000000);
 }
------------------------>8-----------------

Cc: <sta...@vger.kernel.org>
Signed-off-by: Eugeniy Paltsev <eugeniy.palt...@synopsys.com>
Signed-off-by: Vineet Gupta <vgu...@synopsys.com>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 arch/arc/mm/fault.c |    9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

--- a/arch/arc/mm/fault.c
+++ b/arch/arc/mm/fault.c
@@ -66,7 +66,7 @@ void do_page_fault(unsigned long address
        struct vm_area_struct *vma = NULL;
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
-       int si_code = 0;
+       int si_code = SEGV_MAPERR;
        int ret;
        vm_fault_t fault;
        int write = regs->ecr_cause & ECR_C_PROTV_STORE;  /* ST/EX */
@@ -81,16 +81,14 @@ void do_page_fault(unsigned long address
         * only copy the information from the master page table,
         * nothing more.
         */
-       if (address >= VMALLOC_START) {
+       if (address >= VMALLOC_START && !user_mode(regs)) {
                ret = handle_kernel_vaddr_fault(address);
                if (unlikely(ret))
-                       goto bad_area_nosemaphore;
+                       goto no_context;
                else
                        return;
        }
 
-       si_code = SEGV_MAPERR;
-
        /*
         * If we're in an interrupt or have no user
         * context, we must not take the fault..
@@ -198,7 +196,6 @@ good_area:
 bad_area:
        up_read(&mm->mmap_sem);
 
-bad_area_nosemaphore:
        /* User mode accesses just cause a SIGSEGV */
        if (user_mode(regs)) {
                tsk->thread.fault_address = address;


Reply via email to