| From 1b17844b29ae042576bea588164f2f1e9590a8bc Mon Sep 17 00:00:00 2001 |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| Date: Tue, 22 Apr 2014 13:49:40 -0700 |
| Subject: mm: make fixup_user_fault() check the vma access rights too |
| |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| |
| commit 1b17844b29ae042576bea588164f2f1e9590a8bc upstream. |
| |
| fixup_user_fault() is used by the futex code when the direct user access |
| fails, and the futex code wants it to either map in the page in a usable |
| form or return an error. It relied on handle_mm_fault() to map the |
| page, and correctly checked the error return from that, but while that |
| does map the page, it doesn't actually guarantee that the page will be |
| mapped with sufficient permissions to be then accessed. |
| |
| So do the appropriate tests of the vma access rights by hand. |
| |
| [ Side note: arguably handle_mm_fault() could just do that itself, but |
| we have traditionally done it in the caller, because some callers - |
| notably get_user_pages() - have been able to access pages even when |
| they are mapped with PROT_NONE. Maybe we should re-visit that design |
| decision, but in the meantime this is the minimal patch. ] |
| |
| Found by Dave Jones running his trinity tool. |
| |
| Reported-by: Dave Jones <davej@redhat.com> |
| Acked-by: Hugh Dickins <hughd@google.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| mm/memory.c | 5 +++++ |
| 1 file changed, 5 insertions(+) |
| |
| --- a/mm/memory.c |
| +++ b/mm/memory.c |
| @@ -1937,12 +1937,17 @@ int fixup_user_fault(struct task_struct |
| unsigned long address, unsigned int fault_flags) |
| { |
| struct vm_area_struct *vma; |
| + vm_flags_t vm_flags; |
| int ret; |
| |
| vma = find_extend_vma(mm, address); |
| if (!vma || address < vma->vm_start) |
| return -EFAULT; |
| |
| + vm_flags = (fault_flags & FAULT_FLAG_WRITE) ? VM_WRITE : VM_READ; |
| + if (!(vm_flags & vma->vm_flags)) |
| + return -EFAULT; |
| + |
| ret = handle_mm_fault(mm, vma, address, fault_flags); |
| if (ret & VM_FAULT_ERROR) { |
| if (ret & VM_FAULT_OOM) |