Re: [PATCH v13 02/11] can: bcm: fix lockless bound/ifindex race and silent RX_SETUP failure

Oliver Hartkopp <[email protected]>
Newsgroups org.kernel.vger.linux-can,dev.linux.lists.sashiko-reviews
Message-ID <[email protected]>

On 14.07.26 12:33, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> 
> Pre-existing issues:
> - [High] Unsafe lockless iteration of `bo->tx_ops` and `bo->rx_ops` in procfs, using `list_add()` instead of `list_add_rcu()` for list updates and `list_for_each_entry()` instead of `list_for_each_entry_rcu()`.
> - [High] `bcm_rx_setup()` modifies an active `rx_op`'s data and state from process context without any synchronization with `bcm_rx_handler()` running in softirq context.
> - [High] `bcm_tx_setup()` modifies an active `tx_op`'s frames and flags without holding `bcm_tx_lock`, racing with the softirq timer and transmission paths.
> --
> 

Fixed later.

> --- Patch [2]: [PATCH v13 02/11] can: bcm: fix lockless bound/ifindex race and silent RX_SETUP failure ---
> commit 79233a73945b83eac56e8c17536d2f019c104f50
> Author: Oliver Hartkopp <[email protected]>
> 
>      can: bcm: fix lockless bound/ifindex race and silent RX_SETUP failure
>      
>      bcm_sendmsg() reads bo->ifindex and checks bo->bound before taking
>      lock_sock(), while bcm_notify(), bcm_connect() and bcm_release() all
>      mutate both fields under that same lock. Because the lockless reads
>      and the locked writes are unordered with respect to each other, a
>      racing bcm_notify() (device unregister) or bcm_connect() (concurrent
>      bind on another thread sharing the socket) can make bcm_sendmsg()
>      observe an inconsistent combination, e.g. a stale bound=1 together
>      with the now-cleared ifindex=0, silently turning a socket bound to a
>      specific CAN interface into one that also matches "any" interface.
> 
>      Link: https://lore.kernel.org/linux-can/CAGp+u1aBK8QVjsvAxM2Ldzep4rEbsP9x_pV3At4g=h1kVEtyhA@mail.gmail.com/
> 
>> diff --git a/net/can/bcm.c b/net/can/bcm.c
>> index bdf53241bd7b3..b612135b017d1 100644
>> --- a/net/can/bcm.c
>> +++ b/net/can/bcm.c
>> @@ -1323,6 +1323,11 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
>>   
>>   				op->rx_reg_dev = dev;
>>   				dev_put(dev);
>> +			} else {
>> +				/* the requested device is gone - do not
>> +				 * silently succeed without registering
>> +				 */
>> +				err = -ENODEV;
>>   			}
>>   
>>   		} else
> 
> [Severity: High]
> This isn't a bug introduced by this patch, but does bcm_rx_setup() safely
> modify an active rx_op's data and state from process context without
> synchronization with bcm_rx_handler() running in softirq context?
> 
> bcm_rx_setup() directly overwrites op->frames via memcpy_from_msg() and
> clears op->last_frames while only holding lock_sock(sk):
> 
> net/can/bcm.c:bcm_rx_setup() {
>      ...
>      err = memcpy_from_msg(op->frames, msg, msg_head->nframes * op->cfsiz);
>      ...
> }
> 
> Concurrently, bcm_rx_handler() executes locklessly in the softirq RX path
> and reads these frames:
> 
> net/can/bcm.c:bcm_rx_handler() {
>      ...
>      if ((get_u64(op->frames, 0) & get_u64(rxframe, 0)) == ...
>      ...
> }
> 
> Since memcpy_from_msg() copies from userspace and can block or be preempted,
> could the softirq observe partially updated frames, mismatched lengths, or
> torn flags, leading to incorrect CAN message filtering and potential data
> corruption?
> 
> [ ... ]
>> @@ -1436,20 +1463,21 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
>>   			struct net_device *dev;
>>   
>>   			dev = dev_get_by_index(sock_net(sk), ifindex);
>> -			if (!dev)
>> -				return -ENODEV;
>> +			if (!dev) {
>> +				ret = -ENODEV;
>> +				goto out_release;
>> +			}
>>   
>>   			if (dev->type != ARPHRD_CAN) {
>>   				dev_put(dev);
>> -				return -ENODEV;
>> +				ret = -ENODEV;
>> +				goto out_release;
>>   			}
>>   
>>   			dev_put(dev);
>>   		}
>>   	}
>>   
>> -	lock_sock(sk);
>> -
>>   	switch (msg_head.opcode) {
>>   
>>   	case TX_SETUP:
> 
> [Severity: High]
> This is a pre-existing issue, but does bcm_tx_setup() modify an active
> tx_op's frames and flags without holding bcm_tx_lock, racing with the softirq
> timer and transmission paths?
> 
> When updating an existing tx op, bcm_tx_setup() calls memcpy_from_msg() to
> update op->frames before acquiring bcm_tx_lock:
> 
> net/can/bcm.c:bcm_tx_setup() {
>      ...
>      err = memcpy_from_msg((u8 *)cf, msg, op->cfsiz);
>      ...
> }
> 
> Meanwhile, bcm_can_tx() drops the lock and calls skb_put_data() to copy the
> frame into an skb:
> 
> net/can/bcm.c:bcm_can_tx() {
>      ...
>      skb_put_data(skb, cf, op->cfsiz);
>      ...
> }
> 
> Could this data race allow the softirq to transmit partially updated CAN
> frames onto the bus? Because memcpy_from_msg() accesses userspace and might
> block, the race window appears wide enough to result in deterministic
> corruption of transmitted frames under concurrent updates.
> 
> [Severity: High]
> This is also a pre-existing issue, but is it safe for bcm_proc_show() to
> iterate over bo->tx_ops and bo->rx_ops locklessly in procfs, while
> bcm_tx_setup() and bcm_rx_setup() use list_add() instead of list_add_rcu()?
> 
> bcm_tx_setup() and bcm_rx_setup() insert new operations using the plain
> list_add() macro, which lacks the smp_store_release() memory barrier:
> 
> net/can/bcm.c:bcm_tx_setup() {
>      ...
>      list_add(&op->list, &bo->tx_ops);
>      ...
> }
> 
> bcm_proc_show() traverses tx_ops locklessly under rcu_read_lock(), but uses
> the unsafe list_for_each_entry() macro entirely bypassing RCU read primitives:
> 
> net/can/bcm.c:bcm_proc_show() {
>      ...
>      list_for_each_entry(op, &bo->tx_ops, list) {
>      ...
> }
> 
> Could a concurrent procfs reader observe the list pointer before the bcm_op
> structure is fully visible in memory, causing a dereference of uninitialized
> memory or a crash?
> 
>>   		ret = bcm_tx_setup(&msg_head, msg, ifindex, sk);
>>   		break;
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.