[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CANBPYPhbzDqijP2verfDTFpSp3aKFY59pJzXk9FnALM=0U_yjw@mail.gmail.com>
Date: Tue, 22 Apr 2025 00:50:46 -0700
From: Li Li <dualli@...omium.org>
To: Simon Horman <horms@...nel.org>
Cc: dualli@...gle.com, corbet@....net, davem@...emloft.net,
edumazet@...gle.com, kuba@...nel.org, pabeni@...hat.com,
donald.hunter@...il.com, gregkh@...uxfoundation.org, arve@...roid.com,
tkjos@...roid.com, maco@...roid.com, joel@...lfernandes.org,
brauner@...nel.org, cmllamas@...gle.com, surenb@...gle.com,
omosnace@...hat.com, shuah@...nel.org, arnd@...db.de, masahiroy@...nel.org,
bagasdotme@...il.com, tweek@...gle.com, paul@...l-moore.com,
linux-kernel@...r.kernel.org, linux-doc@...r.kernel.org,
netdev@...r.kernel.org, selinux@...r.kernel.org,
linux-security-module@...r.kernel.org, hridya@...gle.com,
smoreland@...gle.com, ynaffit@...gle.com, kernel-team@...roid.com
Subject: Re: [PATCH RESEND v17 2/3] binder: report txn errors via generic netlink
On Mon, Apr 21, 2025 at 8:17 AM Simon Horman <horms@...nel.org> wrote:
>
> On Wed, Apr 16, 2025 at 05:20:03PM -0700, Li Li wrote:
> > From: Li Li <dualli@...gle.com>
> >
> > Introduce generic netlink messages into the binder driver so that the
> > Linux/Android system administration processes can listen to important
> > events and take corresponding actions, like stopping a broken app from
> > attacking the OS by sending huge amount of spamming binder transactions.
> >
> > The binder netlink sources and headers are automatically generated from
> > the corresponding binder netlink YAML spec. Don't modify them directly.
> >
> > Signed-off-by: Li Li <dualli@...gle.com>
>
> Hi Li Li,
>
> > diff --git a/drivers/android/binder.c b/drivers/android/binder.c
>
> ...
>
> > static void binder_transaction(struct binder_proc *proc,
> > struct binder_thread *thread,
> > struct binder_transaction_data *tr, int reply,
> > @@ -3683,10 +3764,14 @@ 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
> > + if (binder_netlink_enabled(proc, BINDER_FLAG_SPAM))
> > + binder_netlink_report(context, BR_ONEWAY_SPAM_SUSPECT,
> > + reply, t);
> > + } else {
> > tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
> > + }
> > t->work.type = BINDER_WORK_TRANSACTION;
> >
> > if (reply) {
> > @@ -3736,8 +3821,12 @@ 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;
> > + if (binder_netlink_enabled(proc, BINDER_FLAG_ASYNC_FROZEN))
> > + binder_netlink_report(context, return_error,
> > + reply, t);
> > + }
> > binder_enqueue_thread_work(thread, tcomplete);
> > if (return_error &&
> > return_error != BR_TRANSACTION_PENDING_FROZEN)
> > @@ -3799,6 +3888,10 @@ static void binder_transaction(struct binder_proc *proc,
>
> The code preceding this hunk looks like this:
>
> err_alloc_tcomplete_failed:
> if (trace_binder_txn_latency_free_enabled())
> binder_txn_latency_free(t);
> kfree(t);
> binder_stats_deleted(BINDER_STAT_TRANSACTION);
> err_alloc_t_failed:
> err_bad_todo_list:
> err_bad_call_stack:
> err_empty_call_stack:
> err_dead_binder:
> err_invalid_target_handle:
> if (target_node) {
> binder_dec_node(target_node, 1, 0);
> binder_dec_node_tmpref(target_node);
> }
>
> 1. The labels err_bad_todo_list, err_bad_call_stack,
> err_empty_call_stack, and err_invalid_target_handle may
> be jumped to before t is initialised.
>
> 2. In the err_alloc_tcomplete_failed label t is kfree'd.
>
> However, the call to binder_netlink_report below will dereference t.
>
> Flagged by Smatch.
>
Thank you for flagging this! Let me double check the lifecycle of t.
> > binder_dec_node_tmpref(target_node);
> > }
> >
> > + if (binder_netlink_enabled(proc, BINDER_FLAG_FAILED))
> > + binder_netlink_report(context, return_error,
> > + reply, t);
> > +
> > binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
> > "%d:%d transaction %s to %d:%d failed %d/%d/%d, code %u size %lld-%lld line %d\n",
> > proc->pid, thread->pid, reply ? "reply" :
>
> ...
>
> > +/**
> > + * binder_nl_report_setup_doit() - netlink .doit handler
> > + * @skb: the metadata struct passed from netlink driver
> > + * @info: the generic netlink struct passed from netlink driver
> > + *
> > + * Implements the .doit function to process binder netlink commands.
> > + */
> > +int binder_nl_report_setup_doit(struct sk_buff *skb, struct genl_info *info)
> > +{
> > + struct binder_context *context = NULL;
> > + struct binder_device *device;
> > + struct binder_proc *proc;
> > + u32 flags, pid;
> > + bool found;
> > + void *hdr;
> > + int ret;
> > +
> > + ret = security_binder_setup_report(current_cred());
> > + if (ret < 0) {
> > + NL_SET_ERR_MSG(info->extack, "Permission denied");
> > + return ret;
> > + }
> > +
> > + if (nla_len(info->attrs[BINDER_A_CMD_CONTEXT])) {
> > + /* Search the specified binder context */
> > + hlist_for_each_entry(device, &binder_devices, hlist) {
> > + if (!nla_strcmp(info->attrs[BINDER_A_CMD_CONTEXT],
> > + device->context.name)) {
> > + context = &device->context;
> > + break;
> > + }
> > + }
> > +
> > + if (!context) {
> > + NL_SET_ERR_MSG(info->extack, "Invalid binder context");
> > + return -EINVAL;
> > + }
> > + }
> > +
> > + pid = nla_get_u32(info->attrs[BINDER_A_CMD_PID]);
> > + flags = nla_get_u32(info->attrs[BINDER_A_CMD_FLAGS]);
> > +
> > + if (!pid) {
> > + if (!context) {
> > + NL_SET_ERR_MSG(info->extack,
> > + "Invalid binder context and pid");
> > + return -EINVAL;
> > + }
> > +
> > + /* Set the global flags for the whole binder context */
> > + context->report_flags = flags;
> > + } else {
> > + /* Set the per-process flags */
> > + found = false;
> > + mutex_lock(&binder_procs_lock);
> > + hlist_for_each_entry(proc, &binder_procs, proc_node) {
> > + if (proc->pid == pid
> > + && (proc->context == context || !context)) {
> > + proc->report_flags = flags;
> > + found = true;
> > + }
> > + }
> > + mutex_unlock(&binder_procs_lock);
> > +
> > + if (!found) {
> > + NL_SET_ERR_MSG_FMT(info->extack,
> > + "Invalid binder report pid %u",
> > + pid);
> > + return -EINVAL;
> > + }
> > + }
>
> Within the above conditions it is assumed that context may be NULL.
>
> > +
> > + skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
> > + if (!skb) {
> > + pr_err("Failed to alloc binder netlink reply message\n");
> > + return -ENOMEM;
> > + }
> > +
> > + hdr = genlmsg_iput(skb, info);
> > + if (!hdr)
> > + goto free_skb;
> > +
> > + if (nla_put_string(skb, BINDER_A_CMD_CONTEXT, context->name) ||
>
> But here context is dereferenced unconditionally.
> This does not seem consistent.
>
> Flagged by Smatch.
>
Indeed, I should use proc->context->name here.
> > + nla_put_u32(skb, BINDER_A_CMD_PID, pid) ||
> > + nla_put_u32(skb, BINDER_A_CMD_FLAGS, flags))
> > + goto cancel_skb;
> > +
> > + genlmsg_end(skb, hdr);
> > +
> > + if (genlmsg_reply(skb, info)) {
> > + pr_err("Failed to send binder netlink reply message\n");
> > + return -EFAULT;
> > + }
> > +
> > + return 0;
> > +
> > +cancel_skb:
> > + pr_err("Failed to add reply attributes to binder netlink message\n");
> > + genlmsg_cancel(skb, hdr);
> > +free_skb:
> > + pr_err("Free binder netlink reply message on error\n");
> > + nlmsg_free(skb);
> > + ret = -EMSGSIZE;
> > +
> > + return ret;
> > +}
>
> ...
Powered by blists - more mailing lists