diff options
| author | Andrea Arcangeli <aarcange@redhat.com> | 2017-06-16 17:02:37 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-06-16 17:37:05 -0400 |
| commit | 64c2b20301f62c697352c8028c569b1b2bdd8e82 (patch) | |
| tree | 435b7139eca1e06238e50aca345a904d0f19ccd5 /fs | |
| parent | 3c226c637b69104f6b9f1c6ec5b08d7b741b3229 (diff) | |
userfaultfd: shmem: handle coredumping in handle_userfault()
Anon and hugetlbfs handle FOLL_DUMP set by get_dump_page() internally to
__get_user_pages().
shmem as opposed has no special FOLL_DUMP handling there so
handle_mm_fault() is invoked without mmap_sem and ends up calling
handle_userfault() that isn't expecting to be invoked without mmap_sem
held.
This makes handle_userfault() fail immediately if invoked through
shmem_vm_ops->fault during coredumping and solves the problem.
The side effect is a BUG_ON with no lock held triggered by the
coredumping process which exits. Only 4.11 is affected, pre-4.11 anon
memory holes are skipped in __get_user_pages by checking FOLL_DUMP
explicitly against empty pagetables (mm/gup.c:no_page_table()).
It's zero cost as we already had a check for current->flags to prevent
futex to trigger userfaults during exit (PF_EXITING).
Link: http://lkml.kernel.org/r/20170615214838.27429-1-aarcange@redhat.com
Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
Reported-by: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Cc: <stable@vger.kernel.org> [4.11+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/userfaultfd.c | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index f7555fc25877..1d622f276e3a 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c | |||
| @@ -340,9 +340,28 @@ int handle_userfault(struct vm_fault *vmf, unsigned long reason) | |||
| 340 | bool must_wait, return_to_userland; | 340 | bool must_wait, return_to_userland; |
| 341 | long blocking_state; | 341 | long blocking_state; |
| 342 | 342 | ||
| 343 | BUG_ON(!rwsem_is_locked(&mm->mmap_sem)); | ||
| 344 | |||
| 345 | ret = VM_FAULT_SIGBUS; | 343 | ret = VM_FAULT_SIGBUS; |
| 344 | |||
| 345 | /* | ||
| 346 | * We don't do userfault handling for the final child pid update. | ||
| 347 | * | ||
| 348 | * We also don't do userfault handling during | ||
| 349 | * coredumping. hugetlbfs has the special | ||
| 350 | * follow_hugetlb_page() to skip missing pages in the | ||
| 351 | * FOLL_DUMP case, anon memory also checks for FOLL_DUMP with | ||
| 352 | * the no_page_table() helper in follow_page_mask(), but the | ||
| 353 | * shmem_vm_ops->fault method is invoked even during | ||
| 354 | * coredumping without mmap_sem and it ends up here. | ||
| 355 | */ | ||
| 356 | if (current->flags & (PF_EXITING|PF_DUMPCORE)) | ||
| 357 | goto out; | ||
| 358 | |||
| 359 | /* | ||
| 360 | * Coredumping runs without mmap_sem so we can only check that | ||
| 361 | * the mmap_sem is held, if PF_DUMPCORE was not set. | ||
| 362 | */ | ||
| 363 | WARN_ON_ONCE(!rwsem_is_locked(&mm->mmap_sem)); | ||
| 364 | |||
| 346 | ctx = vmf->vma->vm_userfaultfd_ctx.ctx; | 365 | ctx = vmf->vma->vm_userfaultfd_ctx.ctx; |
| 347 | if (!ctx) | 366 | if (!ctx) |
| 348 | goto out; | 367 | goto out; |
| @@ -361,12 +380,6 @@ int handle_userfault(struct vm_fault *vmf, unsigned long reason) | |||
| 361 | goto out; | 380 | goto out; |
| 362 | 381 | ||
| 363 | /* | 382 | /* |
| 364 | * We don't do userfault handling for the final child pid update. | ||
| 365 | */ | ||
| 366 | if (current->flags & PF_EXITING) | ||
| 367 | goto out; | ||
| 368 | |||
| 369 | /* | ||
| 370 | * Check that we can return VM_FAULT_RETRY. | 383 | * Check that we can return VM_FAULT_RETRY. |
| 371 | * | 384 | * |
| 372 | * NOTE: it should become possible to return VM_FAULT_RETRY | 385 | * NOTE: it should become possible to return VM_FAULT_RETRY |
