Commit 8375dfac authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by Marc Kleine-Budde

can: isotp: fix error path in isotp_sendmsg() to unlock wait queue

Commit 43a08c3b ("can: isotp: isotp_sendmsg(): fix TX buffer concurrent
access in isotp_sendmsg()") introduced a new locking scheme that may render
the userspace application in a locking state when an error is detected.
This issue shows up under high load on simultaneously running isotp channels
with identical configuration which is against the ISO specification and
therefore breaks any reasonable PDU communication anyway.

Fixes: 43a08c3b ("can: isotp: isotp_sendmsg(): fix TX buffer concurrent access in isotp_sendmsg()")
Link: https://lore.kernel.org/all/20220209073601.25728-1-socketcan@hartkopp.net
Cc: stable@vger.kernel.org
Cc: Ziyang Xuan <william.xuanziyang@huawei.com>
Signed-off-by: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 7c759040
...@@ -887,7 +887,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -887,7 +887,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
if (!size || size > MAX_MSG_LENGTH) { if (!size || size > MAX_MSG_LENGTH) {
err = -EINVAL; err = -EINVAL;
goto err_out; goto err_out_drop;
} }
/* take care of a potential SF_DL ESC offset for TX_DL > 8 */ /* take care of a potential SF_DL ESC offset for TX_DL > 8 */
...@@ -897,24 +897,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -897,24 +897,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
if ((so->opt.flags & CAN_ISOTP_SF_BROADCAST) && if ((so->opt.flags & CAN_ISOTP_SF_BROADCAST) &&
(size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) { (size > so->tx.ll_dl - SF_PCI_SZ4 - ae - off)) {
err = -EINVAL; err = -EINVAL;
goto err_out; goto err_out_drop;
} }
err = memcpy_from_msg(so->tx.buf, msg, size); err = memcpy_from_msg(so->tx.buf, msg, size);
if (err < 0) if (err < 0)
goto err_out; goto err_out_drop;
dev = dev_get_by_index(sock_net(sk), so->ifindex); dev = dev_get_by_index(sock_net(sk), so->ifindex);
if (!dev) { if (!dev) {
err = -ENXIO; err = -ENXIO;
goto err_out; goto err_out_drop;
} }
skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv), skb = sock_alloc_send_skb(sk, so->ll.mtu + sizeof(struct can_skb_priv),
msg->msg_flags & MSG_DONTWAIT, &err); msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb) { if (!skb) {
dev_put(dev); dev_put(dev);
goto err_out; goto err_out_drop;
} }
can_skb_reserve(skb); can_skb_reserve(skb);
...@@ -976,7 +976,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -976,7 +976,7 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
if (err) { if (err) {
pr_notice_once("can-isotp: %s: can_send_ret %pe\n", pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
__func__, ERR_PTR(err)); __func__, ERR_PTR(err));
goto err_out; goto err_out_drop;
} }
if (wait_tx_done) { if (wait_tx_done) {
...@@ -989,6 +989,9 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) ...@@ -989,6 +989,9 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
return size; return size;
err_out_drop:
/* drop this PDU and unlock a potential wait queue */
old_state = ISOTP_IDLE;
err_out: err_out:
so->tx.state = old_state; so->tx.state = old_state;
if (so->tx.state == ISOTP_IDLE) if (so->tx.state == ISOTP_IDLE)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment