]>
Commit | Line | Data |
---|---|---|
d5b95bcd GKH |
1 | From 401592d2e095947344e10ec0623adbcd58934dd4 Mon Sep 17 00:00:00 2001 |
2 | From: Roman Penyaev <rpenyaev@suse.de> | |
3 | Date: Tue, 5 Mar 2019 15:43:20 -0800 | |
4 | Subject: mm/vmalloc: fix size check for remap_vmalloc_range_partial() | |
5 | ||
6 | From: Roman Penyaev <rpenyaev@suse.de> | |
7 | ||
8 | commit 401592d2e095947344e10ec0623adbcd58934dd4 upstream. | |
9 | ||
10 | When VM_NO_GUARD is not set area->size includes adjacent guard page, | |
11 | thus for correct size checking get_vm_area_size() should be used, but | |
12 | not area->size. | |
13 | ||
14 | This fixes possible kernel oops when userspace tries to mmap an area on | |
15 | 1 page bigger than was allocated by vmalloc_user() call: the size check | |
16 | inside remap_vmalloc_range_partial() accounts non-existing guard page | |
17 | also, so check successfully passes but vmalloc_to_page() returns NULL | |
18 | (guard page does not physically exist). | |
19 | ||
20 | The following code pattern example should trigger an oops: | |
21 | ||
22 | static int oops_mmap(struct file *file, struct vm_area_struct *vma) | |
23 | { | |
24 | void *mem; | |
25 | ||
26 | mem = vmalloc_user(4096); | |
27 | BUG_ON(!mem); | |
28 | /* Do not care about mem leak */ | |
29 | ||
30 | return remap_vmalloc_range(vma, mem, 0); | |
31 | } | |
32 | ||
33 | And userspace simply mmaps size + PAGE_SIZE: | |
34 | ||
35 | mmap(NULL, 8192, PROT_WRITE|PROT_READ, MAP_PRIVATE, fd, 0); | |
36 | ||
37 | Possible candidates for oops which do not have any explicit size | |
38 | checks: | |
39 | ||
40 | *** drivers/media/usb/stkwebcam/stk-webcam.c: | |
41 | v4l_stk_mmap[789] ret = remap_vmalloc_range(vma, sbuf->buffer, 0); | |
42 | ||
43 | Or the following one: | |
44 | ||
45 | *** drivers/video/fbdev/core/fbmem.c | |
46 | static int | |
47 | fb_mmap(struct file *file, struct vm_area_struct * vma) | |
48 | ... | |
49 | res = fb->fb_mmap(info, vma); | |
50 | ||
51 | Where fb_mmap callback calls remap_vmalloc_range() directly without any | |
52 | explicit checks: | |
53 | ||
54 | *** drivers/video/fbdev/vfb.c | |
55 | static int vfb_mmap(struct fb_info *info, | |
56 | struct vm_area_struct *vma) | |
57 | { | |
58 | return remap_vmalloc_range(vma, (void *)info->fix.smem_start, vma->vm_pgoff); | |
59 | } | |
60 | ||
61 | Link: http://lkml.kernel.org/r/20190103145954.16942-2-rpenyaev@suse.de | |
62 | Signed-off-by: Roman Penyaev <rpenyaev@suse.de> | |
63 | Acked-by: Michal Hocko <mhocko@suse.com> | |
64 | Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> | |
65 | Cc: Joe Perches <joe@perches.com> | |
66 | Cc: "Luis R. Rodriguez" <mcgrof@kernel.org> | |
67 | Cc: <stable@vger.kernel.org> | |
68 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | |
69 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
70 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
71 | ||
72 | --- | |
73 | mm/vmalloc.c | 2 +- | |
74 | 1 file changed, 1 insertion(+), 1 deletion(-) | |
75 | ||
76 | --- a/mm/vmalloc.c | |
77 | +++ b/mm/vmalloc.c | |
78 | @@ -2262,7 +2262,7 @@ int remap_vmalloc_range_partial(struct v | |
79 | if (!(area->flags & VM_USERMAP)) | |
80 | return -EINVAL; | |
81 | ||
82 | - if (kaddr + size > area->addr + area->size) | |
83 | + if (kaddr + size > area->addr + get_vm_area_size(area)) | |
84 | return -EINVAL; | |
85 | ||
86 | do { |