aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-04-22 16:49:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-04-22 16:49:40 -0400
commit1b17844b29ae042576bea588164f2f1e9590a8bc (patch)
treeca1751393012b54f7be0b5b1750299e4e2ff4a8a
parent4d0fa8a0f01272d4de33704f20303dcecdb55df1 (diff)
mm: make fixup_user_fault() check the vma access rights too
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> Cc: stable@vger.kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/memory.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/mm/memory.c b/mm/memory.c
index d0f0bef3be48..93e332d5ed77 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1955,12 +1955,17 @@ int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
1955 unsigned long address, unsigned int fault_flags) 1955 unsigned long address, unsigned int fault_flags)
1956{ 1956{
1957 struct vm_area_struct *vma; 1957 struct vm_area_struct *vma;
1958 vm_flags_t vm_flags;
1958 int ret; 1959 int ret;
1959 1960
1960 vma = find_extend_vma(mm, address); 1961 vma = find_extend_vma(mm, address);
1961 if (!vma || address < vma->vm_start) 1962 if (!vma || address < vma->vm_start)
1962 return -EFAULT; 1963 return -EFAULT;
1963 1964
1965 vm_flags = (fault_flags & FAULT_FLAG_WRITE) ? VM_WRITE : VM_READ;
1966 if (!(vm_flags & vma->vm_flags))
1967 return -EFAULT;
1968
1964 ret = handle_mm_fault(mm, vma, address, fault_flags); 1969 ret = handle_mm_fault(mm, vma, address, fault_flags);
1965 if (ret & VM_FAULT_ERROR) { 1970 if (ret & VM_FAULT_ERROR) {
1966 if (ret & VM_FAULT_OOM) 1971 if (ret & VM_FAULT_OOM)