summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleksij Rempel <o.rempel@pengutronix.de>2020-08-07 12:51:57 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-08-26 10:40:50 +0200
commit60be1488a3ae1350c0f629ef7956d9192cf6cba9 (patch)
tree58b261f2c902fa0fc51e3fe4b621ce7754606a85
parent055c65c7e7dd0fd8061669f5df908ccf228b7ad3 (diff)
downloadlinux-stable-60be1488a3ae1350c0f629ef7956d9192cf6cba9.tar.gz
linux-stable-60be1488a3ae1350c0f629ef7956d9192cf6cba9.tar.bz2
linux-stable-60be1488a3ae1350c0f629ef7956d9192cf6cba9.zip
can: j1939: transport: j1939_session_tx_dat(): fix use-after-free read in j1939_tp_txtimer()
commit cd3b3636c99fcac52c598b64061f3fe4413c6a12 upstream. The current stack implementation do not support ECTS requests of not aligned TP sized blocks. If ECTS will request a block with size and offset spanning two TP blocks, this will cause memcpy() to read beyond the queued skb (which does only contain one TP sized block). Sometimes KASAN will detect this read if the memory region beyond the skb was previously allocated and freed. In other situations it will stay undetected. The ETP transfer in any case will be corrupted. This patch adds a sanity check to avoid this kind of read and abort the session with error J1939_XTP_ABORT_ECTS_TOO_BIG. Reported-by: syzbot+5322482fe520b02aea30@syzkaller.appspotmail.com Fixes: 9d71dd0c7009 ("can: add support of SAE J1939 protocol") Cc: linux-stable <stable@vger.kernel.org> # >= v5.4 Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Link: https://lore.kernel.org/r/20200807105200.26441-3-o.rempel@pengutronix.de Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--net/can/j1939/transport.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
index 9f99af5b0b11..5bfe6bf15a99 100644
--- a/net/can/j1939/transport.c
+++ b/net/can/j1939/transport.c
@@ -787,6 +787,18 @@ static int j1939_session_tx_dat(struct j1939_session *session)
if (len > 7)
len = 7;
+ if (offset + len > se_skb->len) {
+ netdev_err_once(priv->ndev,
+ "%s: 0x%p: requested data outside of queued buffer: offset %i, len %i, pkt.tx: %i\n",
+ __func__, session, skcb->offset, se_skb->len , session->pkt.tx);
+ return -EOVERFLOW;
+ }
+
+ if (!len) {
+ ret = -ENOBUFS;
+ break;
+ }
+
memcpy(&dat[1], &tpdat[offset], len);
ret = j1939_tp_tx_dat(session, dat, len + 1);
if (ret < 0) {
@@ -1120,6 +1132,9 @@ static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer)
* cleanup including propagation of the error to user space.
*/
break;
+ case -EOVERFLOW:
+ j1939_session_cancel(session, J1939_XTP_ABORT_ECTS_TOO_BIG);
+ break;
case 0:
session->tx_retry = 0;
break;