diff options
Diffstat (limited to 'mm/memory.c')
| -rw-r--r-- | mm/memory.c | 31 | 
1 files changed, 19 insertions, 12 deletions
diff --git a/mm/memory.c b/mm/memory.c index 01f39e8144ef..1ec1ef3418bf 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -5393,27 +5393,28 @@ retry:  	if (!vma_is_anonymous(vma) && !vma_is_tcp(vma))  		goto inval; -	/* find_mergeable_anon_vma uses adjacent vmas which are not locked */ -	if (!vma->anon_vma && !vma_is_tcp(vma)) -		goto inval; -  	if (!vma_start_read(vma))  		goto inval;  	/* +	 * find_mergeable_anon_vma uses adjacent vmas which are not locked. +	 * This check must happen after vma_start_read(); otherwise, a +	 * concurrent mremap() with MREMAP_DONTUNMAP could dissociate the VMA +	 * from its anon_vma. +	 */ +	if (unlikely(!vma->anon_vma && !vma_is_tcp(vma))) +		goto inval_end_read; + +	/*  	 * Due to the possibility of userfault handler dropping mmap_lock, avoid  	 * it for now and fall back to page fault handling under mmap_lock.  	 */ -	if (userfaultfd_armed(vma)) { -		vma_end_read(vma); -		goto inval; -	} +	if (userfaultfd_armed(vma)) +		goto inval_end_read;  	/* Check since vm_start/vm_end might change before we lock the VMA */ -	if (unlikely(address < vma->vm_start || address >= vma->vm_end)) { -		vma_end_read(vma); -		goto inval; -	} +	if (unlikely(address < vma->vm_start || address >= vma->vm_end)) +		goto inval_end_read;  	/* Check if the VMA got isolated after we found it */  	if (vma->detached) { @@ -5425,6 +5426,9 @@ retry:  	rcu_read_unlock();  	return vma; + +inval_end_read: +	vma_end_read(vma);  inval:  	rcu_read_unlock();  	count_vm_vma_lock_event(VMA_LOCK_ABORT); @@ -5701,6 +5705,9 @@ int __access_remote_vm(struct mm_struct *mm, unsigned long addr, void *buf,  	if (mmap_read_lock_killable(mm))  		return 0; +	/* Untag the address before looking up the VMA */ +	addr = untagged_addr_remote(mm, addr); +  	/* Avoid triggering the temporary warning in __get_user_pages */  	if (!vma_lookup(mm, addr) && !expand_stack(mm, addr))  		return 0;  | 
