Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a4149ac authored by shaohanlin(127659)'s avatar shaohanlin(127659) Committed by Gerrit Code Review
Browse files

Merge "coredump: fix race condition between mmget_not_zero()/get_task_mm() and...

Merge "coredump: fix race condition between mmget_not_zero()/get_task_mm() and core dumping" into 8901-fairphone-p-mp-release
parents 66c8048a 1ead9dab
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -1122,6 +1122,24 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
					count = -EINTR;
					goto out_mm;
				}
				/*
				 * Avoid to modify vma->vm_flags
				 * without locked ops while the
				 * coredump reads the vm_flags.
				 */
				if (!mmget_still_valid(mm)) {
					/*
					 * Silently return "count"
					 * like if get_task_mm()
					 * failed. FIXME: should this
					 * function have returned
					 * -ESRCH if get_task_mm()
					 * failed like if
					 * get_proc_task() fails?
					 */
					up_write(&mm->mmap_sem);
					goto out_mm;
				}
				for (vma = mm->mmap; vma; vma = vma->vm_next) {
					vm_write_begin(vma);
					WRITE_ONCE(vma->vm_flags,
+9 −0
Original line number Diff line number Diff line
@@ -479,6 +479,8 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
	 * taking the mmap_sem for writing.
	 */
	down_write(&mm->mmap_sem);
	if (!mmget_still_valid(mm))
		goto skip_mm;
	prev = NULL;
	for (vma = mm->mmap; vma; vma = vma->vm_next) {
		cond_resched();
@@ -504,6 +506,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
		vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
		vm_write_end(vma);
	}
skip_mm:
	up_write(&mm->mmap_sem);
	mmput(mm);
wakeup:
@@ -805,6 +808,9 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
		goto out;

	down_write(&mm->mmap_sem);
	if (!mmget_still_valid(mm))
		goto out_unlock;

	vma = find_vma_prev(mm, start, &prev);
	if (!vma)
		goto out_unlock;
@@ -953,6 +959,9 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
		goto out;

	down_write(&mm->mmap_sem);
	if (!mmget_still_valid(mm))
		goto out_unlock;

	vma = find_vma_prev(mm, start, &prev);
	if (!vma)
		goto out_unlock;
+20 −0
Original line number Diff line number Diff line
@@ -1213,6 +1213,26 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long address,
		unsigned long size, struct zap_details *);
void unmap_vmas(struct mmu_gather *tlb, struct vm_area_struct *start_vma,
		unsigned long start, unsigned long end);
/*
 * This has to be called after a get_task_mm()/mmget_not_zero()
 * followed by taking the mmap_sem for writing before modifying the
 * vmas or anything the coredump pretends not to change from under it.
 *
 * NOTE: find_extend_vma() called from GUP context is the only place
 * that can modify the "mm" (notably the vm_start/end) under mmap_sem
 * for reading and outside the context of the process, so it is also
 * the only case that holds the mmap_sem for reading that must call
 * this function. Generally if the mmap_sem is hold for reading
 * there's no need of this check after get_task_mm()/mmget_not_zero().
 *
 * This function can be obsoleted and the check can be removed, after
 * the coredump code will hold the mmap_sem for writing before
 * invoking the ->core_dump methods.
 */
static inline bool mmget_still_valid(struct mm_struct *mm)
{
	return likely(!mm->core_state);
}

/**
 * mm_walk - callbacks for walk_page_range
+5 −1
Original line number Diff line number Diff line
@@ -2561,7 +2561,8 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr)
	vma = find_vma_prev(mm, addr, &prev);
	if (vma && (vma->vm_start <= addr))
		return vma;
	if (!prev || expand_stack(prev, addr))
	/* don't alter vm_end if the coredump is running */
	if (!prev || !mmget_still_valid(mm) || expand_stack(prev, addr))
		return NULL;
	if (prev->vm_flags & VM_LOCKED)
		populate_vma_page_range(prev, addr, prev->vm_end, NULL);
@@ -2587,6 +2588,9 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr)
		return vma;
	if (!(vma->vm_flags & VM_GROWSDOWN))
		return NULL;
	/* don't alter vm_start if the coredump is running */
	if (!mmget_still_valid(mm))
		return NULL;
	start = vma->vm_start;
	if (expand_stack(vma, addr))
		return NULL;