1 |
From 0cbb4b4f4c44f54af268969b18d8deda63aded59 Mon Sep 17 00:00:00 2001 |
2 |
From: Andrea Arcangeli <aarcange@redhat.com> |
3 |
Date: Thu, 4 Jan 2018 16:18:09 -0800 |
4 |
Subject: userfaultfd: clear the vma->vm_userfaultfd_ctx if UFFD_EVENT_FORK fails |
5 |
|
6 |
From: Andrea Arcangeli <aarcange@redhat.com> |
7 |
|
8 |
commit 0cbb4b4f4c44f54af268969b18d8deda63aded59 upstream. |
9 |
|
10 |
The previous fix in commit 384632e67e08 ("userfaultfd: non-cooperative: |
11 |
fix fork use after free") corrected the refcounting in case of |
12 |
UFFD_EVENT_FORK failure for the fork userfault paths. |
13 |
|
14 |
That still didn't clear the vma->vm_userfaultfd_ctx of the vmas that |
15 |
were set to point to the aborted new uffd ctx earlier in |
16 |
dup_userfaultfd. |
17 |
|
18 |
Link: http://lkml.kernel.org/r/20171223002505.593-2-aarcange@redhat.com |
19 |
Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> |
20 |
Reported-by: syzbot <syzkaller@googlegroups.com> |
21 |
Reviewed-by: Mike Rapoport <rppt@linux.vnet.ibm.com> |
22 |
Cc: Eric Biggers <ebiggers3@gmail.com> |
23 |
Cc: Dmitry Vyukov <dvyukov@google.com> |
24 |
Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
25 |
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
26 |
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
27 |
|
28 |
--- |
29 |
fs/userfaultfd.c | 20 ++++++++++++++++++-- |
30 |
1 file changed, 18 insertions(+), 2 deletions(-) |
31 |
|
32 |
--- a/fs/userfaultfd.c |
33 |
+++ b/fs/userfaultfd.c |
34 |
@@ -570,11 +570,14 @@ out: |
35 |
static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx, |
36 |
struct userfaultfd_wait_queue *ewq) |
37 |
{ |
38 |
+ struct userfaultfd_ctx *release_new_ctx; |
39 |
+ |
40 |
if (WARN_ON_ONCE(current->flags & PF_EXITING)) |
41 |
goto out; |
42 |
|
43 |
ewq->ctx = ctx; |
44 |
init_waitqueue_entry(&ewq->wq, current); |
45 |
+ release_new_ctx = NULL; |
46 |
|
47 |
spin_lock(&ctx->event_wqh.lock); |
48 |
/* |
49 |
@@ -601,8 +604,7 @@ static void userfaultfd_event_wait_compl |
50 |
new = (struct userfaultfd_ctx *) |
51 |
(unsigned long) |
52 |
ewq->msg.arg.reserved.reserved1; |
53 |
- |
54 |
- userfaultfd_ctx_put(new); |
55 |
+ release_new_ctx = new; |
56 |
} |
57 |
break; |
58 |
} |
59 |
@@ -617,6 +619,20 @@ static void userfaultfd_event_wait_compl |
60 |
__set_current_state(TASK_RUNNING); |
61 |
spin_unlock(&ctx->event_wqh.lock); |
62 |
|
63 |
+ if (release_new_ctx) { |
64 |
+ struct vm_area_struct *vma; |
65 |
+ struct mm_struct *mm = release_new_ctx->mm; |
66 |
+ |
67 |
+ /* the various vma->vm_userfaultfd_ctx still points to it */ |
68 |
+ down_write(&mm->mmap_sem); |
69 |
+ for (vma = mm->mmap; vma; vma = vma->vm_next) |
70 |
+ if (vma->vm_userfaultfd_ctx.ctx == release_new_ctx) |
71 |
+ vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; |
72 |
+ up_write(&mm->mmap_sem); |
73 |
+ |
74 |
+ userfaultfd_ctx_put(release_new_ctx); |
75 |
+ } |
76 |
+ |
77 |
/* |
78 |
* ctx may go away after this if the userfault pseudo fd is |
79 |
* already released. |