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

Configure Feed

Select the types of activity you want to include in your feed.

binder: Create safe versions of binder log files

Binder defines several seq_files that can be accessed via debugfs or
binderfs. Some of these files (e.g., 'state' and 'transactions')
contain more granular information about binder's internal state that
is helpful for debugging, but they also leak userspace address data
through user-defined 'cookie' or 'ptr' values. Consequently, access
to these files must be heavily restricted.

Add two new files, 'state_hashed' and 'transactions_hashed', that
reproduce the information in the original files but use the kernel's
raw pointer obfuscation to hash any potential user addresses. This
approach allows systems to grant broader access to the new files
without having to change the security policy around the existing ones.

In practice, userspace populates these fields with user addresses, but
within the driver, these values only serve as unique identifiers for
their associated binder objects. Consequently, binder logs can
obfuscate these values and still retain meaning. While this strategy
prevents leaking information about the userspace memory layout in the
existing log files, it also decouples log messages about binder
objects from their user-defined identifiers.

Acked-by: Carlos Llamas <cmllamas@google.com>
Tested-by: Carlos Llamas <cmllamas@google.com>
Signed-off-by: "Tiffany Y. Yang" <ynaffit@google.com>
Link: https://lore.kernel.org/r/20250510013435.1520671-7-ynaffit@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Tiffany Y. Yang and committed by
Greg Kroah-Hartman
57483a36 91f1bbaa

+79 -27
+79 -27
drivers/android/binder.c
··· 6377 6377 struct binder_proc *proc, 6378 6378 const char *prefix, 6379 6379 const char *transaction_prefix, 6380 - struct binder_work *w) 6380 + struct binder_work *w, bool hash_ptrs) 6381 6381 { 6382 6382 struct binder_node *node; 6383 6383 struct binder_transaction *t; ··· 6400 6400 break; 6401 6401 case BINDER_WORK_NODE: 6402 6402 node = container_of(w, struct binder_node, work); 6403 - seq_printf(m, "%snode work %d: u%016llx c%016llx\n", 6404 - prefix, node->debug_id, 6405 - (u64)node->ptr, (u64)node->cookie); 6403 + if (hash_ptrs) 6404 + seq_printf(m, "%snode work %d: u%p c%p\n", 6405 + prefix, node->debug_id, 6406 + (void *)(long)node->ptr, 6407 + (void *)(long)node->cookie); 6408 + else 6409 + seq_printf(m, "%snode work %d: u%016llx c%016llx\n", 6410 + prefix, node->debug_id, 6411 + (u64)node->ptr, (u64)node->cookie); 6406 6412 break; 6407 6413 case BINDER_WORK_DEAD_BINDER: 6408 6414 seq_printf(m, "%shas dead binder\n", prefix); ··· 6433 6427 6434 6428 static void print_binder_thread_ilocked(struct seq_file *m, 6435 6429 struct binder_thread *thread, 6436 - bool print_always) 6430 + bool print_always, bool hash_ptrs) 6437 6431 { 6438 6432 struct binder_transaction *t; 6439 6433 struct binder_work *w; ··· 6463 6457 } 6464 6458 list_for_each_entry(w, &thread->todo, entry) { 6465 6459 print_binder_work_ilocked(m, thread->proc, " ", 6466 - " pending transaction", w); 6460 + " pending transaction", 6461 + w, hash_ptrs); 6467 6462 } 6468 6463 if (!print_always && m->count == header_pos) 6469 6464 m->count = start_pos; 6470 6465 } 6471 6466 6472 6467 static void print_binder_node_nilocked(struct seq_file *m, 6473 - struct binder_node *node) 6468 + struct binder_node *node, 6469 + bool hash_ptrs) 6474 6470 { 6475 6471 struct binder_ref *ref; 6476 6472 struct binder_work *w; ··· 6480 6472 6481 6473 count = hlist_count_nodes(&node->refs); 6482 6474 6483 - seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d tr %d", 6484 - node->debug_id, (u64)node->ptr, (u64)node->cookie, 6475 + if (hash_ptrs) 6476 + seq_printf(m, " node %d: u%p c%p", node->debug_id, 6477 + (void *)(long)node->ptr, (void *)(long)node->cookie); 6478 + else 6479 + seq_printf(m, " node %d: u%016llx c%016llx", node->debug_id, 6480 + (u64)node->ptr, (u64)node->cookie); 6481 + seq_printf(m, " hs %d hw %d ls %d lw %d is %d iw %d tr %d", 6485 6482 node->has_strong_ref, node->has_weak_ref, 6486 6483 node->local_strong_refs, node->local_weak_refs, 6487 6484 node->internal_strong_refs, count, node->tmp_refs); ··· 6499 6486 if (node->proc) { 6500 6487 list_for_each_entry(w, &node->async_todo, entry) 6501 6488 print_binder_work_ilocked(m, node->proc, " ", 6502 - " pending async transaction", w); 6489 + " pending async transaction", 6490 + w, hash_ptrs); 6503 6491 } 6504 6492 } 6505 6493 ··· 6522 6508 * @proc: struct binder_proc we hold the inner_proc_lock to (if any) 6523 6509 * @node: struct binder_node to print fields of 6524 6510 * @prev_node: struct binder_node we hold a temporary reference to (if any) 6511 + * @hash_ptrs: whether to hash @node's binder_uintptr_t fields 6525 6512 * 6526 6513 * Helper function to handle synchronization around printing a struct 6527 6514 * binder_node while iterating through @proc->nodes or the dead nodes list. ··· 6535 6520 static struct binder_node * 6536 6521 print_next_binder_node_ilocked(struct seq_file *m, struct binder_proc *proc, 6537 6522 struct binder_node *node, 6538 - struct binder_node *prev_node) 6523 + struct binder_node *prev_node, bool hash_ptrs) 6539 6524 { 6540 6525 /* 6541 6526 * Take a temporary reference on the node so that isn't freed while ··· 6553 6538 if (prev_node) 6554 6539 binder_put_node(prev_node); 6555 6540 binder_node_inner_lock(node); 6556 - print_binder_node_nilocked(m, node); 6541 + print_binder_node_nilocked(m, node, hash_ptrs); 6557 6542 binder_node_inner_unlock(node); 6558 6543 if (proc) 6559 6544 binder_inner_proc_lock(proc); ··· 6563 6548 } 6564 6549 6565 6550 static void print_binder_proc(struct seq_file *m, struct binder_proc *proc, 6566 - bool print_all) 6551 + bool print_all, bool hash_ptrs) 6567 6552 { 6568 6553 struct binder_work *w; 6569 6554 struct rb_node *n; ··· 6578 6563 binder_inner_proc_lock(proc); 6579 6564 for (n = rb_first(&proc->threads); n; n = rb_next(n)) 6580 6565 print_binder_thread_ilocked(m, rb_entry(n, struct binder_thread, 6581 - rb_node), print_all); 6566 + rb_node), print_all, hash_ptrs); 6582 6567 6583 6568 for (n = rb_first(&proc->nodes); n; n = rb_next(n)) { 6584 6569 struct binder_node *node = rb_entry(n, struct binder_node, ··· 6587 6572 continue; 6588 6573 6589 6574 last_node = print_next_binder_node_ilocked(m, proc, node, 6590 - last_node); 6575 + last_node, 6576 + hash_ptrs); 6591 6577 } 6592 6578 binder_inner_proc_unlock(proc); 6593 6579 if (last_node) ··· 6606 6590 binder_inner_proc_lock(proc); 6607 6591 list_for_each_entry(w, &proc->todo, entry) 6608 6592 print_binder_work_ilocked(m, proc, " ", 6609 - " pending transaction", w); 6593 + " pending transaction", w, 6594 + hash_ptrs); 6610 6595 list_for_each_entry(w, &proc->delivered_death, entry) { 6611 6596 seq_puts(m, " has delivered dead binder\n"); 6612 6597 break; ··· 6789 6772 print_binder_stats(m, " ", &proc->stats); 6790 6773 } 6791 6774 6792 - static int state_show(struct seq_file *m, void *unused) 6775 + static void print_binder_state(struct seq_file *m, bool hash_ptrs) 6793 6776 { 6794 6777 struct binder_proc *proc; 6795 6778 struct binder_node *node; ··· 6802 6785 seq_puts(m, "dead nodes:\n"); 6803 6786 hlist_for_each_entry(node, &binder_dead_nodes, dead_node) 6804 6787 last_node = print_next_binder_node_ilocked(m, NULL, node, 6805 - last_node); 6788 + last_node, 6789 + hash_ptrs); 6806 6790 spin_unlock(&binder_dead_nodes_lock); 6807 6791 if (last_node) 6808 6792 binder_put_node(last_node); 6809 6793 6810 6794 mutex_lock(&binder_procs_lock); 6811 6795 hlist_for_each_entry(proc, &binder_procs, proc_node) 6812 - print_binder_proc(m, proc, true); 6796 + print_binder_proc(m, proc, true, hash_ptrs); 6813 6797 mutex_unlock(&binder_procs_lock); 6798 + } 6814 6799 6800 + static void print_binder_transactions(struct seq_file *m, bool hash_ptrs) 6801 + { 6802 + struct binder_proc *proc; 6803 + 6804 + seq_puts(m, "binder transactions:\n"); 6805 + mutex_lock(&binder_procs_lock); 6806 + hlist_for_each_entry(proc, &binder_procs, proc_node) 6807 + print_binder_proc(m, proc, false, hash_ptrs); 6808 + mutex_unlock(&binder_procs_lock); 6809 + } 6810 + 6811 + static int state_show(struct seq_file *m, void *unused) 6812 + { 6813 + print_binder_state(m, false); 6814 + return 0; 6815 + } 6816 + 6817 + static int state_hashed_show(struct seq_file *m, void *unused) 6818 + { 6819 + print_binder_state(m, true); 6815 6820 return 0; 6816 6821 } 6817 6822 ··· 6855 6816 6856 6817 static int transactions_show(struct seq_file *m, void *unused) 6857 6818 { 6858 - struct binder_proc *proc; 6819 + print_binder_transactions(m, false); 6820 + return 0; 6821 + } 6859 6822 6860 - seq_puts(m, "binder transactions:\n"); 6861 - mutex_lock(&binder_procs_lock); 6862 - hlist_for_each_entry(proc, &binder_procs, proc_node) 6863 - print_binder_proc(m, proc, false); 6864 - mutex_unlock(&binder_procs_lock); 6865 - 6823 + static int transactions_hashed_show(struct seq_file *m, void *unused) 6824 + { 6825 + print_binder_transactions(m, true); 6866 6826 return 0; 6867 6827 } 6868 6828 ··· 6874 6836 hlist_for_each_entry(itr, &binder_procs, proc_node) { 6875 6837 if (itr->pid == pid) { 6876 6838 seq_puts(m, "binder proc state:\n"); 6877 - print_binder_proc(m, itr, true); 6839 + print_binder_proc(m, itr, true, false); 6878 6840 } 6879 6841 } 6880 6842 mutex_unlock(&binder_procs_lock); ··· 6941 6903 }; 6942 6904 6943 6905 DEFINE_SHOW_ATTRIBUTE(state); 6906 + DEFINE_SHOW_ATTRIBUTE(state_hashed); 6944 6907 DEFINE_SHOW_ATTRIBUTE(stats); 6945 6908 DEFINE_SHOW_ATTRIBUTE(transactions); 6909 + DEFINE_SHOW_ATTRIBUTE(transactions_hashed); 6946 6910 DEFINE_SHOW_ATTRIBUTE(transaction_log); 6947 6911 6948 6912 const struct binder_debugfs_entry binder_debugfs_entries[] = { ··· 6952 6912 .name = "state", 6953 6913 .mode = 0444, 6954 6914 .fops = &state_fops, 6915 + .data = NULL, 6916 + }, 6917 + { 6918 + .name = "state_hashed", 6919 + .mode = 0444, 6920 + .fops = &state_hashed_fops, 6955 6921 .data = NULL, 6956 6922 }, 6957 6923 { ··· 6970 6924 .name = "transactions", 6971 6925 .mode = 0444, 6972 6926 .fops = &transactions_fops, 6927 + .data = NULL, 6928 + }, 6929 + { 6930 + .name = "transactions_hashed", 6931 + .mode = 0444, 6932 + .fops = &transactions_hashed_fops, 6973 6933 .data = NULL, 6974 6934 }, 6975 6935 {