summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJann Horn <jannh@google.com>2019-10-16 11:01:18 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-10-17 08:58:44 -0400
commit45d02f79b539073b76077836871de6b674e36eb4 (patch)
treeff505d460ace78810d7dcf93084d32d2d830d409
parent4f5cafb5cb8471e54afdc9054d973535614f7675 (diff)
binder: Don't modify VMA bounds in ->mmap handler
binder_mmap() tries to prevent the creation of overly big binder mappings by silently truncating the size of the VMA to 4MiB. However, this violates the API contract of mmap(). If userspace attempts to create a large binder VMA, and later attempts to unmap that VMA, it will call munmap() on a range beyond the end of the VMA, which may have been allocated to another VMA in the meantime. This can lead to userspace memory corruption. The following sequence of calls leads to a segfault without this commit: int main(void) { int binder_fd = open("/dev/binder", O_RDWR); if (binder_fd == -1) err(1, "open binder"); void *binder_mapping = mmap(NULL, 0x800000UL, PROT_READ, MAP_SHARED, binder_fd, 0); if (binder_mapping == MAP_FAILED) err(1, "mmap binder"); void *data_mapping = mmap(NULL, 0x400000UL, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (data_mapping == MAP_FAILED) err(1, "mmap data"); munmap(binder_mapping, 0x800000UL); *(char*)data_mapping = 1; return 0; } Cc: stable@vger.kernel.org Signed-off-by: Jann Horn <jannh@google.com> Acked-by: Todd Kjos <tkjos@google.com> Acked-by: Christian Brauner <christian.brauner@ubuntu.com> Link: https://lore.kernel.org/r/20191016150119.154756-1-jannh@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/android/binder.c7
-rw-r--r--drivers/android/binder_alloc.c6
2 files changed, 4 insertions, 9 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 5b9ac2122e89..265d9dd46a5e 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -97,10 +97,6 @@ DEFINE_SHOW_ATTRIBUTE(proc);
97#define SZ_1K 0x400 97#define SZ_1K 0x400
98#endif 98#endif
99 99
100#ifndef SZ_4M
101#define SZ_4M 0x400000
102#endif
103
104#define FORBIDDEN_MMAP_FLAGS (VM_WRITE) 100#define FORBIDDEN_MMAP_FLAGS (VM_WRITE)
105 101
106enum { 102enum {
@@ -5177,9 +5173,6 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
5177 if (proc->tsk != current->group_leader) 5173 if (proc->tsk != current->group_leader)
5178 return -EINVAL; 5174 return -EINVAL;
5179 5175
5180 if ((vma->vm_end - vma->vm_start) > SZ_4M)
5181 vma->vm_end = vma->vm_start + SZ_4M;
5182
5183 binder_debug(BINDER_DEBUG_OPEN_CLOSE, 5176 binder_debug(BINDER_DEBUG_OPEN_CLOSE,
5184 "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", 5177 "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n",
5185 __func__, proc->pid, vma->vm_start, vma->vm_end, 5178 __func__, proc->pid, vma->vm_start, vma->vm_end,
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index d42a8b2f636a..eb76a823fbb2 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -22,6 +22,7 @@
22#include <asm/cacheflush.h> 22#include <asm/cacheflush.h>
23#include <linux/uaccess.h> 23#include <linux/uaccess.h>
24#include <linux/highmem.h> 24#include <linux/highmem.h>
25#include <linux/sizes.h>
25#include "binder_alloc.h" 26#include "binder_alloc.h"
26#include "binder_trace.h" 27#include "binder_trace.h"
27 28
@@ -689,7 +690,9 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
689 alloc->buffer = (void __user *)vma->vm_start; 690 alloc->buffer = (void __user *)vma->vm_start;
690 mutex_unlock(&binder_alloc_mmap_lock); 691 mutex_unlock(&binder_alloc_mmap_lock);
691 692
692 alloc->pages = kcalloc((vma->vm_end - vma->vm_start) / PAGE_SIZE, 693 alloc->buffer_size = min_t(unsigned long, vma->vm_end - vma->vm_start,
694 SZ_4M);
695 alloc->pages = kcalloc(alloc->buffer_size / PAGE_SIZE,
693 sizeof(alloc->pages[0]), 696 sizeof(alloc->pages[0]),
694 GFP_KERNEL); 697 GFP_KERNEL);
695 if (alloc->pages == NULL) { 698 if (alloc->pages == NULL) {
@@ -697,7 +700,6 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
697 failure_string = "alloc page array"; 700 failure_string = "alloc page array";
698 goto err_alloc_pages_failed; 701 goto err_alloc_pages_failed;
699 } 702 }
700 alloc->buffer_size = vma->vm_end - vma->vm_start;
701 703
702 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); 704 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
703 if (!buffer) { 705 if (!buffer) {