From: Marc Kleine-Budde <mkl@pengutronix.de>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, kuba@kernel.org, linux-can@vger.kernel.org,
kernel@pengutronix.de, Oliver Hartkopp <socketcan@hartkopp.net>,
stable@vger.kernel.org, Marc Kleine-Budde <mkl@pengutronix.de>
Subject: [PATCH net 8/9] can: bcm: use a private mutex instead of lock_sock()
Date: Sun, 15 Nov 2026 10:54:59 +0100 [thread overview]
Message-ID: <20261115095746.709371-9-mkl@pengutronix.de> (raw)
In-Reply-To: <20261115095746.709371-1-mkl@pengutronix.de>
From: Oliver Hartkopp <socketcan@hartkopp.net>
bcm_notify() takes lock_sock() of every CAN_BCM socket in the namespace
of a vanishing CAN device while holding RTNL. Any path that holds the
socket lock while accessing user space can therefore block RTNL. With
"can: bcm: copy the CAN frames outside of lock_sock()" the CAN frames
of bcm_sendmsg() are copied outside of the socket lock, but the generic
SOL_SOCKET options in sk_setsockopt() and sk_getsockopt() still access
user space under sockopt_lock_sock(), e.g. for SO_ATTACH_FILTER,
SO_LINGER or SO_TXTIME.
CAN_BCM only uses lock_sock() to serialize the binding and the bcm_op
lists. It does not use the socket backlog, as the BCM messages are
queued directly to the socket.
Replace lock_sock() with the mutex conf_lock in struct bcm_sock. The
generic socket options do not take this mutex, so they can not block
bcm_notify() anymore. No user space access happens while the mutex is
held. The memory allocations for the bcm_ops and the CAN receivers are
still done under the mutex, as they have been under lock_sock() before.
bcm_release() removes the procfs entry before taking the mutex, as
remove_proc_entry() waits for readers that may stall in their copy to
user space. The socket has already left the notifier list at this
point.
Fixes: ffd980f976e7 ("[CAN]: Add broadcast manager (bcm) protocol")
Cc: stable@vger.kernel.org # depends on "can: bcm: copy the CAN frames outside of lock_sock()"
Tested-by: Oliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261113-can-bcmlock-memcg-v5-5-634c0e04bc72@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/bcm.c | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 1595b7720c98..dc9e2890490a 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -145,6 +145,7 @@ struct bcm_sock {
unsigned long dropped_usr_msgs;
struct proc_dir_entry *bcm_proc_read;
char procname [32]; /* inode number in decimal with \0 */
+ struct mutex conf_lock; /* protects bind and the bcm_op lists */
};
static LIST_HEAD(bcm_notifier_list);
@@ -1673,8 +1674,8 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
if ((size - MHSIZ) % cfsiz)
return -EINVAL;
- /* Copy the CAN frames from user space before lock_sock(), so a
- * stalled copy can not block bcm_notify() waiting for lock_sock()
+ /* Copy the CAN frames from user space before taking bo->conf_lock, so a
+ * stalled copy can not block bcm_notify() waiting for bo->conf_lock
* under RTNL. Only the frames the opcode handler reads are copied.
* The handlers keep their checks and read the frames from fmsg.
*/
@@ -1714,12 +1715,12 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
kv.iov_len = flen;
iov_iter_kvec(&fmsg.msg_iter, ITER_SOURCE, &kv, 1, flen);
- lock_sock(sk);
+ mutex_lock(&bo->conf_lock);
- /* Re-validate under the socket lock: a concurrent bcm_notify()
+ /* Re-validate under bo->conf_lock: a concurrent bcm_notify()
* may have unbound this socket (device removal) after the
* lockless fast-path check above. bo->ifindex is only ever
- * mutated under lock_sock(), so reading it here - instead of
+ * mutated under bo->conf_lock, so reading it here - instead of
* before taking the lock - guarantees it can't be observed
* torn against bo->bound.
*/
@@ -1819,7 +1820,7 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
}
out_release:
- release_sock(sk);
+ mutex_unlock(&bo->conf_lock);
out_free:
if (frames != &sframe)
kvfree(frames);
@@ -1843,7 +1844,7 @@ static void bcm_notify(struct bcm_sock *bo, unsigned long msg,
switch (msg) {
case NETDEV_UNREGISTER:
- lock_sock(sk);
+ mutex_lock(&bo->conf_lock);
/* rx_ops: remove device specific receive entries */
list_for_each_entry(op, &bo->rx_ops, list) {
@@ -1877,7 +1878,7 @@ static void bcm_notify(struct bcm_sock *bo, unsigned long msg,
notify_enodev = 1;
}
- release_sock(sk);
+ mutex_unlock(&bo->conf_lock);
if (notify_enodev) {
sk->sk_err = ENODEV;
@@ -1930,6 +1931,7 @@ static int bcm_init(struct sock *sk)
bo->ifindex = 0;
bo->dropped_usr_msgs = 0;
bo->bcm_proc_read = NULL;
+ mutex_init(&bo->conf_lock);
INIT_LIST_HEAD(&bo->tx_ops);
INIT_LIST_HEAD(&bo->rx_ops);
@@ -1969,15 +1971,14 @@ static int bcm_release(struct socket *sock)
list_del(&bo->notifier);
spin_unlock(&bcm_notifier_lock);
- /* bcm_notify() can not access this socket anymore */
- lock_sock(sk);
-
#if IS_ENABLED(CONFIG_PROC_FS)
/* remove procfs entry */
if (net->can.bcmproc_dir && bo->bcm_proc_read)
remove_proc_entry(bo->procname, net->can.bcmproc_dir);
#endif /* CONFIG_PROC_FS */
+ mutex_lock(&bo->conf_lock);
+
list_for_each_entry_safe(op, next, &bo->tx_ops, list) {
list_del_rcu(&op->list);
bcm_remove_op(op);
@@ -2012,10 +2013,11 @@ static int bcm_release(struct socket *sock)
WRITE_ONCE(bo->ifindex, 0);
}
+ mutex_unlock(&bo->conf_lock);
+
sock_orphan(sk);
sock->sk = NULL;
- release_sock(sk);
sock_prot_inuse_add(net, sk->sk_prot, -1);
sock_put(sk);
@@ -2034,7 +2036,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
if (len < BCM_MIN_NAMELEN)
return -EINVAL;
- lock_sock(sk);
+ mutex_lock(&bo->conf_lock);
if (bo->bound) {
ret = -EISCONN;
@@ -2086,7 +2088,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int
WRITE_ONCE(bo->bound, 1);
fail:
- release_sock(sk);
+ mutex_unlock(&bo->conf_lock);
return ret;
}
--
2.53.0
next prev parent reply other threads:[~2026-11-15 9:57 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-15 9:54 [PATCH net 0/9] pull-request: can 2026-11-15 Marc Kleine-Budde
2026-11-15 9:54 ` [PATCH net 1/9] can: bcm: copy the CAN frames outside of lock_sock() Marc Kleine-Budde
2026-11-15 9:54 ` [PATCH net 2/9] can: bcm: do not remove the procfs entry in bcm_notify() Marc Kleine-Budde
2026-11-15 9:54 ` [PATCH net 3/9] can: netlink: fix static FD-NON-ISO mode validation Marc Kleine-Budde
2026-11-15 9:54 ` [PATCH net 4/9] can: raw: use a private mutex instead of lock_sock() Marc Kleine-Budde
2026-11-15 9:54 ` [PATCH net 5/9] can: netlink: fix IFLA_CAN_BITRATE_MAX attribute sizing Marc Kleine-Budde
2026-11-15 9:54 ` [PATCH net 6/9] can: isotp: use a private mutex instead of lock_sock() Marc Kleine-Budde
2026-11-15 9:54 ` [PATCH net 7/9] can: netlink: fix CAN XL PWM attribute sizing Marc Kleine-Budde
2026-11-15 9:54 ` Marc Kleine-Budde [this message]
2026-11-15 9:55 ` [PATCH net 9/9] can: gs_usb: gs_can_start_xmit(): don't leak uninitialized memory over USB Marc Kleine-Budde
2026-11-15 10:18 ` [PATCH net 0/9] pull-request: can 2026-11-15 Marc Kleine-Budde
2026-11-15 11:23 ` Oliver Hartkopp
2026-11-15 11:55 ` Marc Kleine-Budde
2026-11-15 20:10 ` netdev-bot+sinfo
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=20261115095746.709371-9-mkl@pengutronix.de \
--to=mkl@pengutronix.de \
--cc=davem@davemloft.net \
--cc=kernel@pengutronix.de \
--cc=kuba@kernel.org \
--cc=linux-can@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=socketcan@hartkopp.net \
--cc=stable@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