| From 21c7feb6e3e3c12e46d1718259f3737862232206 Mon Sep 17 00:00:00 2001 |
| From: Jann Horn <jannh@google.com> |
| Date: Fri, 18 Oct 2019 22:56:29 +0200 |
| Subject: [PATCH] binder: Fix race between mmap() and |
| binder_alloc_print_pages() |
| |
| commit 8eb52a1ee37aafd9b796713aa0b3ab9cbc455be3 upstream. |
| |
| binder_alloc_print_pages() iterates over |
| alloc->pages[0..alloc->buffer_size-1] under alloc->mutex. |
| binder_alloc_mmap_handler() writes alloc->pages and alloc->buffer_size |
| without holding that lock, and even writes them before the last bailout |
| point. |
| |
| Unfortunately we can't take the alloc->mutex in the ->mmap() handler |
| because mmap_sem can be taken while alloc->mutex is held. |
| So instead, we have to locklessly check whether the binder_alloc has been |
| fully initialized with binder_alloc_get_vma(), like in |
| binder_alloc_new_buf_locked(). |
| |
| Fixes: 8ef4665aa129 ("android: binder: Add page usage in binder stats") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Jann Horn <jannh@google.com> |
| Acked-by: Christian Brauner <christian.brauner@ubuntu.com> |
| Link: https://lore.kernel.org/r/20191018205631.248274-1-jannh@google.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c |
| index 8fe99b20ca02..b39894fe80ef 100644 |
| --- a/drivers/android/binder_alloc.c |
| +++ b/drivers/android/binder_alloc.c |
| @@ -841,14 +841,20 @@ void binder_alloc_print_pages(struct seq_file *m, |
| int free = 0; |
| |
| mutex_lock(&alloc->mutex); |
| - for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { |
| - page = &alloc->pages[i]; |
| - if (!page->page_ptr) |
| - free++; |
| - else if (list_empty(&page->lru)) |
| - active++; |
| - else |
| - lru++; |
| + /* |
| + * Make sure the binder_alloc is fully initialized, otherwise we might |
| + * read inconsistent state. |
| + */ |
| + if (binder_alloc_get_vma(alloc) != NULL) { |
| + for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { |
| + page = &alloc->pages[i]; |
| + if (!page->page_ptr) |
| + free++; |
| + else if (list_empty(&page->lru)) |
| + active++; |
| + else |
| + lru++; |
| + } |
| } |
| mutex_unlock(&alloc->mutex); |
| seq_printf(m, " pages: %d:%d:%d\n", active, lru, free); |
| -- |
| 2.7.4 |
| |