aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/android/binder_alloc.c
diff options
context:
space:
mode:
authorTodd Kjos <tkjos@android.com>2018-11-06 18:55:32 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-11-26 14:01:47 -0500
commit7bada55ab50697861eee6bb7d60b41e68a961a9c (patch)
tree90962d6d3e534ff0a8321118279016bcbb541f8e /drivers/android/binder_alloc.c
parent032371a1e673275202c047537726f4216d7dbf0b (diff)
binder: fix race that allows malicious free of live buffer
Malicious code can attempt to free buffers using the BC_FREE_BUFFER ioctl to binder. There are protections against a user freeing a buffer while in use by the kernel, however there was a window where BC_FREE_BUFFER could be used to free a recently allocated buffer that was not completely initialized. This resulted in a use-after-free detected by KASAN with a malicious test program. This window is closed by setting the buffer's allow_user_free attribute to 0 when the buffer is allocated or when the user has previously freed it instead of waiting for the caller to set it. The problem was that when the struct buffer was recycled, allow_user_free was stale and set to 1 allowing a free to go through. Signed-off-by: Todd Kjos <tkjos@google.com> Acked-by: Arve Hjønnevåg <arve@android.com> Cc: stable <stable@vger.kernel.org> # 4.14 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/android/binder_alloc.c')
-rw-r--r--drivers/android/binder_alloc.c16
1 files changed, 6 insertions, 10 deletions
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index 64fd96eada31..030c98f35cca 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -151,16 +151,12 @@ static struct binder_buffer *binder_alloc_prepare_to_free_locked(
151 else { 151 else {
152 /* 152 /*
153 * Guard against user threads attempting to 153 * Guard against user threads attempting to
154 * free the buffer twice 154 * free the buffer when in use by kernel or
155 * after it's already been freed.
155 */ 156 */
156 if (buffer->free_in_progress) { 157 if (!buffer->allow_user_free)
157 binder_alloc_debug(BINDER_DEBUG_USER_ERROR, 158 return ERR_PTR(-EPERM);
158 "%d:%d FREE_BUFFER u%016llx user freed buffer twice\n", 159 buffer->allow_user_free = 0;
159 alloc->pid, current->pid,
160 (u64)user_ptr);
161 return NULL;
162 }
163 buffer->free_in_progress = 1;
164 return buffer; 160 return buffer;
165 } 161 }
166 } 162 }
@@ -500,7 +496,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked(
500 496
501 rb_erase(best_fit, &alloc->free_buffers); 497 rb_erase(best_fit, &alloc->free_buffers);
502 buffer->free = 0; 498 buffer->free = 0;
503 buffer->free_in_progress = 0; 499 buffer->allow_user_free = 0;
504 binder_insert_allocated_buffer_locked(alloc, buffer); 500 binder_insert_allocated_buffer_locked(alloc, buffer);
505 binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, 501 binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
506 "%d: binder_alloc_buf size %zd got %pK\n", 502 "%d: binder_alloc_buf size %zd got %pK\n",