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: introduce transaction reports via netlink

Introduce a generic netlink multicast event to report binder transaction
failures to userspace. This allows subscribers to monitor these events
and take appropriate actions, such as stopping a misbehaving application
that is spamming a service with huge amount of transactions.

The multicast event contains full details of the failed transactions,
including the sender/target PIDs, payload size and specific error code.
This interface is defined using a YAML spec, from which the UAPI and
kernel headers and source are auto-generated.

Signed-off-by: Li Li <dualli@google.com>
Signed-off-by: Carlos Llamas <cmllamas@google.com>
Link: https://lore.kernel.org/r/20250727182932.2499194-4-cmllamas@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Li Li and committed by
Greg Kroah-Hartman
63740349 5cd0645b

+265 -5
+93
Documentation/netlink/specs/binder.yaml
··· 1 + # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 2 + # 3 + # Copyright 2025 Google LLC 4 + # 5 + --- 6 + name: binder 7 + protocol: genetlink 8 + uapi-header: linux/android/binder_netlink.h 9 + doc: Binder interface over generic netlink 10 + 11 + attribute-sets: 12 + - 13 + name: report 14 + doc: | 15 + Attributes included within a transaction failure report. The elements 16 + correspond directly with the specific transaction that failed, along 17 + with the error returned to the sender e.g. BR_DEAD_REPLY. 18 + 19 + attributes: 20 + - 21 + name: error 22 + type: u32 23 + doc: The enum binder_driver_return_protocol returned to the sender. 24 + - 25 + name: context 26 + type: string 27 + doc: The binder context where the transaction occurred. 28 + - 29 + name: from_pid 30 + type: u32 31 + doc: The PID of the sender process. 32 + - 33 + name: from_tid 34 + type: u32 35 + doc: The TID of the sender thread. 36 + - 37 + name: to_pid 38 + type: u32 39 + doc: | 40 + The PID of the recipient process. This attribute may not be present 41 + if the target could not be determined. 42 + - 43 + name: to_tid 44 + type: u32 45 + doc: | 46 + The TID of the recipient thread. This attribute may not be present 47 + if the target could not be determined. 48 + - 49 + name: is_reply 50 + type: flag 51 + doc: When present, indicates the failed transaction is a reply. 52 + - 53 + name: flags 54 + type: u32 55 + doc: The bitmask of enum transaction_flags from the transaction. 56 + - 57 + name: code 58 + type: u32 59 + doc: The application-defined code from the transaction. 60 + - 61 + name: data_size 62 + type: u32 63 + doc: The transaction payload size in bytes. 64 + 65 + operations: 66 + list: 67 + - 68 + name: report 69 + doc: | 70 + A multicast event sent to userspace subscribers to notify them about 71 + binder transaction failures. The generated report provides the full 72 + details of the specific transaction that failed. The intention is for 73 + programs to monitor these events and react to the failures as needed. 74 + 75 + attribute-set: report 76 + mcgrp: report 77 + event: 78 + attributes: 79 + - error 80 + - context 81 + - from_pid 82 + - from_tid 83 + - to_pid 84 + - to_tid 85 + - is_reply 86 + - flags 87 + - code 88 + - data_size 89 + 90 + mcast-groups: 91 + list: 92 + - 93 + name: report
+1
MAINTAINERS
··· 1790 1790 L: linux-kernel@vger.kernel.org 1791 1791 S: Supported 1792 1792 T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 1793 + F: Documentation/netlink/specs/binder.yaml 1793 1794 F: drivers/android/ 1794 1795 1795 1796 ANDROID GOLDFISH PIC DRIVER
+1
drivers/android/Kconfig
··· 4 4 config ANDROID_BINDER_IPC 5 5 bool "Android Binder IPC Driver" 6 6 depends on MMU 7 + depends on NET 7 8 default n 8 9 help 9 10 Binder is used in Android for both communication between processes,
+1 -1
drivers/android/Makefile
··· 2 2 ccflags-y += -I$(src) # needed for trace events 3 3 4 4 obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o 5 - obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o 5 + obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o binder_netlink.o 6 6 obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += tests/
+81 -4
drivers/android/binder.c
··· 74 74 75 75 #include <linux/cacheflush.h> 76 76 77 + #include "binder_netlink.h" 77 78 #include "binder_internal.h" 78 79 #include "binder_trace.h" 79 80 ··· 2994 2993 binder_thread_dec_tmpref(from); 2995 2994 } 2996 2995 2996 + /** 2997 + * binder_netlink_report() - report a transaction failure via netlink 2998 + * @proc: the binder proc sending the transaction 2999 + * @t: the binder transaction that failed 3000 + * @data_size: the user provided data size for the transaction 3001 + * @error: enum binder_driver_return_protocol returned to sender 3002 + */ 3003 + static void binder_netlink_report(struct binder_proc *proc, 3004 + struct binder_transaction *t, 3005 + u32 data_size, 3006 + u32 error) 3007 + { 3008 + const char *context = proc->context->name; 3009 + struct sk_buff *skb; 3010 + void *hdr; 3011 + 3012 + if (!genl_has_listeners(&binder_nl_family, &init_net, 3013 + BINDER_NLGRP_REPORT)) 3014 + return; 3015 + 3016 + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 3017 + if (!skb) 3018 + return; 3019 + 3020 + hdr = genlmsg_put(skb, 0, 0, &binder_nl_family, 0, BINDER_CMD_REPORT); 3021 + if (!hdr) 3022 + goto free_skb; 3023 + 3024 + if (nla_put_u32(skb, BINDER_A_REPORT_ERROR, error) || 3025 + nla_put_string(skb, BINDER_A_REPORT_CONTEXT, context) || 3026 + nla_put_u32(skb, BINDER_A_REPORT_FROM_PID, t->from_pid) || 3027 + nla_put_u32(skb, BINDER_A_REPORT_FROM_TID, t->from_tid)) 3028 + goto cancel_skb; 3029 + 3030 + if (t->to_proc && 3031 + nla_put_u32(skb, BINDER_A_REPORT_TO_PID, t->to_proc->pid)) 3032 + goto cancel_skb; 3033 + 3034 + if (t->to_thread && 3035 + nla_put_u32(skb, BINDER_A_REPORT_TO_TID, t->to_thread->pid)) 3036 + goto cancel_skb; 3037 + 3038 + if (t->is_reply && nla_put_flag(skb, BINDER_A_REPORT_IS_REPLY)) 3039 + goto cancel_skb; 3040 + 3041 + if (nla_put_u32(skb, BINDER_A_REPORT_FLAGS, t->flags) || 3042 + nla_put_u32(skb, BINDER_A_REPORT_CODE, t->code) || 3043 + nla_put_u32(skb, BINDER_A_REPORT_DATA_SIZE, data_size)) 3044 + goto cancel_skb; 3045 + 3046 + genlmsg_end(skb, hdr); 3047 + genlmsg_multicast(&binder_nl_family, skb, 0, BINDER_NLGRP_REPORT, 3048 + GFP_KERNEL); 3049 + return; 3050 + 3051 + cancel_skb: 3052 + genlmsg_cancel(skb, hdr); 3053 + free_skb: 3054 + nlmsg_free(skb); 3055 + } 3056 + 2997 3057 static void binder_transaction(struct binder_proc *proc, 2998 3058 struct binder_thread *thread, 2999 3059 struct binder_transaction_data *tr, int reply, ··· 3741 3679 return_error_line = __LINE__; 3742 3680 goto err_copy_data_failed; 3743 3681 } 3744 - if (t->buffer->oneway_spam_suspect) 3682 + if (t->buffer->oneway_spam_suspect) { 3745 3683 tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT; 3746 - else 3684 + binder_netlink_report(proc, t, tr->data_size, 3685 + BR_ONEWAY_SPAM_SUSPECT); 3686 + } else { 3747 3687 tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; 3688 + } 3748 3689 3749 3690 if (reply) { 3750 3691 binder_enqueue_thread_work(thread, tcomplete); ··· 3795 3730 * process and is put in a pending queue, waiting for the target 3796 3731 * process to be unfrozen. 3797 3732 */ 3798 - if (return_error == BR_TRANSACTION_PENDING_FROZEN) 3733 + if (return_error == BR_TRANSACTION_PENDING_FROZEN) { 3799 3734 tcomplete->type = BINDER_WORK_TRANSACTION_PENDING; 3735 + binder_netlink_report(proc, t, tr->data_size, 3736 + return_error); 3737 + } 3800 3738 binder_enqueue_thread_work(thread, tcomplete); 3801 3739 if (return_error && 3802 3740 return_error != BR_TRANSACTION_PENDING_FROZEN) ··· 3857 3789 binder_dec_node(target_node, 1, 0); 3858 3790 binder_dec_node_tmpref(target_node); 3859 3791 } 3792 + 3793 + binder_netlink_report(proc, t, tr->data_size, return_error); 3860 3794 kfree(t); 3861 3795 binder_stats_deleted(BINDER_STAT_TRANSACTION); 3862 3796 err_alloc_t_failed: ··· 7129 7059 } 7130 7060 } 7131 7061 7132 - ret = init_binderfs(); 7062 + ret = genl_register_family(&binder_nl_family); 7133 7063 if (ret) 7134 7064 goto err_init_binder_device_failed; 7135 7065 7066 + ret = init_binderfs(); 7067 + if (ret) 7068 + goto err_init_binderfs_failed; 7069 + 7136 7070 return ret; 7071 + 7072 + err_init_binderfs_failed: 7073 + genl_unregister_family(&binder_nl_family); 7137 7074 7138 7075 err_init_binder_device_failed: 7139 7076 hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
+31
drivers/android/binder_netlink.c
··· 1 + // SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/binder.yaml */ 4 + /* YNL-GEN kernel source */ 5 + 6 + #include <net/netlink.h> 7 + #include <net/genetlink.h> 8 + 9 + #include "binder_netlink.h" 10 + 11 + #include <uapi/linux/android/binder_netlink.h> 12 + 13 + /* Ops table for binder */ 14 + static const struct genl_split_ops binder_nl_ops[] = { 15 + }; 16 + 17 + static const struct genl_multicast_group binder_nl_mcgrps[] = { 18 + [BINDER_NLGRP_REPORT] = { "report", }, 19 + }; 20 + 21 + struct genl_family binder_nl_family __ro_after_init = { 22 + .name = BINDER_FAMILY_NAME, 23 + .version = BINDER_FAMILY_VERSION, 24 + .netnsok = true, 25 + .parallel_ops = true, 26 + .module = THIS_MODULE, 27 + .split_ops = binder_nl_ops, 28 + .n_split_ops = ARRAY_SIZE(binder_nl_ops), 29 + .mcgrps = binder_nl_mcgrps, 30 + .n_mcgrps = ARRAY_SIZE(binder_nl_mcgrps), 31 + };
+20
drivers/android/binder_netlink.h
··· 1 + /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/binder.yaml */ 4 + /* YNL-GEN kernel header */ 5 + 6 + #ifndef _LINUX_BINDER_GEN_H 7 + #define _LINUX_BINDER_GEN_H 8 + 9 + #include <net/netlink.h> 10 + #include <net/genetlink.h> 11 + 12 + #include <uapi/linux/android/binder_netlink.h> 13 + 14 + enum { 15 + BINDER_NLGRP_REPORT, 16 + }; 17 + 18 + extern struct genl_family binder_nl_family; 19 + 20 + #endif /* _LINUX_BINDER_GEN_H */
+37
include/uapi/linux/android/binder_netlink.h
··· 1 + /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ 2 + /* Do not edit directly, auto-generated from: */ 3 + /* Documentation/netlink/specs/binder.yaml */ 4 + /* YNL-GEN uapi header */ 5 + 6 + #ifndef _UAPI_LINUX_ANDROID_BINDER_NETLINK_H 7 + #define _UAPI_LINUX_ANDROID_BINDER_NETLINK_H 8 + 9 + #define BINDER_FAMILY_NAME "binder" 10 + #define BINDER_FAMILY_VERSION 1 11 + 12 + enum { 13 + BINDER_A_REPORT_ERROR = 1, 14 + BINDER_A_REPORT_CONTEXT, 15 + BINDER_A_REPORT_FROM_PID, 16 + BINDER_A_REPORT_FROM_TID, 17 + BINDER_A_REPORT_TO_PID, 18 + BINDER_A_REPORT_TO_TID, 19 + BINDER_A_REPORT_IS_REPLY, 20 + BINDER_A_REPORT_FLAGS, 21 + BINDER_A_REPORT_CODE, 22 + BINDER_A_REPORT_DATA_SIZE, 23 + 24 + __BINDER_A_REPORT_MAX, 25 + BINDER_A_REPORT_MAX = (__BINDER_A_REPORT_MAX - 1) 26 + }; 27 + 28 + enum { 29 + BINDER_CMD_REPORT = 1, 30 + 31 + __BINDER_CMD_MAX, 32 + BINDER_CMD_MAX = (__BINDER_CMD_MAX - 1) 33 + }; 34 + 35 + #define BINDER_MCGRP_REPORT "report" 36 + 37 + #endif /* _UAPI_LINUX_ANDROID_BINDER_NETLINK_H */