diff mbox series

[1/1] binder: fix race between munmap() and direct reclaim

Message ID 1555571261-7298-2-git-send-email-tyhicks@canonical.com
State New
Headers show
Series [1/1] binder: fix race between munmap() and direct reclaim | expand

Commit Message

Tyler Hicks April 18, 2019, 7:07 a.m. UTC
From: Todd Kjos <tkjos@android.com>

An munmap() on a binder device causes binder_vma_close() to be called
which clears the alloc->vma pointer.

If direct reclaim causes binder_alloc_free_page() to be called, there
is a race where alloc->vma is read into a local vma pointer and then
used later after the mm->mmap_sem is acquired. This can result in
calling zap_page_range() with an invalid vma which manifests as a
use-after-free in zap_page_range().

The fix is to check alloc->vma after acquiring the mmap_sem (which we
were acquiring anyway) and skip zap_page_range() if it has changed
to NULL.

Signed-off-by: Todd Kjos <tkjos@google.com>
Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

CVE-2019-1999

(backported from commit 5cec2d2e5839f9c0fec319c523a911e0a7fd299f)
[tyhicks: Backport to 5.0:
 - The write mode of mmap_sem is held in 5.0]
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
---
 drivers/android/binder_alloc.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

Comments

Stefan Bader April 18, 2019, 8:43 a.m. UTC | #1
On 18.04.19 09:07, Tyler Hicks wrote:
> From: Todd Kjos <tkjos@android.com>
> 
> An munmap() on a binder device causes binder_vma_close() to be called
> which clears the alloc->vma pointer.
> 
> If direct reclaim causes binder_alloc_free_page() to be called, there
> is a race where alloc->vma is read into a local vma pointer and then
> used later after the mm->mmap_sem is acquired. This can result in
> calling zap_page_range() with an invalid vma which manifests as a
> use-after-free in zap_page_range().
> 
> The fix is to check alloc->vma after acquiring the mmap_sem (which we
> were acquiring anyway) and skip zap_page_range() if it has changed
> to NULL.
> 
> Signed-off-by: Todd Kjos <tkjos@google.com>
> Reviewed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
> Cc: stable <stable@vger.kernel.org>
> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> 
> CVE-2019-1999
> 
> (backported from commit 5cec2d2e5839f9c0fec319c523a911e0a7fd299f)
> [tyhicks: Backport to 5.0:
>  - The write mode of mmap_sem is held in 5.0]
> Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
> ---
>  drivers/android/binder_alloc.c | 18 ++++++++----------
>  1 file changed, 8 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
> index 6a9a4b83b057..c4d8b786d671 100644
> --- a/drivers/android/binder_alloc.c
> +++ b/drivers/android/binder_alloc.c
> @@ -958,14 +958,13 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
>  
>  	index = page - alloc->pages;
>  	page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE;
> +
> +	mm = alloc->vma_vm_mm;
> +	if (!mmget_not_zero(mm))
> +		goto err_mmget;
> +	if (!down_write_trylock(&mm->mmap_sem))
> +		goto err_down_write_mmap_sem_failed;
>  	vma = binder_alloc_get_vma(alloc);
> -	if (vma) {
> -		if (!mmget_not_zero(alloc->vma_vm_mm))
> -			goto err_mmget;
> -		mm = alloc->vma_vm_mm;
> -		if (!down_write_trylock(&mm->mmap_sem))
> -			goto err_down_write_mmap_sem_failed;
> -	}
>  
>  	list_lru_isolate(lru, item);
>  	spin_unlock(lock);
> @@ -978,10 +977,9 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
>  			       PAGE_SIZE);
>  
>  		trace_binder_unmap_user_end(alloc, index);
> -
> -		up_write(&mm->mmap_sem);
> -		mmput(mm);
>  	}
> +	up_write(&mm->mmap_sem);
> +	mmput(mm);
>  
>  	trace_binder_unmap_kernel_start(alloc, index);
>  
>
diff mbox series

Patch

diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 6a9a4b83b057..c4d8b786d671 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -958,14 +958,13 @@  enum lru_status binder_alloc_free_page(struct list_head *item,
 
 	index = page - alloc->pages;
 	page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE;
+
+	mm = alloc->vma_vm_mm;
+	if (!mmget_not_zero(mm))
+		goto err_mmget;
+	if (!down_write_trylock(&mm->mmap_sem))
+		goto err_down_write_mmap_sem_failed;
 	vma = binder_alloc_get_vma(alloc);
-	if (vma) {
-		if (!mmget_not_zero(alloc->vma_vm_mm))
-			goto err_mmget;
-		mm = alloc->vma_vm_mm;
-		if (!down_write_trylock(&mm->mmap_sem))
-			goto err_down_write_mmap_sem_failed;
-	}
 
 	list_lru_isolate(lru, item);
 	spin_unlock(lock);
@@ -978,10 +977,9 @@  enum lru_status binder_alloc_free_page(struct list_head *item,
 			       PAGE_SIZE);
 
 		trace_binder_unmap_user_end(alloc, index);
-
-		up_write(&mm->mmap_sem);
-		mmput(mm);
 	}
+	up_write(&mm->mmap_sem);
+	mmput(mm);
 
 	trace_binder_unmap_kernel_start(alloc, index);