Skip to content

Commit c614576

Browse files
committed
can: isotp: fix potential CAN frame reception race in isotp_rcv()
JIRA: https://issues.redhat.com/browse/RHEL-80832 commit 7c75904 Author: Oliver Hartkopp <socketcan@hartkopp.net> Date: Tue Feb 8 21:00:26 2022 +0100 can: isotp: fix potential CAN frame reception race in isotp_rcv() When receiving a CAN frame the current code logic does not consider concurrently receiving processes which do not show up in real world usage. Ziyang Xuan writes: The following syz problem is one of the scenarios. so->rx.len is changed by isotp_rcv_ff() during isotp_rcv_cf(), so->rx.len equals 0 before alloc_skb() and equals 4096 after alloc_skb(). That will trigger skb_over_panic() in skb_put(). ======================================================= CPU: 1 PID: 19 Comm: ksoftirqd/1 Not tainted 5.16.0-rc8-syzkaller #0 RIP: 0010:skb_panic+0x16c/0x16e net/core/skbuff.c:113 Call Trace: <TASK> skb_over_panic net/core/skbuff.c:118 [inline] skb_put.cold+0x24/0x24 net/core/skbuff.c:1990 isotp_rcv_cf net/can/isotp.c:570 [inline] isotp_rcv+0xa38/0x1e30 net/can/isotp.c:668 deliver net/can/af_can.c:574 [inline] can_rcv_filter+0x445/0x8d0 net/can/af_can.c:635 can_receive+0x31d/0x580 net/can/af_can.c:665 can_rcv+0x120/0x1c0 net/can/af_can.c:696 __netif_receive_skb_one_core+0x114/0x180 net/core/dev.c:5465 __netif_receive_skb+0x24/0x1b0 net/core/dev.c:5579 Therefore we make sure the state changes and data structures stay consistent at CAN frame reception time by adding a spin_lock in isotp_rcv(). This fixes the issue reported by syzkaller but does not affect real world operation. Fixes: e057dd3 ("can: add ISO 15765-2:2016 transport protocol") Link: https://lore.kernel.org/linux-can/d7e69278-d741-c706-65e1-e87623d9a8e8@huawei.com/T/ Link: https://lore.kernel.org/all/20220208200026.13783-1-socketcan@hartkopp.net Cc: stable@vger.kernel.org Reported-by: syzbot+4c63f36709a642f801c5@syzkaller.appspotmail.com Reported-by: Ziyang Xuan <william.xuanziyang@huawei.com> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Radu Rendec <rrendec@redhat.com>
1 parent 14b89c2 commit c614576

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

net/can/isotp.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include <linux/module.h>
5656
#include <linux/init.h>
5757
#include <linux/interrupt.h>
58+
#include <linux/spinlock.h>
5859
#include <linux/hrtimer.h>
5960
#include <linux/wait.h>
6061
#include <linux/uio.h>
@@ -150,6 +151,7 @@ struct isotp_sock {
150151
struct tpcon rx, tx;
151152
struct list_head notifier;
152153
wait_queue_head_t wait;
154+
spinlock_t rx_lock; /* protect single thread state machine */
153155
};
154156

155157
static LIST_HEAD(isotp_notifier_list);
@@ -641,11 +643,17 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
641643

642644
n_pci_type = cf->data[ae] & 0xF0;
643645

646+
/* Make sure the state changes and data structures stay consistent at
647+
* CAN frame reception time. This locking is not needed in real world
648+
* use cases but the inconsistency can be triggered with syzkaller.
649+
*/
650+
spin_lock(&so->rx_lock);
651+
644652
if (so->opt.flags & CAN_ISOTP_HALF_DUPLEX) {
645653
/* check rx/tx path half duplex expectations */
646654
if ((so->tx.state != ISOTP_IDLE && n_pci_type != N_PCI_FC) ||
647655
(so->rx.state != ISOTP_IDLE && n_pci_type == N_PCI_FC))
648-
return;
656+
goto out_unlock;
649657
}
650658

651659
switch (n_pci_type) {
@@ -694,6 +702,9 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
694702
isotp_rcv_cf(sk, cf, ae, skb);
695703
break;
696704
}
705+
706+
out_unlock:
707+
spin_unlock(&so->rx_lock);
697708
}
698709

699710
static void isotp_fill_dataframe(struct canfd_frame *cf, struct isotp_sock *so,
@@ -1589,6 +1600,7 @@ static int isotp_init(struct sock *sk)
15891600
so->txtimer.function = isotp_tx_timer_handler;
15901601

15911602
init_waitqueue_head(&so->wait);
1603+
spin_lock_init(&so->rx_lock);
15921604

15931605
spin_lock(&isotp_notifier_lock);
15941606
list_add_tail(&so->notifier, &isotp_notifier_list);

0 commit comments

Comments
 (0)