| From 6b7339f4c31ad69c8e9c0b2859276e22cf72176d Mon Sep 17 00:00:00 2001 |
| From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> |
| Date: Mon, 6 Jul 2015 23:18:37 +0300 |
| Subject: mm: avoid setting up anonymous pages into file mapping |
| |
| From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> |
| |
| commit 6b7339f4c31ad69c8e9c0b2859276e22cf72176d upstream. |
| |
| Reading page fault handler code I've noticed that under right |
| circumstances kernel would map anonymous pages into file mappings: if |
| the VMA doesn't have vm_ops->fault() and the VMA wasn't fully populated |
| on ->mmap(), kernel would handle page fault to not populated pte with |
| do_anonymous_page(). |
| |
| Let's change page fault handler to use do_anonymous_page() only on |
| anonymous VMA (->vm_ops == NULL) and make sure that the VMA is not |
| shared. |
| |
| For file mappings without vm_ops->fault() or shred VMA without vm_ops, |
| page fault on pte_none() entry would lead to SIGBUS. |
| |
| Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> |
| Acked-by: Oleg Nesterov <oleg@redhat.com> |
| Cc: Andrew Morton <akpm@linux-foundation.org> |
| Cc: Willy Tarreau <w@1wt.eu> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| |
| --- |
| mm/memory.c | 13 +++++++++---- |
| 1 file changed, 9 insertions(+), 4 deletions(-) |
| |
| --- a/mm/memory.c |
| +++ b/mm/memory.c |
| @@ -3230,6 +3230,10 @@ static int do_anonymous_page(struct mm_s |
| |
| pte_unmap(page_table); |
| |
| + /* File mapping without ->vm_ops ? */ |
| + if (vma->vm_flags & VM_SHARED) |
| + return VM_FAULT_SIGBUS; |
| + |
| /* Check if we need to add a guard page to the stack */ |
| if (check_stack_guard_page(vma, address) < 0) |
| return VM_FAULT_SIGSEGV; |
| @@ -3495,6 +3499,9 @@ static int do_linear_fault(struct mm_str |
| - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; |
| |
| pte_unmap(page_table); |
| + /* The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */ |
| + if (!vma->vm_ops->fault) |
| + return VM_FAULT_SIGBUS; |
| return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte); |
| } |
| |
| @@ -3706,11 +3713,9 @@ int handle_pte_fault(struct mm_struct *m |
| entry = *pte; |
| if (!pte_present(entry)) { |
| if (pte_none(entry)) { |
| - if (vma->vm_ops) { |
| - if (likely(vma->vm_ops->fault)) |
| - return do_linear_fault(mm, vma, address, |
| + if (vma->vm_ops) |
| + return do_linear_fault(mm, vma, address, |
| pte, pmd, flags, entry); |
| - } |
| return do_anonymous_page(mm, vma, address, |
| pte, pmd, flags); |
| } |