]>
Commit | Line | Data |
---|---|---|
7a7567a2 GKH |
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 | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | From: Paul Burton <paul.burton@mips.com> | |
10 | ||
11 | commit 074a1e1167afd82c26f6d03a9a8b997d564bb241 upstream. | |
12 | ||
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. | |
22 | ||
23 | For example we may vmalloc an address in the kernel mapped region | |
24 | starting a MAP_BASE & obtain the virtual address: | |
25 | ||
26 | addr = 0xc000000000002000 | |
27 | ||
28 | When masked by virt_to_phys(), which uses __pa() & in turn CPHYSADDR(), | |
29 | we obtain the following (bogus) physical address: | |
30 | ||
31 | addr = 0x2000 | |
32 | ||
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. | |
37 | ||
38 | This is equivalent to the ARM64 change made in commit ca219452c6b8 | |
39 | ("arm64: Correctly bounds check virt_addr_valid"). | |
40 | ||
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 | |
45 | feature. | |
46 | ||
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> | |
58 | ||
59 | --- | |
60 | arch/mips/mm/mmap.c | 5 +++++ | |
61 | 1 file changed, 5 insertions(+) | |
62 | ||
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 | |
66 | ||
67 | int __virt_addr_valid(const volatile void *kaddr) | |
68 | { | |
69 | + unsigned long vaddr = (unsigned long)vaddr; | |
70 | + | |
71 | + if ((vaddr < PAGE_OFFSET) || (vaddr >= MAP_BASE)) | |
72 | + return 0; | |
73 | + | |
74 | return pfn_valid(PFN_DOWN(virt_to_phys(kaddr))); | |
75 | } | |
76 | EXPORT_SYMBOL_GPL(__virt_addr_valid); |