Skip to content

Commit b97ee72

Browse files
committed
Merge tag 'linux-can-fixes-for-6.3-20230405' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can
Marc Kleine-Budde says: ==================== pull-request: can 2023-04-05 The first patch is by Oleksij Rempel and fixes a out-of-bounds memory access in the j1939 protocol. The remaining 3 patches target the ISOTP protocol. Oliver Hartkopp fixes the ISOTP protocol to pass information about dropped PDUs to the user space via control messages. Michal Sojka's patch fixes poll() to not forward false EPOLLOUT events. And Oliver Hartkopp fixes a race condition between isotp_sendsmg() and isotp_release(). * tag 'linux-can-fixes-for-6.3-20230405' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can: can: isotp: fix race between isotp_sendsmg() and isotp_release() can: isotp: isotp_ops: fix poll() to not report false EPOLLOUT events can: isotp: isotp_recvmsg(): use sock_recv_cmsgs() to get SOCK_RXQ_OVFL infos can: j1939: j1939_tp_tx_dat_new(): fix out-of-bounds memory access ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 4181b39 + 0517374 commit b97ee72

File tree

2 files changed

+52
-27
lines changed

2 files changed

+52
-27
lines changed

net/can/isotp.c

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ enum {
119119
ISOTP_WAIT_FIRST_FC,
120120
ISOTP_WAIT_FC,
121121
ISOTP_WAIT_DATA,
122-
ISOTP_SENDING
122+
ISOTP_SENDING,
123+
ISOTP_SHUTDOWN,
123124
};
124125

125126
struct tpcon {
@@ -880,8 +881,8 @@ static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
880881
txtimer);
881882
struct sock *sk = &so->sk;
882883

883-
/* don't handle timeouts in IDLE state */
884-
if (so->tx.state == ISOTP_IDLE)
884+
/* don't handle timeouts in IDLE or SHUTDOWN state */
885+
if (so->tx.state == ISOTP_IDLE || so->tx.state == ISOTP_SHUTDOWN)
885886
return HRTIMER_NORESTART;
886887

887888
/* we did not get any flow control or echo frame in time */
@@ -918,7 +919,6 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
918919
{
919920
struct sock *sk = sock->sk;
920921
struct isotp_sock *so = isotp_sk(sk);
921-
u32 old_state = so->tx.state;
922922
struct sk_buff *skb;
923923
struct net_device *dev;
924924
struct canfd_frame *cf;
@@ -928,23 +928,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
928928
int off;
929929
int err;
930930

931-
if (!so->bound)
931+
if (!so->bound || so->tx.state == ISOTP_SHUTDOWN)
932932
return -EADDRNOTAVAIL;
933933

934+
wait_free_buffer:
934935
/* we do not support multiple buffers - for now */
935-
if (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE ||
936-
wq_has_sleeper(&so->wait)) {
937-
if (msg->msg_flags & MSG_DONTWAIT) {
938-
err = -EAGAIN;
939-
goto err_out;
940-
}
936+
if (wq_has_sleeper(&so->wait) && (msg->msg_flags & MSG_DONTWAIT))
937+
return -EAGAIN;
941938

942-
/* wait for complete transmission of current pdu */
943-
err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
944-
if (err)
945-
goto err_out;
939+
/* wait for complete transmission of current pdu */
940+
err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
941+
if (err)
942+
goto err_event_drop;
946943

947-
so->tx.state = ISOTP_SENDING;
944+
if (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) {
945+
if (so->tx.state == ISOTP_SHUTDOWN)
946+
return -EADDRNOTAVAIL;
947+
948+
goto wait_free_buffer;
948949
}
949950

950951
if (!size || size > MAX_MSG_LENGTH) {
@@ -1074,21 +1075,25 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
10741075

10751076
if (wait_tx_done) {
10761077
/* wait for complete transmission of current pdu */
1077-
wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
1078+
err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
1079+
if (err)
1080+
goto err_event_drop;
10781081

10791082
if (sk->sk_err)
10801083
return -sk->sk_err;
10811084
}
10821085

10831086
return size;
10841087

1088+
err_event_drop:
1089+
/* got signal: force tx state machine to be idle */
1090+
so->tx.state = ISOTP_IDLE;
1091+
hrtimer_cancel(&so->txfrtimer);
1092+
hrtimer_cancel(&so->txtimer);
10851093
err_out_drop:
10861094
/* drop this PDU and unlock a potential wait queue */
1087-
old_state = ISOTP_IDLE;
1088-
err_out:
1089-
so->tx.state = old_state;
1090-
if (so->tx.state == ISOTP_IDLE)
1091-
wake_up_interruptible(&so->wait);
1095+
so->tx.state = ISOTP_IDLE;
1096+
wake_up_interruptible(&so->wait);
10921097

10931098
return err;
10941099
}
@@ -1120,7 +1125,7 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
11201125
if (ret < 0)
11211126
goto out_err;
11221127

1123-
sock_recv_timestamp(msg, sk, skb);
1128+
sock_recv_cmsgs(msg, sk, skb);
11241129

11251130
if (msg->msg_name) {
11261131
__sockaddr_check_size(ISOTP_MIN_NAMELEN);
@@ -1150,10 +1155,12 @@ static int isotp_release(struct socket *sock)
11501155
net = sock_net(sk);
11511156

11521157
/* wait for complete transmission of current pdu */
1153-
wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
1158+
while (wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0 &&
1159+
cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SHUTDOWN) != ISOTP_IDLE)
1160+
;
11541161

11551162
/* force state machines to be idle also when a signal occurred */
1156-
so->tx.state = ISOTP_IDLE;
1163+
so->tx.state = ISOTP_SHUTDOWN;
11571164
so->rx.state = ISOTP_IDLE;
11581165

11591166
spin_lock(&isotp_notifier_lock);
@@ -1608,6 +1615,21 @@ static int isotp_init(struct sock *sk)
16081615
return 0;
16091616
}
16101617

1618+
static __poll_t isotp_poll(struct file *file, struct socket *sock, poll_table *wait)
1619+
{
1620+
struct sock *sk = sock->sk;
1621+
struct isotp_sock *so = isotp_sk(sk);
1622+
1623+
__poll_t mask = datagram_poll(file, sock, wait);
1624+
poll_wait(file, &so->wait, wait);
1625+
1626+
/* Check for false positives due to TX state */
1627+
if ((mask & EPOLLWRNORM) && (so->tx.state != ISOTP_IDLE))
1628+
mask &= ~(EPOLLOUT | EPOLLWRNORM);
1629+
1630+
return mask;
1631+
}
1632+
16111633
static int isotp_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd,
16121634
unsigned long arg)
16131635
{
@@ -1623,7 +1645,7 @@ static const struct proto_ops isotp_ops = {
16231645
.socketpair = sock_no_socketpair,
16241646
.accept = sock_no_accept,
16251647
.getname = isotp_getname,
1626-
.poll = datagram_poll,
1648+
.poll = isotp_poll,
16271649
.ioctl = isotp_sock_no_ioctlcmd,
16281650
.gettstamp = sock_gettstamp,
16291651
.listen = sock_no_listen,

net/can/j1939/transport.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,10 @@ sk_buff *j1939_tp_tx_dat_new(struct j1939_priv *priv,
604604
/* reserve CAN header */
605605
skb_reserve(skb, offsetof(struct can_frame, data));
606606

607-
memcpy(skb->cb, re_skcb, sizeof(skb->cb));
607+
/* skb->cb must be large enough to hold a j1939_sk_buff_cb structure */
608+
BUILD_BUG_ON(sizeof(skb->cb) < sizeof(*re_skcb));
609+
610+
memcpy(skb->cb, re_skcb, sizeof(*re_skcb));
608611
skcb = j1939_skb_to_cb(skb);
609612
if (swap_src_dst)
610613
j1939_skbcb_swap(skcb);

0 commit comments

Comments
 (0)