Re: [PATCH v3] binder: add mutex_lock for mmap and NULL when free

From: Kassey Li
Date: Mon Oct 09 2023 - 08:22:32 EST




On 2023/10/8 7:16, Carlos Llamas wrote:
On Sat, Oct 07, 2023 at 08:28:13PM +0800, Kassey Li wrote:
- Enforce alloc->mutex in binder_alloc_mmap_handler when add the entry to
list.

- Assign the freed pages/page_ptr to NULL to catch possible use after free
with NULL pointer access.

Fixes: 19c987241ca1 ("binder: separate out binder_alloc functions")
Fixes: f2517eb76f1f ("android: binder: Add global lru shrinker to binder")
CC: Todd Kjos <tkjos@xxxxxxxxxxx>
CC: Sherry Yang <sherryy@xxxxxxxxxxx>
Link: https://lore.kernel.org/all/20231007034046.2352124-1-quic_yingangl@xxxxxxxxxxx/
Signed-off-by: Kassey Li <quic_yingangl@xxxxxxxxxxx>
---
V1 -> V2: Add Fixes info.
V2 -> V3: Add this history.
---
drivers/android/binder_alloc.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index e3db8297095a..c7d126e04343 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -775,6 +775,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
}
buffer->user_data = alloc->buffer;
+ mutex_lock(&alloc->mutex);

At this stage we are already holding the mm->mmap_lock. If you take the
alloc->mutex here you will deadlock. You should see this warning with
lockdep enabled. Also, you don't need the lock here...

lockdep did not warn, but i agree with you, i did not aware the mm->mmap_lock. thanks for the remind.

list_add(&buffer->entry, &alloc->buffers);
buffer->free = 1;
binder_insert_free_buffer(alloc, buffer);
@@ -782,7 +783,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
/* Signal binder_alloc is fully initialized */
binder_alloc_set_vma(alloc, vma);

This barrier will set the alloc->vma pointer. Once set, it signals that
the alloc-> space has been initialized and it is safe to access.

-
+ mutex_unlock(&alloc->mutex);
return 0;
err_alloc_buf_struct_failed:
@@ -856,9 +857,11 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
__func__, alloc->pid, i, page_addr,
on_lru ? "on lru" : "active");
__free_page(alloc->pages[i].page_ptr);
+ alloc->pages[i].page_ptr = NULL;
page_count++;
}
kfree(alloc->pages);
+ alloc->pages = NULL;

The process is dying and there aren't any more references to it. It is
pointless to mark the pages NULL. No one is or will use them after.

looks correct.

}
mutex_unlock(&alloc->mutex);
if (alloc->mm)
--
2.25.1


I see that you reported a crash on the previous thread here:
https://lore.kernel.org/all/26988068-8c9f-8591-db6e-44c8105af638@xxxxxxxxxxx/
...unfortunately, it doesn't seem to me like setting alloc->pages = NULL
would help fix your issue.

I do agree this sounds like a use-after-free though. Are you able to
reproduce the issue with KASAN enabled? This should tell us where the
actual problem is.

kasan is trying but not reproduced yet, we will chasing with this test enable kasan.

--
Carlos Llamas