mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	userfaultfd: clear the vma->vm_userfaultfd_ctx if UFFD_EVENT_FORK fails
The previous fix in commit 384632e67e ("userfaultfd: non-cooperative:
fix fork use after free") corrected the refcounting in case of
UFFD_EVENT_FORK failure for the fork userfault paths.
That still didn't clear the vma->vm_userfaultfd_ctx of the vmas that
were set to point to the aborted new uffd ctx earlier in
dup_userfaultfd.
Link: http://lkml.kernel.org/r/20171223002505.593-2-aarcange@redhat.com
Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
Reported-by: syzbot <syzkaller@googlegroups.com>
Reviewed-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Cc: Eric Biggers <ebiggers3@gmail.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
			
			
This commit is contained in:
		
							parent
							
								
									d09cfbbfa0
								
							
						
					
					
						commit
						0cbb4b4f4c
					
				
					 1 changed files with 18 additions and 2 deletions
				
			
		| 
						 | 
					@ -570,11 +570,14 @@ int handle_userfault(struct vm_fault *vmf, unsigned long reason)
 | 
				
			||||||
static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx,
 | 
					static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx,
 | 
				
			||||||
					      struct userfaultfd_wait_queue *ewq)
 | 
										      struct userfaultfd_wait_queue *ewq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct userfaultfd_ctx *release_new_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (WARN_ON_ONCE(current->flags & PF_EXITING))
 | 
						if (WARN_ON_ONCE(current->flags & PF_EXITING))
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ewq->ctx = ctx;
 | 
						ewq->ctx = ctx;
 | 
				
			||||||
	init_waitqueue_entry(&ewq->wq, current);
 | 
						init_waitqueue_entry(&ewq->wq, current);
 | 
				
			||||||
 | 
						release_new_ctx = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock(&ctx->event_wqh.lock);
 | 
						spin_lock(&ctx->event_wqh.lock);
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -601,8 +604,7 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx,
 | 
				
			||||||
				new = (struct userfaultfd_ctx *)
 | 
									new = (struct userfaultfd_ctx *)
 | 
				
			||||||
					(unsigned long)
 | 
										(unsigned long)
 | 
				
			||||||
					ewq->msg.arg.reserved.reserved1;
 | 
										ewq->msg.arg.reserved.reserved1;
 | 
				
			||||||
 | 
									release_new_ctx = new;
 | 
				
			||||||
				userfaultfd_ctx_put(new);
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -617,6 +619,20 @@ static void userfaultfd_event_wait_completion(struct userfaultfd_ctx *ctx,
 | 
				
			||||||
	__set_current_state(TASK_RUNNING);
 | 
						__set_current_state(TASK_RUNNING);
 | 
				
			||||||
	spin_unlock(&ctx->event_wqh.lock);
 | 
						spin_unlock(&ctx->event_wqh.lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (release_new_ctx) {
 | 
				
			||||||
 | 
							struct vm_area_struct *vma;
 | 
				
			||||||
 | 
							struct mm_struct *mm = release_new_ctx->mm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* the various vma->vm_userfaultfd_ctx still points to it */
 | 
				
			||||||
 | 
							down_write(&mm->mmap_sem);
 | 
				
			||||||
 | 
							for (vma = mm->mmap; vma; vma = vma->vm_next)
 | 
				
			||||||
 | 
								if (vma->vm_userfaultfd_ctx.ctx == release_new_ctx)
 | 
				
			||||||
 | 
									vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
 | 
				
			||||||
 | 
							up_write(&mm->mmap_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							userfaultfd_ctx_put(release_new_ctx);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * ctx may go away after this if the userfault pseudo fd is
 | 
						 * ctx may go away after this if the userfault pseudo fd is
 | 
				
			||||||
	 * already released.
 | 
						 * already released.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue