aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/android
diff options
context:
space:
mode:
authorTodd Kjos <tkjos@android.com>2019-02-08 13:35:17 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-02-12 04:43:57 -0500
commitdb6b0b810bf945d1991917ffce0e93383101f2fa (patch)
treeae9e2393b7db6604fca6650f6f7bbc4ea17bea93 /drivers/android
parent7a67a39320dfba4b36d3be5dae4581194e650316 (diff)
binder: avoid kernel vm_area for buffer fixups
Refactor the functions to validate and fixup struct binder_buffer pointer objects to avoid using vm_area pointers. Instead copy to/from kernel space using binder_alloc_copy_to_buffer() and binder_alloc_copy_from_buffer(). The following functions were refactored: refactor binder_validate_ptr() binder_validate_fixup() binder_fixup_parent() Signed-off-by: Todd Kjos <tkjos@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/android')
-rw-r--r--drivers/android/binder.c146
1 files changed, 97 insertions, 49 deletions
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index d1bd35914640..db0c45bc9134 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2092,10 +2092,13 @@ static size_t binder_get_object(struct binder_proc *proc,
2092 2092
2093/** 2093/**
2094 * binder_validate_ptr() - validates binder_buffer_object in a binder_buffer. 2094 * binder_validate_ptr() - validates binder_buffer_object in a binder_buffer.
2095 * @proc: binder_proc owning the buffer
2095 * @b: binder_buffer containing the object 2096 * @b: binder_buffer containing the object
2097 * @object: struct binder_object to read into
2096 * @index: index in offset array at which the binder_buffer_object is 2098 * @index: index in offset array at which the binder_buffer_object is
2097 * located 2099 * located
2098 * @start: points to the start of the offset array 2100 * @start_offset: points to the start of the offset array
2101 * @object_offsetp: offset of @object read from @b
2099 * @num_valid: the number of valid offsets in the offset array 2102 * @num_valid: the number of valid offsets in the offset array
2100 * 2103 *
2101 * Return: If @index is within the valid range of the offset array 2104 * Return: If @index is within the valid range of the offset array
@@ -2106,34 +2109,46 @@ static size_t binder_get_object(struct binder_proc *proc,
2106 * Note that the offset found in index @index itself is not 2109 * Note that the offset found in index @index itself is not
2107 * verified; this function assumes that @num_valid elements 2110 * verified; this function assumes that @num_valid elements
2108 * from @start were previously verified to have valid offsets. 2111 * from @start were previously verified to have valid offsets.
2112 * If @object_offsetp is non-NULL, then the offset within
2113 * @b is written to it.
2109 */ 2114 */
2110static struct binder_buffer_object *binder_validate_ptr(struct binder_buffer *b, 2115static struct binder_buffer_object *binder_validate_ptr(
2111 binder_size_t index, 2116 struct binder_proc *proc,
2112 binder_size_t *start, 2117 struct binder_buffer *b,
2113 binder_size_t num_valid) 2118 struct binder_object *object,
2119 binder_size_t index,
2120 binder_size_t start_offset,
2121 binder_size_t *object_offsetp,
2122 binder_size_t num_valid)
2114{ 2123{
2115 struct binder_buffer_object *buffer_obj; 2124 size_t object_size;
2116 binder_size_t *offp; 2125 binder_size_t object_offset;
2126 unsigned long buffer_offset;
2117 2127
2118 if (index >= num_valid) 2128 if (index >= num_valid)
2119 return NULL; 2129 return NULL;
2120 2130
2121 offp = start + index; 2131 buffer_offset = start_offset + sizeof(binder_size_t) * index;
2122 buffer_obj = (struct binder_buffer_object *)(b->data + *offp); 2132 binder_alloc_copy_from_buffer(&proc->alloc, &object_offset,
2123 if (buffer_obj->hdr.type != BINDER_TYPE_PTR) 2133 b, buffer_offset, sizeof(object_offset));
2134 object_size = binder_get_object(proc, b, object_offset, object);
2135 if (!object_size || object->hdr.type != BINDER_TYPE_PTR)
2124 return NULL; 2136 return NULL;
2137 if (object_offsetp)
2138 *object_offsetp = object_offset;
2125 2139
2126 return buffer_obj; 2140 return &object->bbo;
2127} 2141}
2128 2142
2129/** 2143/**
2130 * binder_validate_fixup() - validates pointer/fd fixups happen in order. 2144 * binder_validate_fixup() - validates pointer/fd fixups happen in order.
2145 * @proc: binder_proc owning the buffer
2131 * @b: transaction buffer 2146 * @b: transaction buffer
2132 * @objects_start start of objects buffer 2147 * @objects_start_offset: offset to start of objects buffer
2133 * @buffer: binder_buffer_object in which to fix up 2148 * @buffer_obj_offset: offset to binder_buffer_object in which to fix up
2134 * @offset: start offset in @buffer to fix up 2149 * @fixup_offset: start offset in @buffer to fix up
2135 * @last_obj: last binder_buffer_object that we fixed up in 2150 * @last_obj_offset: offset to last binder_buffer_object that we fixed
2136 * @last_min_offset: minimum fixup offset in @last_obj 2151 * @last_min_offset: minimum fixup offset in object at @last_obj_offset
2137 * 2152 *
2138 * Return: %true if a fixup in buffer @buffer at offset @offset is 2153 * Return: %true if a fixup in buffer @buffer at offset @offset is
2139 * allowed. 2154 * allowed.
@@ -2164,28 +2179,41 @@ static struct binder_buffer_object *binder_validate_ptr(struct binder_buffer *b,
2164 * C (parent = A, offset = 16) 2179 * C (parent = A, offset = 16)
2165 * D (parent = B, offset = 0) // B is not A or any of A's parents 2180 * D (parent = B, offset = 0) // B is not A or any of A's parents
2166 */ 2181 */
2167static bool binder_validate_fixup(struct binder_buffer *b, 2182static bool binder_validate_fixup(struct binder_proc *proc,
2168 binder_size_t *objects_start, 2183 struct binder_buffer *b,
2169 struct binder_buffer_object *buffer, 2184 binder_size_t objects_start_offset,
2185 binder_size_t buffer_obj_offset,
2170 binder_size_t fixup_offset, 2186 binder_size_t fixup_offset,
2171 struct binder_buffer_object *last_obj, 2187 binder_size_t last_obj_offset,
2172 binder_size_t last_min_offset) 2188 binder_size_t last_min_offset)
2173{ 2189{
2174 if (!last_obj) { 2190 if (!last_obj_offset) {
2175 /* Nothing to fix up in */ 2191 /* Nothing to fix up in */
2176 return false; 2192 return false;
2177 } 2193 }
2178 2194
2179 while (last_obj != buffer) { 2195 while (last_obj_offset != buffer_obj_offset) {
2196 unsigned long buffer_offset;
2197 struct binder_object last_object;
2198 struct binder_buffer_object *last_bbo;
2199 size_t object_size = binder_get_object(proc, b, last_obj_offset,
2200 &last_object);
2201 if (object_size != sizeof(*last_bbo))
2202 return false;
2203
2204 last_bbo = &last_object.bbo;
2180 /* 2205 /*
2181 * Safe to retrieve the parent of last_obj, since it 2206 * Safe to retrieve the parent of last_obj, since it
2182 * was already previously verified by the driver. 2207 * was already previously verified by the driver.
2183 */ 2208 */
2184 if ((last_obj->flags & BINDER_BUFFER_FLAG_HAS_PARENT) == 0) 2209 if ((last_bbo->flags & BINDER_BUFFER_FLAG_HAS_PARENT) == 0)
2185 return false; 2210 return false;
2186 last_min_offset = last_obj->parent_offset + sizeof(uintptr_t); 2211 last_min_offset = last_bbo->parent_offset + sizeof(uintptr_t);
2187 last_obj = (struct binder_buffer_object *) 2212 buffer_offset = objects_start_offset +
2188 (b->data + *(objects_start + last_obj->parent)); 2213 sizeof(binder_size_t) * last_bbo->parent,
2214 binder_alloc_copy_from_buffer(&proc->alloc, &last_obj_offset,
2215 b, buffer_offset,
2216 sizeof(last_obj_offset));
2189 } 2217 }
2190 return (fixup_offset >= last_min_offset); 2218 return (fixup_offset >= last_min_offset);
2191} 2219}
@@ -2254,6 +2282,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
2254{ 2282{
2255 binder_size_t *offp, *off_start, *off_end; 2283 binder_size_t *offp, *off_start, *off_end;
2256 int debug_id = buffer->debug_id; 2284 int debug_id = buffer->debug_id;
2285 binder_size_t off_start_offset;
2257 2286
2258 binder_debug(BINDER_DEBUG_TRANSACTION, 2287 binder_debug(BINDER_DEBUG_TRANSACTION,
2259 "%d buffer release %d, size %zd-%zd, failed at %pK\n", 2288 "%d buffer release %d, size %zd-%zd, failed at %pK\n",
@@ -2263,8 +2292,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
2263 if (buffer->target_node) 2292 if (buffer->target_node)
2264 binder_dec_node(buffer->target_node, 1, 0); 2293 binder_dec_node(buffer->target_node, 1, 0);
2265 2294
2266 off_start = (binder_size_t *)(buffer->data + 2295 off_start_offset = ALIGN(buffer->data_size, sizeof(void *));
2267 ALIGN(buffer->data_size, sizeof(void *))); 2296 off_start = (binder_size_t *)(buffer->data + off_start_offset);
2268 if (failed_at) 2297 if (failed_at)
2269 off_end = failed_at; 2298 off_end = failed_at;
2270 else 2299 else
@@ -2350,6 +2379,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
2350 case BINDER_TYPE_FDA: { 2379 case BINDER_TYPE_FDA: {
2351 struct binder_fd_array_object *fda; 2380 struct binder_fd_array_object *fda;
2352 struct binder_buffer_object *parent; 2381 struct binder_buffer_object *parent;
2382 struct binder_object ptr_object;
2353 uintptr_t parent_buffer; 2383 uintptr_t parent_buffer;
2354 u32 *fd_array; 2384 u32 *fd_array;
2355 size_t fd_index; 2385 size_t fd_index;
@@ -2365,8 +2395,10 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
2365 } 2395 }
2366 2396
2367 fda = to_binder_fd_array_object(hdr); 2397 fda = to_binder_fd_array_object(hdr);
2368 parent = binder_validate_ptr(buffer, fda->parent, 2398 parent = binder_validate_ptr(proc, buffer, &ptr_object,
2369 off_start, 2399 fda->parent,
2400 off_start_offset,
2401 NULL,
2370 offp - off_start); 2402 offp - off_start);
2371 if (!parent) { 2403 if (!parent) {
2372 pr_err("transaction release %d bad parent offset\n", 2404 pr_err("transaction release %d bad parent offset\n",
@@ -2665,9 +2697,9 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda,
2665static int binder_fixup_parent(struct binder_transaction *t, 2697static int binder_fixup_parent(struct binder_transaction *t,
2666 struct binder_thread *thread, 2698 struct binder_thread *thread,
2667 struct binder_buffer_object *bp, 2699 struct binder_buffer_object *bp,
2668 binder_size_t *off_start, 2700 binder_size_t off_start_offset,
2669 binder_size_t num_valid, 2701 binder_size_t num_valid,
2670 struct binder_buffer_object *last_fixup_obj, 2702 binder_size_t last_fixup_obj_off,
2671 binder_size_t last_fixup_min_off) 2703 binder_size_t last_fixup_min_off)
2672{ 2704{
2673 struct binder_buffer_object *parent; 2705 struct binder_buffer_object *parent;
@@ -2675,20 +2707,25 @@ static int binder_fixup_parent(struct binder_transaction *t,
2675 struct binder_buffer *b = t->buffer; 2707 struct binder_buffer *b = t->buffer;
2676 struct binder_proc *proc = thread->proc; 2708 struct binder_proc *proc = thread->proc;
2677 struct binder_proc *target_proc = t->to_proc; 2709 struct binder_proc *target_proc = t->to_proc;
2710 struct binder_object object;
2711 binder_size_t buffer_offset;
2712 binder_size_t parent_offset;
2678 2713
2679 if (!(bp->flags & BINDER_BUFFER_FLAG_HAS_PARENT)) 2714 if (!(bp->flags & BINDER_BUFFER_FLAG_HAS_PARENT))
2680 return 0; 2715 return 0;
2681 2716
2682 parent = binder_validate_ptr(b, bp->parent, off_start, num_valid); 2717 parent = binder_validate_ptr(target_proc, b, &object, bp->parent,
2718 off_start_offset, &parent_offset,
2719 num_valid);
2683 if (!parent) { 2720 if (!parent) {
2684 binder_user_error("%d:%d got transaction with invalid parent offset or type\n", 2721 binder_user_error("%d:%d got transaction with invalid parent offset or type\n",
2685 proc->pid, thread->pid); 2722 proc->pid, thread->pid);
2686 return -EINVAL; 2723 return -EINVAL;
2687 } 2724 }
2688 2725
2689 if (!binder_validate_fixup(b, off_start, 2726 if (!binder_validate_fixup(target_proc, b, off_start_offset,
2690 parent, bp->parent_offset, 2727 parent_offset, bp->parent_offset,
2691 last_fixup_obj, 2728 last_fixup_obj_off,
2692 last_fixup_min_off)) { 2729 last_fixup_min_off)) {
2693 binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", 2730 binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n",
2694 proc->pid, thread->pid); 2731 proc->pid, thread->pid);
@@ -2705,7 +2742,10 @@ static int binder_fixup_parent(struct binder_transaction *t,
2705 parent_buffer = (u8 *)((uintptr_t)parent->buffer - 2742 parent_buffer = (u8 *)((uintptr_t)parent->buffer -
2706 binder_alloc_get_user_buffer_offset( 2743 binder_alloc_get_user_buffer_offset(
2707 &target_proc->alloc)); 2744 &target_proc->alloc));
2708 *(binder_uintptr_t *)(parent_buffer + bp->parent_offset) = bp->buffer; 2745 buffer_offset = bp->parent_offset +
2746 (uintptr_t)parent_buffer - (uintptr_t)b->data;
2747 binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset,
2748 &bp->buffer, sizeof(bp->buffer));
2709 2749
2710 return 0; 2750 return 0;
2711} 2751}
@@ -2825,6 +2865,7 @@ static void binder_transaction(struct binder_proc *proc,
2825 struct binder_work *w; 2865 struct binder_work *w;
2826 struct binder_work *tcomplete; 2866 struct binder_work *tcomplete;
2827 binder_size_t *offp, *off_end, *off_start; 2867 binder_size_t *offp, *off_end, *off_start;
2868 binder_size_t off_start_offset;
2828 binder_size_t off_min; 2869 binder_size_t off_min;
2829 u8 *sg_bufp, *sg_buf_end; 2870 u8 *sg_bufp, *sg_buf_end;
2830 struct binder_proc *target_proc = NULL; 2871 struct binder_proc *target_proc = NULL;
@@ -2835,7 +2876,7 @@ static void binder_transaction(struct binder_proc *proc,
2835 uint32_t return_error = 0; 2876 uint32_t return_error = 0;
2836 uint32_t return_error_param = 0; 2877 uint32_t return_error_param = 0;
2837 uint32_t return_error_line = 0; 2878 uint32_t return_error_line = 0;
2838 struct binder_buffer_object *last_fixup_obj = NULL; 2879 binder_size_t last_fixup_obj_off = 0;
2839 binder_size_t last_fixup_min_off = 0; 2880 binder_size_t last_fixup_min_off = 0;
2840 struct binder_context *context = proc->context; 2881 struct binder_context *context = proc->context;
2841 int t_debug_id = atomic_inc_return(&binder_last_id); 2882 int t_debug_id = atomic_inc_return(&binder_last_id);
@@ -3132,8 +3173,8 @@ static void binder_transaction(struct binder_proc *proc,
3132 t->buffer->transaction = t; 3173 t->buffer->transaction = t;
3133 t->buffer->target_node = target_node; 3174 t->buffer->target_node = target_node;
3134 trace_binder_transaction_alloc_buf(t->buffer); 3175 trace_binder_transaction_alloc_buf(t->buffer);
3135 off_start = (binder_size_t *)(t->buffer->data + 3176 off_start_offset = ALIGN(tr->data_size, sizeof(void *));
3136 ALIGN(tr->data_size, sizeof(void *))); 3177 off_start = (binder_size_t *)(t->buffer->data + off_start_offset);
3137 offp = off_start; 3178 offp = off_start;
3138 3179
3139 if (binder_alloc_copy_user_to_buffer( 3180 if (binder_alloc_copy_user_to_buffer(
@@ -3266,11 +3307,15 @@ static void binder_transaction(struct binder_proc *proc,
3266 fp, sizeof(*fp)); 3307 fp, sizeof(*fp));
3267 } break; 3308 } break;
3268 case BINDER_TYPE_FDA: { 3309 case BINDER_TYPE_FDA: {
3310 struct binder_object ptr_object;
3311 binder_size_t parent_offset;
3269 struct binder_fd_array_object *fda = 3312 struct binder_fd_array_object *fda =
3270 to_binder_fd_array_object(hdr); 3313 to_binder_fd_array_object(hdr);
3271 struct binder_buffer_object *parent = 3314 struct binder_buffer_object *parent =
3272 binder_validate_ptr(t->buffer, fda->parent, 3315 binder_validate_ptr(target_proc, t->buffer,
3273 off_start, 3316 &ptr_object, fda->parent,
3317 off_start_offset,
3318 &parent_offset,
3274 offp - off_start); 3319 offp - off_start);
3275 if (!parent) { 3320 if (!parent) {
3276 binder_user_error("%d:%d got transaction with invalid parent offset or type\n", 3321 binder_user_error("%d:%d got transaction with invalid parent offset or type\n",
@@ -3280,9 +3325,11 @@ static void binder_transaction(struct binder_proc *proc,
3280 return_error_line = __LINE__; 3325 return_error_line = __LINE__;
3281 goto err_bad_parent; 3326 goto err_bad_parent;
3282 } 3327 }
3283 if (!binder_validate_fixup(t->buffer, off_start, 3328 if (!binder_validate_fixup(target_proc, t->buffer,
3284 parent, fda->parent_offset, 3329 off_start_offset,
3285 last_fixup_obj, 3330 parent_offset,
3331 fda->parent_offset,
3332 last_fixup_obj_off,
3286 last_fixup_min_off)) { 3333 last_fixup_min_off)) {
3287 binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", 3334 binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n",
3288 proc->pid, thread->pid); 3335 proc->pid, thread->pid);
@@ -3299,7 +3346,7 @@ static void binder_transaction(struct binder_proc *proc,
3299 return_error_line = __LINE__; 3346 return_error_line = __LINE__;
3300 goto err_translate_failed; 3347 goto err_translate_failed;
3301 } 3348 }
3302 last_fixup_obj = parent; 3349 last_fixup_obj_off = parent_offset;
3303 last_fixup_min_off = 3350 last_fixup_min_off =
3304 fda->parent_offset + sizeof(u32) * fda->num_fds; 3351 fda->parent_offset + sizeof(u32) * fda->num_fds;
3305 } break; 3352 } break;
@@ -3338,9 +3385,10 @@ static void binder_transaction(struct binder_proc *proc,
3338 &target_proc->alloc); 3385 &target_proc->alloc);
3339 sg_bufp += ALIGN(bp->length, sizeof(u64)); 3386 sg_bufp += ALIGN(bp->length, sizeof(u64));
3340 3387
3341 ret = binder_fixup_parent(t, thread, bp, off_start, 3388 ret = binder_fixup_parent(t, thread, bp,
3389 off_start_offset,
3342 offp - off_start, 3390 offp - off_start,
3343 last_fixup_obj, 3391 last_fixup_obj_off,
3344 last_fixup_min_off); 3392 last_fixup_min_off);
3345 if (ret < 0) { 3393 if (ret < 0) {
3346 return_error = BR_FAILED_REPLY; 3394 return_error = BR_FAILED_REPLY;
@@ -3351,7 +3399,7 @@ static void binder_transaction(struct binder_proc *proc,
3351 binder_alloc_copy_to_buffer(&target_proc->alloc, 3399 binder_alloc_copy_to_buffer(&target_proc->alloc,
3352 t->buffer, object_offset, 3400 t->buffer, object_offset,
3353 bp, sizeof(*bp)); 3401 bp, sizeof(*bp));
3354 last_fixup_obj = t->buffer->data + object_offset; 3402 last_fixup_obj_off = object_offset;
3355 last_fixup_min_off = 0; 3403 last_fixup_min_off = 0;
3356 } break; 3404 } break;
3357 default: 3405 default: