diff options
author | Christopher Lais <chris+android@zenthought.org> | 2011-12-13 01:24:18 +0800 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2012-01-09 10:54:59 +0800 |
commit | b33d42acce70e434d336393bea586ce2b054e121 (patch) | |
tree | bc992b746a2a95bf4007262b580381cfeaecdd22 | |
parent | f6283b52260090597d6e772abe36bbd3c36e9d25 (diff) | |
download | imx53-b33d42acce70e434d336393bea586ce2b054e121.tar.gz |
binder: Fix memory corruption via page aliasing
binder_deferred_release was not unmapping the page from the buffer
before freeing it, causing memory corruption. This only happened
when page(s) had not been freed by binder_update_page_range, which
properly unmaps the pages.
This only happens on architectures with VIPT aliasing.
To reproduce, create a program which opens, mmaps, munmaps, then closes
the binder very quickly. This should leave a page allocated when the
binder is released. When binder_deferrred_release is called on the
close, the page will remain mapped to the address in the linear
proc->buffer. Later, we may map the same physical page to a different
virtual address that has different coloring, and this may cause
aliasing to occur.
PAGE_POISONING will greatly increase your chances of noticing any
problems.
Change-Id: I6941bf212881b8bf846bdfda43d3609c7ae4892e
Signed-off-by: Christopher Lais <chris+android@zenthought.org>
-rw-r--r-- | drivers/staging/android/binder.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index d14a3c41fc8..34284af58a2 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -3035,11 +3035,14 @@ static void binder_deferred_release(struct binder_proc *proc) int i; for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { if (proc->pages[i]) { + void *page_addr = proc->buffer + i * PAGE_SIZE; binder_debug(BINDER_DEBUG_BUFFER_ALLOC, "binder_release: %d: " "page %d at %p not freed\n", proc->pid, i, - proc->buffer + i * PAGE_SIZE); + page_addr); + unmap_kernel_range((unsigned long)page_addr, + PAGE_SIZE); __free_page(proc->pages[i]); page_count++; } |