OSDN Git Service

binder: Fix memory corruption via page aliasing
authorChristopher Lais <chris+android@zenthought.org>
Sat, 1 May 2010 20:51:48 +0000 (15:51 -0500)
committerIliyan Malchev <malchev@google.com>
Mon, 23 May 2011 22:43:38 +0000 (15:43 -0700)
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>
drivers/staging/android/binder.c

index 6e1d78c..e13b4c4 100644 (file)
@@ -3036,11 +3036,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++;
                        }