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 1/9] can: bcm: copy the CAN frames outside of lock_sock()
Date: Sun, 15 Nov 2026 10:54:52 +0100 [thread overview]
Message-ID: <20261115095746.709371-2-mkl@pengutronix.de> (raw)
In-Reply-To: <20261115095746.709371-1-mkl@pengutronix.de>
From: Oliver Hartkopp <socketcan@hartkopp.net>
bcm_sendmsg() copies the CAN frames of TX_SETUP, RX_SETUP and TX_SEND
from user space while holding lock_sock(). A copy that faults or
stalls, e.g. on a FUSE backed mapping, holds lock_sock() for its whole
duration.
bcm_notify() takes lock_sock() of every CAN_BCM socket in the namespace
of a vanishing CAN device while holding RTNL, independent of the
binding of the socket. So a stalled copy on any CAN_BCM socket can
block RTNL on the unregistration or namespace change of a CAN device in
this namespace, e.g. of a vcan device in an unprivileged user and
network namespace.
Copy the CAN frames that the opcode handler reads to kernel memory
before lock_sock() and hand them to the handlers with a kvec based
msghdr. bcm_tx_setup(), bcm_rx_setup() and bcm_tx_send() keep their
checks and read the frames with memcpy_from_msg() as before. Up to
sizeof(struct canfd_frame) bytes, i.e. a single CAN FD frame or up to
four CAN CC frames, are copied to a buffer on the stack, more frames to
a kvmalloc() buffer of up to MAX_NFRAMES + 1 CAN FD frames.
As the frames are copied before lock_sock() now, a failing copy is
reported before the error conditions that are checked under
lock_sock(). This is in line with POSIX, which does not define an
order in which multiple error conditions are detected and reported.
The generic SOL_SOCKET options in sk_setsockopt() and sk_getsockopt(),
e.g. SO_ATTACH_FILTER, still access user space under the socket lock.
This is not specific to CAN_BCM and not addressed by this patch.
Fixes: ffd980f976e7 ("[CAN]: Add broadcast manager (bcm) protocol")
Cc: stable@vger.kernel.org
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20261113-can-bcmlock-memcg-v5-1-634c0e04bc72@hartkopp.net
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
net/can/bcm.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 52 insertions(+), 3 deletions(-)
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 7bd2aa39777a..3f4c8d828337 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1643,6 +1643,11 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
struct bcm_sock *bo = bcm_sk(sk);
int ifindex;
struct bcm_msg_head msg_head;
+ struct msghdr fmsg = {}; /* CAN frames copied to kernel memory */
+ struct kvec kv;
+ struct canfd_frame sframe; /* stack buffer for up to CANFD_MTU bytes */
+ void *frames = &sframe;
+ size_t flen = 0;
int cfsiz;
int ret; /* read bytes or error codes as return value */
@@ -1663,6 +1668,47 @@ 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()
+ * under RTNL. Only the frames the opcode handler reads are copied.
+ * The handlers keep their checks and read the frames from fmsg.
+ */
+ switch (msg_head.opcode) {
+ case TX_SETUP:
+ if (msg_head.nframes >= 1 && msg_head.nframes <= MAX_NFRAMES)
+ flen = msg_head.nframes * cfsiz;
+ break;
+
+ case RX_SETUP:
+ if (!(msg_head.flags & RX_FILTER_ID) &&
+ msg_head.nframes <= MAX_NFRAMES + 1)
+ flen = msg_head.nframes * cfsiz;
+ break;
+
+ case TX_SEND:
+ if (msg_head.nframes == 1 && size == cfsiz + MHSIZ)
+ flen = cfsiz;
+ break;
+ }
+
+ /* a message with missing frames still fails in the handler */
+ flen = min(flen, msg_data_left(msg));
+
+ if (flen > sizeof(sframe)) {
+ frames = kvmalloc(flen, GFP_KERNEL);
+ if (!frames)
+ return -ENOMEM;
+ }
+
+ if (!copy_from_iter_full(frames, flen, &msg->msg_iter)) {
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ kv.iov_base = frames;
+ kv.iov_len = flen;
+ iov_iter_kvec(&fmsg.msg_iter, ITER_SOURCE, &kv, 1, flen);
+
lock_sock(sk);
/* Re-validate under the socket lock: a concurrent bcm_notify()
@@ -1721,11 +1767,11 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
switch (msg_head.opcode) {
case TX_SETUP:
- ret = bcm_tx_setup(&msg_head, msg, ifindex, sk);
+ ret = bcm_tx_setup(&msg_head, &fmsg, ifindex, sk);
break;
case RX_SETUP:
- ret = bcm_rx_setup(&msg_head, msg, ifindex, sk);
+ ret = bcm_rx_setup(&msg_head, &fmsg, ifindex, sk);
break;
case TX_DELETE:
@@ -1759,7 +1805,7 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
if ((msg_head.nframes != 1) || (size != cfsiz + MHSIZ))
ret = -EINVAL;
else
- ret = bcm_tx_send(msg, ifindex, sk, cfsiz);
+ ret = bcm_tx_send(&fmsg, ifindex, sk, cfsiz);
break;
default:
@@ -1769,6 +1815,9 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
out_release:
release_sock(sk);
+out_free:
+ if (frames != &sframe)
+ kvfree(frames);
return ret;
}
base-commit: aa40afa831ebfe45e40a23721711059f2ac584d4
--
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 ` Marc Kleine-Budde [this message]
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 ` [PATCH net 8/9] can: bcm: use a private mutex instead of lock_sock() Marc Kleine-Budde
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-2-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