mirror of https://github.com/torvalds/linux.git
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>
This commit is contained in:
parent
5cd0645b43
commit
63740349eb
|
|
@ -0,0 +1,93 @@
|
|||
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
#
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
---
|
||||
name: binder
|
||||
protocol: genetlink
|
||||
uapi-header: linux/android/binder_netlink.h
|
||||
doc: Binder interface over generic netlink
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: report
|
||||
doc: |
|
||||
Attributes included within a transaction failure report. The elements
|
||||
correspond directly with the specific transaction that failed, along
|
||||
with the error returned to the sender e.g. BR_DEAD_REPLY.
|
||||
|
||||
attributes:
|
||||
-
|
||||
name: error
|
||||
type: u32
|
||||
doc: The enum binder_driver_return_protocol returned to the sender.
|
||||
-
|
||||
name: context
|
||||
type: string
|
||||
doc: The binder context where the transaction occurred.
|
||||
-
|
||||
name: from_pid
|
||||
type: u32
|
||||
doc: The PID of the sender process.
|
||||
-
|
||||
name: from_tid
|
||||
type: u32
|
||||
doc: The TID of the sender thread.
|
||||
-
|
||||
name: to_pid
|
||||
type: u32
|
||||
doc: |
|
||||
The PID of the recipient process. This attribute may not be present
|
||||
if the target could not be determined.
|
||||
-
|
||||
name: to_tid
|
||||
type: u32
|
||||
doc: |
|
||||
The TID of the recipient thread. This attribute may not be present
|
||||
if the target could not be determined.
|
||||
-
|
||||
name: is_reply
|
||||
type: flag
|
||||
doc: When present, indicates the failed transaction is a reply.
|
||||
-
|
||||
name: flags
|
||||
type: u32
|
||||
doc: The bitmask of enum transaction_flags from the transaction.
|
||||
-
|
||||
name: code
|
||||
type: u32
|
||||
doc: The application-defined code from the transaction.
|
||||
-
|
||||
name: data_size
|
||||
type: u32
|
||||
doc: The transaction payload size in bytes.
|
||||
|
||||
operations:
|
||||
list:
|
||||
-
|
||||
name: report
|
||||
doc: |
|
||||
A multicast event sent to userspace subscribers to notify them about
|
||||
binder transaction failures. The generated report provides the full
|
||||
details of the specific transaction that failed. The intention is for
|
||||
programs to monitor these events and react to the failures as needed.
|
||||
|
||||
attribute-set: report
|
||||
mcgrp: report
|
||||
event:
|
||||
attributes:
|
||||
- error
|
||||
- context
|
||||
- from_pid
|
||||
- from_tid
|
||||
- to_pid
|
||||
- to_tid
|
||||
- is_reply
|
||||
- flags
|
||||
- code
|
||||
- data_size
|
||||
|
||||
mcast-groups:
|
||||
list:
|
||||
-
|
||||
name: report
|
||||
|
|
@ -1790,6 +1790,7 @@ M: Suren Baghdasaryan <surenb@google.com>
|
|||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
|
||||
F: Documentation/netlink/specs/binder.yaml
|
||||
F: drivers/android/
|
||||
|
||||
ANDROID GOLDFISH PIC DRIVER
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ menu "Android"
|
|||
config ANDROID_BINDER_IPC
|
||||
bool "Android Binder IPC Driver"
|
||||
depends on MMU
|
||||
depends on NET
|
||||
default n
|
||||
help
|
||||
Binder is used in Android for both communication between processes,
|
||||
|
|
|
|||
|
|
@ -2,5 +2,5 @@
|
|||
ccflags-y += -I$(src) # needed for trace events
|
||||
|
||||
obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o
|
||||
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o
|
||||
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o binder_netlink.o
|
||||
obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += tests/
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
|
||||
#include <linux/cacheflush.h>
|
||||
|
||||
#include "binder_netlink.h"
|
||||
#include "binder_internal.h"
|
||||
#include "binder_trace.h"
|
||||
|
||||
|
|
@ -2993,6 +2994,67 @@ static void binder_set_txn_from_error(struct binder_transaction *t, int id,
|
|||
binder_thread_dec_tmpref(from);
|
||||
}
|
||||
|
||||
/**
|
||||
* binder_netlink_report() - report a transaction failure via netlink
|
||||
* @proc: the binder proc sending the transaction
|
||||
* @t: the binder transaction that failed
|
||||
* @data_size: the user provided data size for the transaction
|
||||
* @error: enum binder_driver_return_protocol returned to sender
|
||||
*/
|
||||
static void binder_netlink_report(struct binder_proc *proc,
|
||||
struct binder_transaction *t,
|
||||
u32 data_size,
|
||||
u32 error)
|
||||
{
|
||||
const char *context = proc->context->name;
|
||||
struct sk_buff *skb;
|
||||
void *hdr;
|
||||
|
||||
if (!genl_has_listeners(&binder_nl_family, &init_net,
|
||||
BINDER_NLGRP_REPORT))
|
||||
return;
|
||||
|
||||
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
hdr = genlmsg_put(skb, 0, 0, &binder_nl_family, 0, BINDER_CMD_REPORT);
|
||||
if (!hdr)
|
||||
goto free_skb;
|
||||
|
||||
if (nla_put_u32(skb, BINDER_A_REPORT_ERROR, error) ||
|
||||
nla_put_string(skb, BINDER_A_REPORT_CONTEXT, context) ||
|
||||
nla_put_u32(skb, BINDER_A_REPORT_FROM_PID, t->from_pid) ||
|
||||
nla_put_u32(skb, BINDER_A_REPORT_FROM_TID, t->from_tid))
|
||||
goto cancel_skb;
|
||||
|
||||
if (t->to_proc &&
|
||||
nla_put_u32(skb, BINDER_A_REPORT_TO_PID, t->to_proc->pid))
|
||||
goto cancel_skb;
|
||||
|
||||
if (t->to_thread &&
|
||||
nla_put_u32(skb, BINDER_A_REPORT_TO_TID, t->to_thread->pid))
|
||||
goto cancel_skb;
|
||||
|
||||
if (t->is_reply && nla_put_flag(skb, BINDER_A_REPORT_IS_REPLY))
|
||||
goto cancel_skb;
|
||||
|
||||
if (nla_put_u32(skb, BINDER_A_REPORT_FLAGS, t->flags) ||
|
||||
nla_put_u32(skb, BINDER_A_REPORT_CODE, t->code) ||
|
||||
nla_put_u32(skb, BINDER_A_REPORT_DATA_SIZE, data_size))
|
||||
goto cancel_skb;
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
genlmsg_multicast(&binder_nl_family, skb, 0, BINDER_NLGRP_REPORT,
|
||||
GFP_KERNEL);
|
||||
return;
|
||||
|
||||
cancel_skb:
|
||||
genlmsg_cancel(skb, hdr);
|
||||
free_skb:
|
||||
nlmsg_free(skb);
|
||||
}
|
||||
|
||||
static void binder_transaction(struct binder_proc *proc,
|
||||
struct binder_thread *thread,
|
||||
struct binder_transaction_data *tr, int reply,
|
||||
|
|
@ -3679,10 +3741,13 @@ static void binder_transaction(struct binder_proc *proc,
|
|||
return_error_line = __LINE__;
|
||||
goto err_copy_data_failed;
|
||||
}
|
||||
if (t->buffer->oneway_spam_suspect)
|
||||
if (t->buffer->oneway_spam_suspect) {
|
||||
tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT;
|
||||
else
|
||||
binder_netlink_report(proc, t, tr->data_size,
|
||||
BR_ONEWAY_SPAM_SUSPECT);
|
||||
} else {
|
||||
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
|
||||
}
|
||||
|
||||
if (reply) {
|
||||
binder_enqueue_thread_work(thread, tcomplete);
|
||||
|
|
@ -3730,8 +3795,11 @@ static void binder_transaction(struct binder_proc *proc,
|
|||
* process and is put in a pending queue, waiting for the target
|
||||
* process to be unfrozen.
|
||||
*/
|
||||
if (return_error == BR_TRANSACTION_PENDING_FROZEN)
|
||||
if (return_error == BR_TRANSACTION_PENDING_FROZEN) {
|
||||
tcomplete->type = BINDER_WORK_TRANSACTION_PENDING;
|
||||
binder_netlink_report(proc, t, tr->data_size,
|
||||
return_error);
|
||||
}
|
||||
binder_enqueue_thread_work(thread, tcomplete);
|
||||
if (return_error &&
|
||||
return_error != BR_TRANSACTION_PENDING_FROZEN)
|
||||
|
|
@ -3789,6 +3857,8 @@ static void binder_transaction(struct binder_proc *proc,
|
|||
binder_dec_node(target_node, 1, 0);
|
||||
binder_dec_node_tmpref(target_node);
|
||||
}
|
||||
|
||||
binder_netlink_report(proc, t, tr->data_size, return_error);
|
||||
kfree(t);
|
||||
binder_stats_deleted(BINDER_STAT_TRANSACTION);
|
||||
err_alloc_t_failed:
|
||||
|
|
@ -7059,12 +7129,19 @@ static int __init binder_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
ret = init_binderfs();
|
||||
ret = genl_register_family(&binder_nl_family);
|
||||
if (ret)
|
||||
goto err_init_binder_device_failed;
|
||||
|
||||
ret = init_binderfs();
|
||||
if (ret)
|
||||
goto err_init_binderfs_failed;
|
||||
|
||||
return ret;
|
||||
|
||||
err_init_binderfs_failed:
|
||||
genl_unregister_family(&binder_nl_family);
|
||||
|
||||
err_init_binder_device_failed:
|
||||
hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
|
||||
misc_deregister(&device->miscdev);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/binder.yaml */
|
||||
/* YNL-GEN kernel source */
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include "binder_netlink.h"
|
||||
|
||||
#include <uapi/linux/android/binder_netlink.h>
|
||||
|
||||
/* Ops table for binder */
|
||||
static const struct genl_split_ops binder_nl_ops[] = {
|
||||
};
|
||||
|
||||
static const struct genl_multicast_group binder_nl_mcgrps[] = {
|
||||
[BINDER_NLGRP_REPORT] = { "report", },
|
||||
};
|
||||
|
||||
struct genl_family binder_nl_family __ro_after_init = {
|
||||
.name = BINDER_FAMILY_NAME,
|
||||
.version = BINDER_FAMILY_VERSION,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.module = THIS_MODULE,
|
||||
.split_ops = binder_nl_ops,
|
||||
.n_split_ops = ARRAY_SIZE(binder_nl_ops),
|
||||
.mcgrps = binder_nl_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(binder_nl_mcgrps),
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/binder.yaml */
|
||||
/* YNL-GEN kernel header */
|
||||
|
||||
#ifndef _LINUX_BINDER_GEN_H
|
||||
#define _LINUX_BINDER_GEN_H
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include <uapi/linux/android/binder_netlink.h>
|
||||
|
||||
enum {
|
||||
BINDER_NLGRP_REPORT,
|
||||
};
|
||||
|
||||
extern struct genl_family binder_nl_family;
|
||||
|
||||
#endif /* _LINUX_BINDER_GEN_H */
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/binder.yaml */
|
||||
/* YNL-GEN uapi header */
|
||||
|
||||
#ifndef _UAPI_LINUX_ANDROID_BINDER_NETLINK_H
|
||||
#define _UAPI_LINUX_ANDROID_BINDER_NETLINK_H
|
||||
|
||||
#define BINDER_FAMILY_NAME "binder"
|
||||
#define BINDER_FAMILY_VERSION 1
|
||||
|
||||
enum {
|
||||
BINDER_A_REPORT_ERROR = 1,
|
||||
BINDER_A_REPORT_CONTEXT,
|
||||
BINDER_A_REPORT_FROM_PID,
|
||||
BINDER_A_REPORT_FROM_TID,
|
||||
BINDER_A_REPORT_TO_PID,
|
||||
BINDER_A_REPORT_TO_TID,
|
||||
BINDER_A_REPORT_IS_REPLY,
|
||||
BINDER_A_REPORT_FLAGS,
|
||||
BINDER_A_REPORT_CODE,
|
||||
BINDER_A_REPORT_DATA_SIZE,
|
||||
|
||||
__BINDER_A_REPORT_MAX,
|
||||
BINDER_A_REPORT_MAX = (__BINDER_A_REPORT_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
BINDER_CMD_REPORT = 1,
|
||||
|
||||
__BINDER_CMD_MAX,
|
||||
BINDER_CMD_MAX = (__BINDER_CMD_MAX - 1)
|
||||
};
|
||||
|
||||
#define BINDER_MCGRP_REPORT "report"
|
||||
|
||||
#endif /* _UAPI_LINUX_ANDROID_BINDER_NETLINK_H */
|
||||
Loading…
Reference in New Issue