diff options
author | Todd Kjos <tkjos@android.com> | 2017-06-29 15:01:51 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-07-17 08:47:29 -0400 |
commit | 53d311cfa19ad35beba74d706effee02c86d198f (patch) | |
tree | 669eb2b29fbf3b3c0dd24e8eb16212017eb0f24d | |
parent | e4cffcf4bf8b540e150c311e70559d735cc95358 (diff) |
binder: protect against two threads freeing buffer
Adds protection against malicious user code freeing
the same buffer at the same time which could cause
a crash. Cannot happen under normal use.
Signed-off-by: Todd Kjos <tkjos@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/android/binder.c | 4 | ||||
-rw-r--r-- | drivers/android/binder_alloc.c | 22 | ||||
-rw-r--r-- | drivers/android/binder_alloc.h | 7 |
3 files changed, 23 insertions, 10 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 3bbfb2455b70..a1912a22c89c 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c | |||
@@ -2024,8 +2024,8 @@ static int binder_thread_write(struct binder_proc *proc, | |||
2024 | return -EFAULT; | 2024 | return -EFAULT; |
2025 | ptr += sizeof(binder_uintptr_t); | 2025 | ptr += sizeof(binder_uintptr_t); |
2026 | 2026 | ||
2027 | buffer = binder_alloc_buffer_lookup(&proc->alloc, | 2027 | buffer = binder_alloc_prepare_to_free(&proc->alloc, |
2028 | data_ptr); | 2028 | data_ptr); |
2029 | if (buffer == NULL) { | 2029 | if (buffer == NULL) { |
2030 | binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", | 2030 | binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", |
2031 | proc->pid, thread->pid, (u64)data_ptr); | 2031 | proc->pid, thread->pid, (u64)data_ptr); |
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index a0af1419cc79..2a2e41b13de5 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c | |||
@@ -116,7 +116,7 @@ static void binder_insert_allocated_buffer_locked( | |||
116 | rb_insert_color(&new_buffer->rb_node, &alloc->allocated_buffers); | 116 | rb_insert_color(&new_buffer->rb_node, &alloc->allocated_buffers); |
117 | } | 117 | } |
118 | 118 | ||
119 | static struct binder_buffer *binder_alloc_buffer_lookup_locked( | 119 | static struct binder_buffer *binder_alloc_prepare_to_free_locked( |
120 | struct binder_alloc *alloc, | 120 | struct binder_alloc *alloc, |
121 | uintptr_t user_ptr) | 121 | uintptr_t user_ptr) |
122 | { | 122 | { |
@@ -135,8 +135,19 @@ static struct binder_buffer *binder_alloc_buffer_lookup_locked( | |||
135 | n = n->rb_left; | 135 | n = n->rb_left; |
136 | else if (kern_ptr > buffer) | 136 | else if (kern_ptr > buffer) |
137 | n = n->rb_right; | 137 | n = n->rb_right; |
138 | else | 138 | else { |
139 | /* | ||
140 | * Guard against user threads attempting to | ||
141 | * free the buffer twice | ||
142 | */ | ||
143 | if (buffer->free_in_progress) { | ||
144 | pr_err("%d:%d FREE_BUFFER u%016llx user freed buffer twice\n", | ||
145 | alloc->pid, current->pid, (u64)user_ptr); | ||
146 | return NULL; | ||
147 | } | ||
148 | buffer->free_in_progress = 1; | ||
139 | return buffer; | 149 | return buffer; |
150 | } | ||
140 | } | 151 | } |
141 | return NULL; | 152 | return NULL; |
142 | } | 153 | } |
@@ -152,13 +163,13 @@ static struct binder_buffer *binder_alloc_buffer_lookup_locked( | |||
152 | * | 163 | * |
153 | * Return: Pointer to buffer or NULL | 164 | * Return: Pointer to buffer or NULL |
154 | */ | 165 | */ |
155 | struct binder_buffer *binder_alloc_buffer_lookup(struct binder_alloc *alloc, | 166 | struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc, |
156 | uintptr_t user_ptr) | 167 | uintptr_t user_ptr) |
157 | { | 168 | { |
158 | struct binder_buffer *buffer; | 169 | struct binder_buffer *buffer; |
159 | 170 | ||
160 | mutex_lock(&alloc->mutex); | 171 | mutex_lock(&alloc->mutex); |
161 | buffer = binder_alloc_buffer_lookup_locked(alloc, user_ptr); | 172 | buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr); |
162 | mutex_unlock(&alloc->mutex); | 173 | mutex_unlock(&alloc->mutex); |
163 | return buffer; | 174 | return buffer; |
164 | } | 175 | } |
@@ -358,6 +369,7 @@ struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, | |||
358 | 369 | ||
359 | rb_erase(best_fit, &alloc->free_buffers); | 370 | rb_erase(best_fit, &alloc->free_buffers); |
360 | buffer->free = 0; | 371 | buffer->free = 0; |
372 | buffer->free_in_progress = 0; | ||
361 | binder_insert_allocated_buffer_locked(alloc, buffer); | 373 | binder_insert_allocated_buffer_locked(alloc, buffer); |
362 | if (buffer_size != size) { | 374 | if (buffer_size != size) { |
363 | struct binder_buffer *new_buffer = (void *)buffer->data + size; | 375 | struct binder_buffer *new_buffer = (void *)buffer->data + size; |
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 721c511431f9..088e4ffc6230 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h | |||
@@ -48,7 +48,8 @@ struct binder_buffer { | |||
48 | unsigned free:1; | 48 | unsigned free:1; |
49 | unsigned allow_user_free:1; | 49 | unsigned allow_user_free:1; |
50 | unsigned async_transaction:1; | 50 | unsigned async_transaction:1; |
51 | unsigned debug_id:29; | 51 | unsigned free_in_progress:1; |
52 | unsigned debug_id:28; | ||
52 | 53 | ||
53 | struct binder_transaction *transaction; | 54 | struct binder_transaction *transaction; |
54 | 55 | ||
@@ -109,8 +110,8 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, | |||
109 | extern void binder_alloc_init(struct binder_alloc *alloc); | 110 | extern void binder_alloc_init(struct binder_alloc *alloc); |
110 | extern void binder_alloc_vma_close(struct binder_alloc *alloc); | 111 | extern void binder_alloc_vma_close(struct binder_alloc *alloc); |
111 | extern struct binder_buffer * | 112 | extern struct binder_buffer * |
112 | binder_alloc_buffer_lookup(struct binder_alloc *alloc, | 113 | binder_alloc_prepare_to_free(struct binder_alloc *alloc, |
113 | uintptr_t user_ptr); | 114 | uintptr_t user_ptr); |
114 | extern void binder_alloc_free_buf(struct binder_alloc *alloc, | 115 | extern void binder_alloc_free_buf(struct binder_alloc *alloc, |
115 | struct binder_buffer *buffer); | 116 | struct binder_buffer *buffer); |
116 | extern int binder_alloc_mmap_handler(struct binder_alloc *alloc, | 117 | extern int binder_alloc_mmap_handler(struct binder_alloc *alloc, |