From: Oliver Hartkopp <socketcan@hartkopp.net>
To: netdev-bot+sashiko@kernel.org, mkl@pengutronix.de
Cc: netdev@vger.kernel.org, davem@davemloft.net, kuba@kernel.org,
linux-can@vger.kernel.org, kernel@pengutronix.de,
kurt.van.dijck@eia.be
Subject: Re: [PATCH net-next 08/37] can: bcm: fix filter removal race between release and netns change
Date: Fri, 16 Oct 2026 10:51:30 +0200 [thread overview]
Message-ID: <797e174d-cb77-47f8-b56e-c1cfcb1784e4@hartkopp.net> (raw)
In-Reply-To: <179211822523.434549.241636889494644724@kernel.org>
I'm working on an update on this.
On 16.10.26 04:37, netdev-bot+sashiko@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential
> issue(s) to consider.
>
> Critical: 0 · High: 0 · Medium: 2 · Low: 1
>
> If you believe none of the issues are legitimate, please reply to each
> issue of Medium severity or higher and explain why the AI is wrong.
> If any of them are legitimate and you plan to respin, please let patchwork
> know by including "pw-bot: cr" as a separate line at the end of your reply
> (one such reply per series is enough).
>
> - [Medium] The commit moves remove_proc_entry() ahead of rtnl_lock() so
> that procfs readers cannot stall RTNL from close().
> - [Medium] bcm_release() now holds the global rtnl_mutex across the whole
> rx_ops unregistration loop (rtnl_lock() at net/can/bcm.c:1951,…
> - [Low] Stale comment in bcm_release().
>
> --
>
> can: bcm: fix filter removal race between release and netns change
>
> bcm_release() now takes rtnl_lock() before it removes the socket from
> bcm_notifier_list. It holds RTNL across the rx_ops unregistration, so
> bcm_release() and bcm_notify() can no longer both skip filter removal
> while the bound device moves to another netns. The bcm_busy_notifier
> busy-wait becomes a WARN_ON_ONCE(), and the procfs entry and tx_ops are
> now removed before RTNL is taken.
>
> Link: https://lore.kernel.org/linux-can/CEA6A38A-2646-4ADA-95B4-CBAE2F301A8E@doyensec.com/
> Link: https://patch.msgid.link/20261014142114.280279-3-socketcan@hartkopp.net
>
>> diff --git a/net/can/bcm.c b/net/can/bcm.c
>> index 6759662e024c..301920011a30 100644
>> --- a/net/can/bcm.c
>> +++ b/net/can/bcm.c
>> @@ -1926,21 +1926,19 @@ static int bcm_release(struct socket *sock)
>>
>> /* remove bcm_ops, timer, rx_unregister(), etc. */
>>
>> - spin_lock(&bcm_notifier_lock);
>> - while (bcm_busy_notifier == bo) {
>> - spin_unlock(&bcm_notifier_lock);
>> - schedule_timeout_uninterruptible(1);
>> - spin_lock(&bcm_notifier_lock);
>> - }
>> - list_del(&bo->notifier);
>> - spin_unlock(&bcm_notifier_lock);
>> -
>> + /* Remove the procfs entry and the tx_ops before taking RTNL:
>> + * remove_proc_entry() waits for concurrent readers of the entry and
>> + * must not hold up RTNL for them. Clear bo->bcm_proc_read so that
>> + * bcm_notify() does not remove the entry a second time.
>> + */
>> lock_sock(sk);
>>
>> #if IS_ENABLED(CONFIG_PROC_FS)
>> /* remove procfs entry */
>> - if (net->can.bcmproc_dir && bo->bcm_proc_read)
>> + if (net->can.bcmproc_dir && bo->bcm_proc_read) {
>> remove_proc_entry(bo->procname, net->can.bcmproc_dir);
>> + bo->bcm_proc_read = NULL;
>> + }
>> #endif /* CONFIG_PROC_FS */
>
> [Severity: Medium]
> list_del(&bo->notifier) now runs after rtnl_lock(). That means this
> first lock_sock() section runs while the socket is still on
> bcm_notifier_list. Can a procfs reader still stall RTNL here, just
> indirectly through the socket lock?
>
> Consider this interleaving:
>
> CPU1 (close)
> bcm_release()
> lock_sock(sk)
> remove_proc_entry()
> proc_entry_rundown()
> wait_for_completion() <- waits for the reader on CPU2
>
> CPU2 (reader of /proc/net/can-bcm/<ino>)
> proc_reg_read()
> use_pde()
> pde_read() <- copy to a FUSE or userfaultfd
> backed buffer blocks
>
> CPU3 (NETDEV_UNREGISTER, RTNL held)
> bcm_notifier()
> bcm_notify(bo, NETDEV_UNREGISTER, dev)
> lock_sock(sk) <- blocks behind CPU1
>
> bcm_notify() takes lock_sock(sk) before it checks whether any op or the
> binding uses dev. So deleting or moving any CAN device in the socket's
> netns would be enough.
>
> Before this patch, the socket was unlinked first and the busy-wait made
> sure bcm_notify() was not running for it, so this interleaving was not
> possible.
>
> The procfs entry is mode 0644 and is created on any connect(), including
> can_ifindex = 0. With unprivileged user namespaces, a vcan device in a
> user-owned netns can trigger the notifier, and RTNL is global.
>
> Does this mean the commit message goal ("which could otherwise stall
> RTNL from a plain close()") is only partly met?
>
> There are similar RTNL stall paths already. bcm_sendmsg() holds
> lock_sock() across memcpy_from_msg() in bcm_tx_setup() and
> bcm_rx_setup(), and bcm_notify() itself calls remove_proc_entry() under
> RTNL. This particular ordering is new with this patch, though.
>
> [ ... ]
>
>> @@ -1948,6 +1946,21 @@ static int bcm_release(struct socket *sock)
>> bcm_remove_op(op);
>> }
>>
>> + release_sock(sk);
>> +
>> + rtnl_lock();
>> +
>> + /* The netdev notifier chain runs under RTNL, so bcm_notifier() can't
>> + * be walking bcm_notifier_list and point to this socket. The spinlock
>> + * is still needed as bcm_init() adds sockets without holding RTNL.
>> + */
>> + spin_lock(&bcm_notifier_lock);
>> + WARN_ON_ONCE(bcm_busy_notifier == bo);
>> + list_del(&bo->notifier);
>> + spin_unlock(&bcm_notifier_lock);
>> +
>> + lock_sock(sk);
>> +
>> list_for_each_entry_safe(op, next, &bo->rx_ops, list) {
>> /*
>> * Don't care if we're bound or not (due to netdev problems)
>
> [Severity: Low]
> This isn't a functional problem, but the comment a bit further down in
> this rx_ops loop in bcm_release() still describes a concurrent
> unregister:
>
> * op->rx_reg_dev is a tracked reference taken
> * when the subscription was registered, so it
> * stays valid here even if a concurrent
> * NETDEV_UNREGISTER already unlisted the device.
>
> This loop now runs between rtnl_lock() and rtnl_unlock(), and the socket
> stays on bcm_notifier_list until RTNL is taken. A NETDEV_UNREGISTER has
> either already finished, in which case bcm_notify()->bcm_rx_unreg()
> cleared op->rx_reg_dev, or it runs after this loop, when the socket is
> no longer on the list.
>
> Can a concurrent NETDEV_UNREGISTER still happen at this point? The old
> comment seems to contradict the new comment added above it.
>
> The same comment in bcm_delete_rx_op() is still accurate, because that
> path does not hold RTNL. Should the copy in bcm_release() be updated?
>
>> @@ -1973,6 +1986,8 @@ static int bcm_release(struct socket *sock)
>>
>> }
>>
>> + rtnl_unlock();
>> +
>> synchronize_rcu();
>
> [Severity: Medium]
> The global rtnl_mutex is now held across the whole rx_ops
> unregistration loop, and userspace decides how long that loop is. Is
> that intended?
>
> bcm_rx_setup() allocates one op per distinct (can_id, ifindex) with
> kzalloc(OPSIZ, GFP_KERNEL). That allocation is not memcg accounted, and
> there is no per-socket limit. bcm_connect() accepts can_ifindex == 0
> without any device, and ANYDEV ops register on the all-devices list
> through:
>
> err = can_rx_register(sock_net(sk), NULL, op->can_id,
>
> So an unprivileged user with no CAN hardware can create a very large
> number of ops.
>
> On close(), each op calls can_rx_unregister(). That takes
> spin_lock_bh(&net->can.rcvlists_lock) and walks the receiver hlist
> linearly until it finds the match.
>
> A second socket can put M newer entries in front of the victim's
> entries in the same bucket. It can do this with EFF ids that fold to
> the same bucket in effhash(), or with the same SFF id. RTNL would then
> be held for roughly K * M list steps.
>
> Before this patch, the same loop ran only under lock_sock(sk), so only
> the closing task paid for it. Now it would block netlink and netdev
> configuration in every network namespace.
>
> The loop without cond_resched() already existed, and the attacker needs
> a lot of kernel memory. What is new is that RTNL covers the whole loop.
>
next prev parent reply other threads:[~2026-10-16 8:53 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-15 1:39 [PATCH net-next 0/37] pull-request: can-next 2026-10-15 Marc Kleine-Budde
2026-10-15 1:39 ` [PATCH net-next 01/37] can: dev: can_dropped_invalid_skb: drop CAN XL frames on non-CAN XL devices Marc Kleine-Budde
2026-10-15 1:57 ` netdev-bot+sinfo
2026-10-16 8:25 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 02/37] can: raw: remove redundant NULL check before netdev_hold() Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 03/37] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-16 8:42 ` Marc Kleine-Budde
2026-10-16 10:00 ` Oliver Hartkopp
2026-10-15 1:40 ` [PATCH net-next 04/37] can: proc: reset pkg_stats atomics individually Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-16 9:25 ` Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 05/37] can: proc: remove pointers from CAN specific proc output Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 06/37] can: isotp: check the frame type, not just the length Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 07/37] can: isotp: fix filter removal race between release and netns change Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 08/37] can: bcm: " Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-16 8:51 ` Oliver Hartkopp [this message]
2026-10-15 1:40 ` [PATCH net-next 09/37] can: raw: take rtnl_lock() before leaving the notifier list Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 10/37] can: skb: make echo skb freeing safe in any IRQ context Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 11/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3S SoC Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 12/37] can: skb: make CAN skb allocation failure paths IRQ-safe Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 13/37] can: rcar_canfd: Fix typos in macro names Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 14/37] can: dev: can_put_echo_skb(): free skb on invalid echo index Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 15/37] can: rcar_canfd: Allow the CAN FD clock to be sourced from fck Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 16/37] can: rcar_canfd: Do not set registers selecting the CAN mode Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 17/37] can: rcar_canfd: Add support for Renesas RZ/G3S Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 18/37] dt-bindings: can: renesas,rcar-canfd: Restrict resets in top-level Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 19/37] dt-bindings: can: renesas,rcar-canfd: Document RZ/G3L SoC Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 20/37] can: rcar_canfd: Derive max_channels from the device tree Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 21/37] dt-bindings: net: can: convert grcan to DT schema Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 22/37] can: rcar_canfd: Add support for Renesas RZ/G3L Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 23/37] can: grcan: update the binding file reference in the driver comment Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 24/37] can: remove Softing CANcard driver Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 25/37] can: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 26/37] can: cc770: don't discard the IRQ lookup error in probe Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 27/37] can: cc770: fix the clock divider check on the platform bus Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 28/37] can: ems_usb: use usb_kill_urb() to stop the intr URB Marc Kleine-Budde
2026-10-16 2:37 ` netdev-bot+sashiko
2026-10-15 1:40 ` [PATCH net-next 29/37] can: esd: acc_start_xmit(): avoid use-after-free of skb after can_put_echo_skb() Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 30/37] can: flexcan: flexcan_setup_stop_mode_gpr: fix OF node reference leak Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 31/37] can: kvaser_usb: refactor endpoint lookup Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 32/37] can: kvaser_usb: validate command format before parsing in hydra receive path Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 33/37] can: kvaser_pciefd: fix use-after-free in bec poll timer Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 34/37] can: mcp251xfd: mcp251xfd_probe(): reject devices without match data Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 35/37] can: sun4i_can: sun4ican_probe(): fix clk leak Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 36/37] can: ucan: fix repeated word 'is' in comment Marc Kleine-Budde
2026-10-15 1:40 ` [PATCH net-next 37/37] can: xilinx_can: set CAN FD flags on received frames Marc Kleine-Budde
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=797e174d-cb77-47f8-b56e-c1cfcb1784e4@hartkopp.net \
--to=socketcan@hartkopp.net \
--cc=davem@davemloft.net \
--cc=kernel@pengutronix.de \
--cc=kuba@kernel.org \
--cc=kurt.van.dijck@eia.be \
--cc=linux-can@vger.kernel.org \
--cc=mkl@pengutronix.de \
--cc=netdev-bot+sashiko@kernel.org \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox