lkml.org 
[lkml]   [2019]   [Sep]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 134/190] ARC: mm: SIGSEGV userspace trying to access kernel virtual memory
    Date
    [ Upstream commit a8c715b4dd73c26a81a9cc8dc792aa715d8b4bb2 ]

    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: <stable@vger.kernel.org>
    Signed-off-by: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
    Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    arch/arc/mm/fault.c | 9 +++------
    1 file changed, 3 insertions(+), 6 deletions(-)

    diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c
    index 535cf18e8bf2c..4e8143de32e70 100644
    --- a/arch/arc/mm/fault.c
    +++ b/arch/arc/mm/fault.c
    @@ -66,7 +66,7 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
    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, struct pt_regs *regs)
    * 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;
    --
    2.20.1


    \
     
     \ /
      Last update: 2019-09-13 15:50    [W:4.082 / U:0.168 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site