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

binder: print warnings when detecting oneway spamming.

The most common cause of the binder transaction buffer filling up is a
client rapidly firing oneway transactions into a process, before it has
a chance to handle them. Yet the root cause of this is often hard to
debug, because either the system or the app will stop, and by that time
binder debug information we dump in bugreports is no longer relevant.

This change warns as soon as a process dips below 80% of its oneway
space (less than 100kB available in the configuration), when any one
process is responsible for either more than 50 transactions, or more
than 50% of the oneway space.

Signed-off-by: Martijn Coenen <maco@android.com>
Acked-by: Todd Kjos <tkjos@google.com>
Link: https://lore.kernel.org/r/20200821122544.1277051-1-maco@android.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Martijn Coenen and committed by
Greg Kroah-Hartman
261e7818 89320020

+58 -6
+1 -1
drivers/android/binder.c
··· 3134 3134 3135 3135 t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, 3136 3136 tr->offsets_size, extra_buffers_size, 3137 - !reply && (t->flags & TF_ONE_WAY)); 3137 + !reply && (t->flags & TF_ONE_WAY), current->tgid); 3138 3138 if (IS_ERR(t->buffer)) { 3139 3139 /* 3140 3140 * -ESRCH indicates VMA cleared. The target is dying.
+52 -3
drivers/android/binder_alloc.c
··· 338 338 return vma; 339 339 } 340 340 341 + static void debug_low_async_space_locked(struct binder_alloc *alloc, int pid) 342 + { 343 + /* 344 + * Find the amount and size of buffers allocated by the current caller; 345 + * The idea is that once we cross the threshold, whoever is responsible 346 + * for the low async space is likely to try to send another async txn, 347 + * and at some point we'll catch them in the act. This is more efficient 348 + * than keeping a map per pid. 349 + */ 350 + struct rb_node *n = alloc->free_buffers.rb_node; 351 + struct binder_buffer *buffer; 352 + size_t total_alloc_size = 0; 353 + size_t num_buffers = 0; 354 + 355 + for (n = rb_first(&alloc->allocated_buffers); n != NULL; 356 + n = rb_next(n)) { 357 + buffer = rb_entry(n, struct binder_buffer, rb_node); 358 + if (buffer->pid != pid) 359 + continue; 360 + if (!buffer->async_transaction) 361 + continue; 362 + total_alloc_size += binder_alloc_buffer_size(alloc, buffer) 363 + + sizeof(struct binder_buffer); 364 + num_buffers++; 365 + } 366 + 367 + /* 368 + * Warn if this pid has more than 50 transactions, or more than 50% of 369 + * async space (which is 25% of total buffer size). 370 + */ 371 + if (num_buffers > 50 || total_alloc_size > alloc->buffer_size / 4) { 372 + binder_alloc_debug(BINDER_DEBUG_USER_ERROR, 373 + "%d: pid %d spamming oneway? %zd buffers allocated for a total size of %zd\n", 374 + alloc->pid, pid, num_buffers, total_alloc_size); 375 + } 376 + } 377 + 341 378 static struct binder_buffer *binder_alloc_new_buf_locked( 342 379 struct binder_alloc *alloc, 343 380 size_t data_size, 344 381 size_t offsets_size, 345 382 size_t extra_buffers_size, 346 - int is_async) 383 + int is_async, 384 + int pid) 347 385 { 348 386 struct rb_node *n = alloc->free_buffers.rb_node; 349 387 struct binder_buffer *buffer; ··· 524 486 buffer->offsets_size = offsets_size; 525 487 buffer->async_transaction = is_async; 526 488 buffer->extra_buffers_size = extra_buffers_size; 489 + buffer->pid = pid; 527 490 if (is_async) { 528 491 alloc->free_async_space -= size + sizeof(struct binder_buffer); 529 492 binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, 530 493 "%d: binder_alloc_buf size %zd async free %zd\n", 531 494 alloc->pid, size, alloc->free_async_space); 495 + if (alloc->free_async_space < alloc->buffer_size / 10) { 496 + /* 497 + * Start detecting spammers once we have less than 20% 498 + * of async space left (which is less than 10% of total 499 + * buffer size). 500 + */ 501 + debug_low_async_space_locked(alloc, pid); 502 + } 532 503 } 533 504 return buffer; 534 505 ··· 555 508 * @offsets_size: user specified buffer offset 556 509 * @extra_buffers_size: size of extra space for meta-data (eg, security context) 557 510 * @is_async: buffer for async transaction 511 + * @pid: pid to attribute allocation to (used for debugging) 558 512 * 559 513 * Allocate a new buffer given the requested sizes. Returns 560 514 * the kernel version of the buffer pointer. The size allocated ··· 568 520 size_t data_size, 569 521 size_t offsets_size, 570 522 size_t extra_buffers_size, 571 - int is_async) 523 + int is_async, 524 + int pid) 572 525 { 573 526 struct binder_buffer *buffer; 574 527 575 528 mutex_lock(&alloc->mutex); 576 529 buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size, 577 - extra_buffers_size, is_async); 530 + extra_buffers_size, is_async, pid); 578 531 mutex_unlock(&alloc->mutex); 579 532 return buffer; 580 533 }
+4 -1
drivers/android/binder_alloc.h
··· 32 32 * @offsets_size: size of array of offsets 33 33 * @extra_buffers_size: size of space for other objects (like sg lists) 34 34 * @user_data: user pointer to base of buffer space 35 + * @pid: pid to attribute the buffer to (caller) 35 36 * 36 37 * Bookkeeping structure for binder transaction buffers 37 38 */ ··· 52 51 size_t offsets_size; 53 52 size_t extra_buffers_size; 54 53 void __user *user_data; 54 + int pid; 55 55 }; 56 56 57 57 /** ··· 119 117 size_t data_size, 120 118 size_t offsets_size, 121 119 size_t extra_buffers_size, 122 - int is_async); 120 + int is_async, 121 + int pid); 123 122 extern void binder_alloc_init(struct binder_alloc *alloc); 124 123 extern int binder_alloc_shrinker_init(void); 125 124 extern void binder_alloc_vma_close(struct binder_alloc *alloc);
+1 -1
drivers/android/binder_alloc_selftest.c
··· 119 119 int i; 120 120 121 121 for (i = 0; i < BUFFER_NUM; i++) { 122 - buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0); 122 + buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0, 0); 123 123 if (IS_ERR(buffers[i]) || 124 124 !check_buffer_pages_allocated(alloc, buffers[i], 125 125 sizes[i])) {