mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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:
committed by
Greg Kroah-Hartman
parent
5cd0645b43
commit
63740349eb
93
Documentation/netlink/specs/binder.yaml
Normal file
93
Documentation/netlink/specs/binder.yaml
Normal file
@@ -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
|
L: linux-kernel@vger.kernel.org
|
||||||
S: Supported
|
S: Supported
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
|
||||||
|
F: Documentation/netlink/specs/binder.yaml
|
||||||
F: drivers/android/
|
F: drivers/android/
|
||||||
|
|
||||||
ANDROID GOLDFISH PIC DRIVER
|
ANDROID GOLDFISH PIC DRIVER
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ menu "Android"
|
|||||||
config ANDROID_BINDER_IPC
|
config ANDROID_BINDER_IPC
|
||||||
bool "Android Binder IPC Driver"
|
bool "Android Binder IPC Driver"
|
||||||
depends on MMU
|
depends on MMU
|
||||||
|
depends on NET
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
Binder is used in Android for both communication between processes,
|
Binder is used in Android for both communication between processes,
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
ccflags-y += -I$(src) # needed for trace events
|
ccflags-y += -I$(src) # needed for trace events
|
||||||
|
|
||||||
obj-$(CONFIG_ANDROID_BINDERFS) += binderfs.o
|
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/
|
obj-$(CONFIG_ANDROID_BINDER_ALLOC_KUNIT_TEST) += tests/
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
|
|
||||||
#include <linux/cacheflush.h>
|
#include <linux/cacheflush.h>
|
||||||
|
|
||||||
|
#include "binder_netlink.h"
|
||||||
#include "binder_internal.h"
|
#include "binder_internal.h"
|
||||||
#include "binder_trace.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_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,
|
static void binder_transaction(struct binder_proc *proc,
|
||||||
struct binder_thread *thread,
|
struct binder_thread *thread,
|
||||||
struct binder_transaction_data *tr, int reply,
|
struct binder_transaction_data *tr, int reply,
|
||||||
@@ -3679,10 +3741,13 @@ static void binder_transaction(struct binder_proc *proc,
|
|||||||
return_error_line = __LINE__;
|
return_error_line = __LINE__;
|
||||||
goto err_copy_data_failed;
|
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;
|
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;
|
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
if (reply) {
|
if (reply) {
|
||||||
binder_enqueue_thread_work(thread, tcomplete);
|
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 and is put in a pending queue, waiting for the target
|
||||||
* process to be unfrozen.
|
* process to be unfrozen.
|
||||||
*/
|
*/
|
||||||
if (return_error == BR_TRANSACTION_PENDING_FROZEN)
|
if (return_error == BR_TRANSACTION_PENDING_FROZEN) {
|
||||||
tcomplete->type = BINDER_WORK_TRANSACTION_PENDING;
|
tcomplete->type = BINDER_WORK_TRANSACTION_PENDING;
|
||||||
|
binder_netlink_report(proc, t, tr->data_size,
|
||||||
|
return_error);
|
||||||
|
}
|
||||||
binder_enqueue_thread_work(thread, tcomplete);
|
binder_enqueue_thread_work(thread, tcomplete);
|
||||||
if (return_error &&
|
if (return_error &&
|
||||||
return_error != BR_TRANSACTION_PENDING_FROZEN)
|
return_error != BR_TRANSACTION_PENDING_FROZEN)
|
||||||
@@ -3789,6 +3857,8 @@ err_invalid_target_handle:
|
|||||||
binder_dec_node(target_node, 1, 0);
|
binder_dec_node(target_node, 1, 0);
|
||||||
binder_dec_node_tmpref(target_node);
|
binder_dec_node_tmpref(target_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binder_netlink_report(proc, t, tr->data_size, return_error);
|
||||||
kfree(t);
|
kfree(t);
|
||||||
binder_stats_deleted(BINDER_STAT_TRANSACTION);
|
binder_stats_deleted(BINDER_STAT_TRANSACTION);
|
||||||
err_alloc_t_failed:
|
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)
|
if (ret)
|
||||||
goto err_init_binder_device_failed;
|
goto err_init_binder_device_failed;
|
||||||
|
|
||||||
|
ret = init_binderfs();
|
||||||
|
if (ret)
|
||||||
|
goto err_init_binderfs_failed;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
err_init_binderfs_failed:
|
||||||
|
genl_unregister_family(&binder_nl_family);
|
||||||
|
|
||||||
err_init_binder_device_failed:
|
err_init_binder_device_failed:
|
||||||
hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
|
hlist_for_each_entry_safe(device, tmp, &binder_devices, hlist) {
|
||||||
misc_deregister(&device->miscdev);
|
misc_deregister(&device->miscdev);
|
||||||
|
|||||||
31
drivers/android/binder_netlink.c
Normal file
31
drivers/android/binder_netlink.c
Normal file
@@ -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),
|
||||||
|
};
|
||||||
20
drivers/android/binder_netlink.h
Normal file
20
drivers/android/binder_netlink.h
Normal file
@@ -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 */
|
||||||
37
include/uapi/linux/android/binder_netlink.h
Normal file
37
include/uapi/linux/android/binder_netlink.h
Normal file
@@ -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 */
|
||||||
Reference in New Issue
Block a user