1 From 074a1e1167afd82c26f6d03a9a8b997d564bb241 Mon Sep 17 00:00:00 2001
2 From: Paul Burton <paul.burton@mips.com>
3 Date: Tue, 28 May 2019 17:05:03 +0000
4 Subject: MIPS: Bounds check virt_addr_valid
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
9 From: Paul Burton <paul.burton@mips.com>
11 commit 074a1e1167afd82c26f6d03a9a8b997d564bb241 upstream.
13 The virt_addr_valid() function is meant to return true iff
14 virt_to_page() will return a valid struct page reference. This is true
15 iff the address provided is found within the unmapped address range
16 between PAGE_OFFSET & MAP_BASE, but we don't currently check for that
17 condition. Instead we simply mask the address to obtain what will be a
18 physical address if the virtual address is indeed in the desired range,
19 shift it to form a PFN & then call pfn_valid(). This can incorrectly
20 return true if called with a virtual address which, after masking,
21 happens to form a physical address corresponding to a valid PFN.
23 For example we may vmalloc an address in the kernel mapped region
24 starting a MAP_BASE & obtain the virtual address:
26 addr = 0xc000000000002000
28 When masked by virt_to_phys(), which uses __pa() & in turn CPHYSADDR(),
29 we obtain the following (bogus) physical address:
33 In a common system with PHYS_OFFSET=0 this will correspond to a valid
34 struct page which should really be accessed by virtual address
35 PAGE_OFFSET+0x2000, causing virt_addr_valid() to incorrectly return 1
36 indicating that the original address corresponds to a struct page.
38 This is equivalent to the ARM64 change made in commit ca219452c6b8
39 ("arm64: Correctly bounds check virt_addr_valid").
41 This fixes fallout when hardened usercopy is enabled caused by the
42 related commit 517e1fbeb65f ("mm/usercopy: Drop extra
43 is_vmalloc_or_module() check") which removed a check for the vmalloc
44 range that was present from the introduction of the hardened usercopy
47 Signed-off-by: Paul Burton <paul.burton@mips.com>
48 References: ca219452c6b8 ("arm64: Correctly bounds check virt_addr_valid")
49 References: 517e1fbeb65f ("mm/usercopy: Drop extra is_vmalloc_or_module() check")
50 Reported-by: Julien Cristau <jcristau@debian.org>
51 Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
52 Tested-by: YunQiang Su <ysu@wavecomp.com>
53 URL: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=929366
54 Cc: stable@vger.kernel.org # v4.12+
55 Cc: linux-mips@vger.kernel.org
56 Cc: Yunqiang Su <ysu@wavecomp.com>
57 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
60 arch/mips/mm/mmap.c | 5 +++++
61 1 file changed, 5 insertions(+)
63 --- a/arch/mips/mm/mmap.c
64 +++ b/arch/mips/mm/mmap.c
65 @@ -203,6 +203,11 @@ unsigned long arch_randomize_brk(struct
67 int __virt_addr_valid(const volatile void *kaddr)
69 + unsigned long vaddr = (unsigned long)vaddr;
71 + if ((vaddr < PAGE_OFFSET) || (vaddr >= MAP_BASE))
74 return pfn_valid(PFN_DOWN(virt_to_phys(kaddr)));
76 EXPORT_SYMBOL_GPL(__virt_addr_valid);