Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

binder: return errors from buffer copy functions

The buffer copy functions assumed the caller would ensure
correct alignment and that the memory to be copied was
completely within the binder buffer. There have been
a few cases discovered by syzkallar where a malformed
transaction created by a user could violated the
assumptions and resulted in a BUG_ON.

The fix is to remove the BUG_ON and always return the
error to be handled appropriately by the caller.

Acked-by: Martijn Coenen <maco@android.com>
Reported-by: syzbot+3ae18325f96190606754@syzkaller.appspotmail.com
Fixes: bde4a19fc04f ("binder: use userspace pointer as base of buffer space")
Suggested-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Todd Kjos <tkjos@google.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Todd Kjos and committed by
Greg Kroah-Hartman
bb4a2e48 25c7eabe

+124 -91
+91 -60
drivers/android/binder.c
··· 2059 2059 2060 2060 read_size = min_t(size_t, sizeof(*object), buffer->data_size - offset); 2061 2061 if (offset > buffer->data_size || read_size < sizeof(*hdr) || 2062 - !IS_ALIGNED(offset, sizeof(u32))) 2062 + binder_alloc_copy_from_buffer(&proc->alloc, object, buffer, 2063 + offset, read_size)) 2063 2064 return 0; 2064 - binder_alloc_copy_from_buffer(&proc->alloc, object, buffer, 2065 - offset, read_size); 2066 2065 2067 2066 /* Ok, now see if we read a complete object. */ 2068 2067 hdr = &object->hdr; ··· 2130 2131 return NULL; 2131 2132 2132 2133 buffer_offset = start_offset + sizeof(binder_size_t) * index; 2133 - binder_alloc_copy_from_buffer(&proc->alloc, &object_offset, 2134 - b, buffer_offset, sizeof(object_offset)); 2134 + if (binder_alloc_copy_from_buffer(&proc->alloc, &object_offset, 2135 + b, buffer_offset, 2136 + sizeof(object_offset))) 2137 + return NULL; 2135 2138 object_size = binder_get_object(proc, b, object_offset, object); 2136 2139 if (!object_size || object->hdr.type != BINDER_TYPE_PTR) 2137 2140 return NULL; ··· 2213 2212 return false; 2214 2213 last_min_offset = last_bbo->parent_offset + sizeof(uintptr_t); 2215 2214 buffer_offset = objects_start_offset + 2216 - sizeof(binder_size_t) * last_bbo->parent, 2217 - binder_alloc_copy_from_buffer(&proc->alloc, &last_obj_offset, 2218 - b, buffer_offset, 2219 - sizeof(last_obj_offset)); 2215 + sizeof(binder_size_t) * last_bbo->parent; 2216 + if (binder_alloc_copy_from_buffer(&proc->alloc, 2217 + &last_obj_offset, 2218 + b, buffer_offset, 2219 + sizeof(last_obj_offset))) 2220 + return false; 2220 2221 } 2221 2222 return (fixup_offset >= last_min_offset); 2222 2223 } ··· 2304 2301 for (buffer_offset = off_start_offset; buffer_offset < off_end_offset; 2305 2302 buffer_offset += sizeof(binder_size_t)) { 2306 2303 struct binder_object_header *hdr; 2307 - size_t object_size; 2304 + size_t object_size = 0; 2308 2305 struct binder_object object; 2309 2306 binder_size_t object_offset; 2310 2307 2311 - binder_alloc_copy_from_buffer(&proc->alloc, &object_offset, 2312 - buffer, buffer_offset, 2313 - sizeof(object_offset)); 2314 - object_size = binder_get_object(proc, buffer, 2315 - object_offset, &object); 2308 + if (!binder_alloc_copy_from_buffer(&proc->alloc, &object_offset, 2309 + buffer, buffer_offset, 2310 + sizeof(object_offset))) 2311 + object_size = binder_get_object(proc, buffer, 2312 + object_offset, &object); 2316 2313 if (object_size == 0) { 2317 2314 pr_err("transaction release %d bad object at offset %lld, size %zd\n", 2318 2315 debug_id, (u64)object_offset, buffer->data_size); ··· 2435 2432 for (fd_index = 0; fd_index < fda->num_fds; 2436 2433 fd_index++) { 2437 2434 u32 fd; 2435 + int err; 2438 2436 binder_size_t offset = fda_offset + 2439 2437 fd_index * sizeof(fd); 2440 2438 2441 - binder_alloc_copy_from_buffer(&proc->alloc, 2442 - &fd, 2443 - buffer, 2444 - offset, 2445 - sizeof(fd)); 2446 - binder_deferred_fd_close(fd); 2439 + err = binder_alloc_copy_from_buffer( 2440 + &proc->alloc, &fd, buffer, 2441 + offset, sizeof(fd)); 2442 + WARN_ON(err); 2443 + if (!err) 2444 + binder_deferred_fd_close(fd); 2447 2445 } 2448 2446 } break; 2449 2447 default: ··· 2687 2683 int ret; 2688 2684 binder_size_t offset = fda_offset + fdi * sizeof(fd); 2689 2685 2690 - binder_alloc_copy_from_buffer(&target_proc->alloc, 2691 - &fd, t->buffer, 2692 - offset, sizeof(fd)); 2693 - ret = binder_translate_fd(fd, offset, t, thread, 2694 - in_reply_to); 2686 + ret = binder_alloc_copy_from_buffer(&target_proc->alloc, 2687 + &fd, t->buffer, 2688 + offset, sizeof(fd)); 2689 + if (!ret) 2690 + ret = binder_translate_fd(fd, offset, t, thread, 2691 + in_reply_to); 2695 2692 if (ret < 0) 2696 2693 return ret; 2697 2694 } ··· 2745 2740 } 2746 2741 buffer_offset = bp->parent_offset + 2747 2742 (uintptr_t)parent->buffer - (uintptr_t)b->user_data; 2748 - binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset, 2749 - &bp->buffer, sizeof(bp->buffer)); 2743 + if (binder_alloc_copy_to_buffer(&target_proc->alloc, b, buffer_offset, 2744 + &bp->buffer, sizeof(bp->buffer))) { 2745 + binder_user_error("%d:%d got transaction with invalid parent offset\n", 2746 + proc->pid, thread->pid); 2747 + return -EINVAL; 2748 + } 2750 2749 2751 2750 return 0; 2752 2751 } ··· 3169 3160 goto err_binder_alloc_buf_failed; 3170 3161 } 3171 3162 if (secctx) { 3163 + int err; 3172 3164 size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) + 3173 3165 ALIGN(tr->offsets_size, sizeof(void *)) + 3174 3166 ALIGN(extra_buffers_size, sizeof(void *)) - 3175 3167 ALIGN(secctx_sz, sizeof(u64)); 3176 3168 3177 3169 t->security_ctx = (uintptr_t)t->buffer->user_data + buf_offset; 3178 - binder_alloc_copy_to_buffer(&target_proc->alloc, 3179 - t->buffer, buf_offset, 3180 - secctx, secctx_sz); 3170 + err = binder_alloc_copy_to_buffer(&target_proc->alloc, 3171 + t->buffer, buf_offset, 3172 + secctx, secctx_sz); 3173 + if (err) { 3174 + t->security_ctx = 0; 3175 + WARN_ON(1); 3176 + } 3181 3177 security_release_secctx(secctx, secctx_sz); 3182 3178 secctx = NULL; 3183 3179 } ··· 3248 3234 struct binder_object object; 3249 3235 binder_size_t object_offset; 3250 3236 3251 - binder_alloc_copy_from_buffer(&target_proc->alloc, 3252 - &object_offset, 3253 - t->buffer, 3254 - buffer_offset, 3255 - sizeof(object_offset)); 3237 + if (binder_alloc_copy_from_buffer(&target_proc->alloc, 3238 + &object_offset, 3239 + t->buffer, 3240 + buffer_offset, 3241 + sizeof(object_offset))) { 3242 + return_error = BR_FAILED_REPLY; 3243 + return_error_param = -EINVAL; 3244 + return_error_line = __LINE__; 3245 + goto err_bad_offset; 3246 + } 3256 3247 object_size = binder_get_object(target_proc, t->buffer, 3257 3248 object_offset, &object); 3258 3249 if (object_size == 0 || object_offset < off_min) { ··· 3281 3262 3282 3263 fp = to_flat_binder_object(hdr); 3283 3264 ret = binder_translate_binder(fp, t, thread); 3284 - if (ret < 0) { 3265 + 3266 + if (ret < 0 || 3267 + binder_alloc_copy_to_buffer(&target_proc->alloc, 3268 + t->buffer, 3269 + object_offset, 3270 + fp, sizeof(*fp))) { 3285 3271 return_error = BR_FAILED_REPLY; 3286 3272 return_error_param = ret; 3287 3273 return_error_line = __LINE__; 3288 3274 goto err_translate_failed; 3289 3275 } 3290 - binder_alloc_copy_to_buffer(&target_proc->alloc, 3291 - t->buffer, object_offset, 3292 - fp, sizeof(*fp)); 3293 3276 } break; 3294 3277 case BINDER_TYPE_HANDLE: 3295 3278 case BINDER_TYPE_WEAK_HANDLE: { ··· 3299 3278 3300 3279 fp = to_flat_binder_object(hdr); 3301 3280 ret = binder_translate_handle(fp, t, thread); 3302 - if (ret < 0) { 3281 + if (ret < 0 || 3282 + binder_alloc_copy_to_buffer(&target_proc->alloc, 3283 + t->buffer, 3284 + object_offset, 3285 + fp, sizeof(*fp))) { 3303 3286 return_error = BR_FAILED_REPLY; 3304 3287 return_error_param = ret; 3305 3288 return_error_line = __LINE__; 3306 3289 goto err_translate_failed; 3307 3290 } 3308 - binder_alloc_copy_to_buffer(&target_proc->alloc, 3309 - t->buffer, object_offset, 3310 - fp, sizeof(*fp)); 3311 3291 } break; 3312 3292 3313 3293 case BINDER_TYPE_FD: { ··· 3318 3296 int ret = binder_translate_fd(fp->fd, fd_offset, t, 3319 3297 thread, in_reply_to); 3320 3298 3321 - if (ret < 0) { 3299 + fp->pad_binder = 0; 3300 + if (ret < 0 || 3301 + binder_alloc_copy_to_buffer(&target_proc->alloc, 3302 + t->buffer, 3303 + object_offset, 3304 + fp, sizeof(*fp))) { 3322 3305 return_error = BR_FAILED_REPLY; 3323 3306 return_error_param = ret; 3324 3307 return_error_line = __LINE__; 3325 3308 goto err_translate_failed; 3326 3309 } 3327 - fp->pad_binder = 0; 3328 - binder_alloc_copy_to_buffer(&target_proc->alloc, 3329 - t->buffer, object_offset, 3330 - fp, sizeof(*fp)); 3331 3310 } break; 3332 3311 case BINDER_TYPE_FDA: { 3333 3312 struct binder_object ptr_object; ··· 3416 3393 num_valid, 3417 3394 last_fixup_obj_off, 3418 3395 last_fixup_min_off); 3419 - if (ret < 0) { 3396 + if (ret < 0 || 3397 + binder_alloc_copy_to_buffer(&target_proc->alloc, 3398 + t->buffer, 3399 + object_offset, 3400 + bp, sizeof(*bp))) { 3420 3401 return_error = BR_FAILED_REPLY; 3421 3402 return_error_param = ret; 3422 3403 return_error_line = __LINE__; 3423 3404 goto err_translate_failed; 3424 3405 } 3425 - binder_alloc_copy_to_buffer(&target_proc->alloc, 3426 - t->buffer, object_offset, 3427 - bp, sizeof(*bp)); 3428 3406 last_fixup_obj_off = object_offset; 3429 3407 last_fixup_min_off = 0; 3430 3408 } break; ··· 4164 4140 trace_binder_transaction_fd_recv(t, fd, fixup->offset); 4165 4141 fd_install(fd, fixup->file); 4166 4142 fixup->file = NULL; 4167 - binder_alloc_copy_to_buffer(&proc->alloc, t->buffer, 4168 - fixup->offset, &fd, 4169 - sizeof(u32)); 4143 + if (binder_alloc_copy_to_buffer(&proc->alloc, t->buffer, 4144 + fixup->offset, &fd, 4145 + sizeof(u32))) { 4146 + ret = -EINVAL; 4147 + break; 4148 + } 4170 4149 } 4171 4150 list_for_each_entry_safe(fixup, tmp, &t->fd_fixups, fixup_entry) { 4172 4151 if (fixup->file) { 4173 4152 fput(fixup->file); 4174 4153 } else if (ret) { 4175 4154 u32 fd; 4155 + int err; 4176 4156 4177 - binder_alloc_copy_from_buffer(&proc->alloc, &fd, 4178 - t->buffer, fixup->offset, 4179 - sizeof(fd)); 4180 - binder_deferred_fd_close(fd); 4157 + err = binder_alloc_copy_from_buffer(&proc->alloc, &fd, 4158 + t->buffer, 4159 + fixup->offset, 4160 + sizeof(fd)); 4161 + WARN_ON(err); 4162 + if (!err) 4163 + binder_deferred_fd_close(fd); 4181 4164 } 4182 4165 list_del(&fixup->fixup_entry); 4183 4166 kfree(fixup);
+23 -21
drivers/android/binder_alloc.c
··· 1119 1119 return 0; 1120 1120 } 1121 1121 1122 - static void binder_alloc_do_buffer_copy(struct binder_alloc *alloc, 1123 - bool to_buffer, 1124 - struct binder_buffer *buffer, 1125 - binder_size_t buffer_offset, 1126 - void *ptr, 1127 - size_t bytes) 1122 + static int binder_alloc_do_buffer_copy(struct binder_alloc *alloc, 1123 + bool to_buffer, 1124 + struct binder_buffer *buffer, 1125 + binder_size_t buffer_offset, 1126 + void *ptr, 1127 + size_t bytes) 1128 1128 { 1129 1129 /* All copies must be 32-bit aligned and 32-bit size */ 1130 - BUG_ON(!check_buffer(alloc, buffer, buffer_offset, bytes)); 1130 + if (!check_buffer(alloc, buffer, buffer_offset, bytes)) 1131 + return -EINVAL; 1131 1132 1132 1133 while (bytes) { 1133 1134 unsigned long size; ··· 1156 1155 ptr = ptr + size; 1157 1156 buffer_offset += size; 1158 1157 } 1158 + return 0; 1159 1159 } 1160 1160 1161 - void binder_alloc_copy_to_buffer(struct binder_alloc *alloc, 1162 - struct binder_buffer *buffer, 1163 - binder_size_t buffer_offset, 1164 - void *src, 1165 - size_t bytes) 1161 + int binder_alloc_copy_to_buffer(struct binder_alloc *alloc, 1162 + struct binder_buffer *buffer, 1163 + binder_size_t buffer_offset, 1164 + void *src, 1165 + size_t bytes) 1166 1166 { 1167 - binder_alloc_do_buffer_copy(alloc, true, buffer, buffer_offset, 1168 - src, bytes); 1167 + return binder_alloc_do_buffer_copy(alloc, true, buffer, buffer_offset, 1168 + src, bytes); 1169 1169 } 1170 1170 1171 - void binder_alloc_copy_from_buffer(struct binder_alloc *alloc, 1172 - void *dest, 1173 - struct binder_buffer *buffer, 1174 - binder_size_t buffer_offset, 1175 - size_t bytes) 1171 + int binder_alloc_copy_from_buffer(struct binder_alloc *alloc, 1172 + void *dest, 1173 + struct binder_buffer *buffer, 1174 + binder_size_t buffer_offset, 1175 + size_t bytes) 1176 1176 { 1177 - binder_alloc_do_buffer_copy(alloc, false, buffer, buffer_offset, 1178 - dest, bytes); 1177 + return binder_alloc_do_buffer_copy(alloc, false, buffer, buffer_offset, 1178 + dest, bytes); 1179 1179 } 1180 1180
+10 -10
drivers/android/binder_alloc.h
··· 159 159 const void __user *from, 160 160 size_t bytes); 161 161 162 - void binder_alloc_copy_to_buffer(struct binder_alloc *alloc, 163 - struct binder_buffer *buffer, 164 - binder_size_t buffer_offset, 165 - void *src, 166 - size_t bytes); 162 + int binder_alloc_copy_to_buffer(struct binder_alloc *alloc, 163 + struct binder_buffer *buffer, 164 + binder_size_t buffer_offset, 165 + void *src, 166 + size_t bytes); 167 167 168 - void binder_alloc_copy_from_buffer(struct binder_alloc *alloc, 169 - void *dest, 170 - struct binder_buffer *buffer, 171 - binder_size_t buffer_offset, 172 - size_t bytes); 168 + int binder_alloc_copy_from_buffer(struct binder_alloc *alloc, 169 + void *dest, 170 + struct binder_buffer *buffer, 171 + binder_size_t buffer_offset, 172 + size_t bytes); 173 173 174 174 #endif /* _LINUX_BINDER_ALLOC_H */ 175 175