linux-can.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/5] j1939 fixes
@ 2020-08-07 10:51 Oleksij Rempel
  2020-08-07 10:51 ` [PATCH v1 1/5] can: j1939: transport: j1939_simple_recv(): ignore local J1939 messages send not by J1939 stack Oleksij Rempel
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Oleksij Rempel @ 2020-08-07 10:51 UTC (permalink / raw)
  To: dev.kurt, mkl, wg; +Cc: Oleksij Rempel, kernel, linux-can, netdev, David Jander

This patch set include different fixes reported by google syzkaller or
other users.

Oleksij Rempel (5):
  can: j1939: transport: j1939_simple_recv(): ignore local J1939
    messages send not by J1939 stack
  can: j1939: transport: j1939_session_tx_dat(): fix use-after-free read
    in j1939_tp_txtimer()
  can: j1939: socket: j1939_sk_bind(): make sure ml_priv is allocated
  can: j1939: transport: add j1939_session_skb_find_by_offset() function
  can: j1939: transport: j1939_xtp_rx_dat_one(): compare own packets to
    detect corruptions

 net/can/j1939/socket.c    |  9 +++++++
 net/can/j1939/transport.c | 56 +++++++++++++++++++++++++++++++++------
 2 files changed, 57 insertions(+), 8 deletions(-)

-- 
2.28.0

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v1 1/5] can: j1939: transport: j1939_simple_recv(): ignore local J1939 messages send not by J1939 stack
  2020-08-07 10:51 [PATCH v1 0/5] j1939 fixes Oleksij Rempel
@ 2020-08-07 10:51 ` Oleksij Rempel
  2020-08-07 10:51 ` [PATCH v1 2/5] can: j1939: transport: j1939_session_tx_dat(): fix use-after-free read in j1939_tp_txtimer() Oleksij Rempel
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Oleksij Rempel @ 2020-08-07 10:51 UTC (permalink / raw)
  To: dev.kurt, mkl, wg; +Cc: Oleksij Rempel, kernel, linux-can, netdev, David Jander

In current J1939 stack implementation, we process all locally send
messages as own messages. Even if it was send by CAN_RAW socket.

To reproduce it use following commands:
testj1939 -P -r can0:0x80 &
cansend can0 18238040#0123

This step will trigger false positive not critical warning:
j1939_simple_recv: Received already invalidated message

With this patch we add additional check to make sure, related skb is own
echo message.

Fixes: 9d71dd0c7009 ("can: add support of SAE J1939 protocol")
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 net/can/j1939/socket.c    | 1 +
 net/can/j1939/transport.c | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c
index f7587428febd..b9a17c2ee16f 100644
--- a/net/can/j1939/socket.c
+++ b/net/can/j1939/socket.c
@@ -398,6 +398,7 @@ static int j1939_sk_init(struct sock *sk)
 	spin_lock_init(&jsk->sk_session_queue_lock);
 	INIT_LIST_HEAD(&jsk->sk_session_queue);
 	sk->sk_destruct = j1939_sk_sock_destruct;
+	sk->sk_protocol = CAN_J1939;
 
 	return 0;
 }
diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
index 9f99af5b0b11..b135c5e2a86e 100644
--- a/net/can/j1939/transport.c
+++ b/net/can/j1939/transport.c
@@ -2017,6 +2017,10 @@ void j1939_simple_recv(struct j1939_priv *priv, struct sk_buff *skb)
 	if (!skb->sk)
 		return;
 
+	if (skb->sk->sk_family != AF_CAN ||
+	    skb->sk->sk_protocol != CAN_J1939)
+		return;
+
 	j1939_session_list_lock(priv);
 	session = j1939_session_get_simple(priv, skb);
 	j1939_session_list_unlock(priv);
-- 
2.28.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 2/5] can: j1939: transport: j1939_session_tx_dat(): fix use-after-free read in j1939_tp_txtimer()
  2020-08-07 10:51 [PATCH v1 0/5] j1939 fixes Oleksij Rempel
  2020-08-07 10:51 ` [PATCH v1 1/5] can: j1939: transport: j1939_simple_recv(): ignore local J1939 messages send not by J1939 stack Oleksij Rempel
@ 2020-08-07 10:51 ` Oleksij Rempel
  2020-08-07 10:51 ` [PATCH v1 3/5] can: j1939: socket: j1939_sk_bind(): make sure ml_priv is allocated Oleksij Rempel
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Oleksij Rempel @ 2020-08-07 10:51 UTC (permalink / raw)
  To: dev.kurt, mkl, wg
  Cc: Oleksij Rempel, syzbot+5322482fe520b02aea30, linux-stable,
	kernel, linux-can, netdev, David Jander

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>
---
 net/can/j1939/transport.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
index b135c5e2a86e..30957c9a8eb7 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;
-- 
2.28.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 3/5] can: j1939: socket: j1939_sk_bind(): make sure ml_priv is allocated
  2020-08-07 10:51 [PATCH v1 0/5] j1939 fixes Oleksij Rempel
  2020-08-07 10:51 ` [PATCH v1 1/5] can: j1939: transport: j1939_simple_recv(): ignore local J1939 messages send not by J1939 stack Oleksij Rempel
  2020-08-07 10:51 ` [PATCH v1 2/5] can: j1939: transport: j1939_session_tx_dat(): fix use-after-free read in j1939_tp_txtimer() Oleksij Rempel
@ 2020-08-07 10:51 ` Oleksij Rempel
  2020-08-07 10:51 ` [PATCH v1 4/5] can: j1939: transport: add j1939_session_skb_find_by_offset() function Oleksij Rempel
  2020-08-07 10:52 ` [PATCH v1 5/5] can: j1939: transport: j1939_xtp_rx_dat_one(): compare own packets to detect corruptions Oleksij Rempel
  4 siblings, 0 replies; 6+ messages in thread
From: Oleksij Rempel @ 2020-08-07 10:51 UTC (permalink / raw)
  To: dev.kurt, mkl, wg
  Cc: Oleksij Rempel, syzbot+f03d384f3455d28833eb, linux-stable,
	kernel, linux-can, netdev, David Jander

This patch adds check to ensure that the struct net_device::ml_priv is
allocated, as it is used later by the j1939 stack.

The allocation is done by all mainline CAN network drivers, but when using
bond or team devices this is not the case.

Bail out if no ml_priv is allocated.

Reported-by: syzbot+f03d384f3455d28833eb@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>
---
 net/can/j1939/socket.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c
index b9a17c2ee16f..27542de233c7 100644
--- a/net/can/j1939/socket.c
+++ b/net/can/j1939/socket.c
@@ -467,6 +467,14 @@ static int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len)
 			goto out_release_sock;
 		}
 
+		if (!ndev->ml_priv) {
+			netdev_warn_once(ndev,
+					 "No CAN mid layer private allocated, please fix your driver and use alloc_candev()!\n");
+			dev_put(ndev);
+			ret = -ENODEV;
+			goto out_release_sock;
+		}
+
 		priv = j1939_netdev_start(ndev);
 		dev_put(ndev);
 		if (IS_ERR(priv)) {
-- 
2.28.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 4/5] can: j1939: transport: add j1939_session_skb_find_by_offset() function
  2020-08-07 10:51 [PATCH v1 0/5] j1939 fixes Oleksij Rempel
                   ` (2 preceding siblings ...)
  2020-08-07 10:51 ` [PATCH v1 3/5] can: j1939: socket: j1939_sk_bind(): make sure ml_priv is allocated Oleksij Rempel
@ 2020-08-07 10:51 ` Oleksij Rempel
  2020-08-07 10:52 ` [PATCH v1 5/5] can: j1939: transport: j1939_xtp_rx_dat_one(): compare own packets to detect corruptions Oleksij Rempel
  4 siblings, 0 replies; 6+ messages in thread
From: Oleksij Rempel @ 2020-08-07 10:51 UTC (permalink / raw)
  To: dev.kurt, mkl, wg
  Cc: Oleksij Rempel, Henrique Figueira, kernel, linux-can, netdev,
	David Jander

Sometimes it makes no sense to search the skb by pkt.dpo, since we need
next the skb within the transaction block. This may happen if we have an
ETP session with CTS set to less than 255 packets.

After this patch, we will be able to work with ETP sessions where the
block size (ETP.CM_CTS byte 2) is less than 255 packets.

Reported-by: Henrique Figueira <henrislip@gmail.com>
Reported-by: https://github.com/linux-can/can-utils/issues/228
Fixes: 9d71dd0c7009 ("can: add support of SAE J1939 protocol")
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 net/can/j1939/transport.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
index 30957c9a8eb7..90a2baac8a4a 100644
--- a/net/can/j1939/transport.c
+++ b/net/can/j1939/transport.c
@@ -352,17 +352,16 @@ void j1939_session_skb_queue(struct j1939_session *session,
 	skb_queue_tail(&session->skb_queue, skb);
 }
 
-static struct sk_buff *j1939_session_skb_find(struct j1939_session *session)
+static struct
+sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session,
+					  unsigned int offset_start)
 {
 	struct j1939_priv *priv = session->priv;
+	struct j1939_sk_buff_cb *do_skcb;
 	struct sk_buff *skb = NULL;
 	struct sk_buff *do_skb;
-	struct j1939_sk_buff_cb *do_skcb;
-	unsigned int offset_start;
 	unsigned long flags;
 
-	offset_start = session->pkt.dpo * 7;
-
 	spin_lock_irqsave(&session->skb_queue.lock, flags);
 	skb_queue_walk(&session->skb_queue, do_skb) {
 		do_skcb = j1939_skb_to_cb(do_skb);
@@ -382,6 +381,14 @@ static struct sk_buff *j1939_session_skb_find(struct j1939_session *session)
 	return skb;
 }
 
+static struct sk_buff *j1939_session_skb_find(struct j1939_session *session)
+{
+	unsigned int offset_start;
+
+	offset_start = session->pkt.dpo * 7;
+	return j1939_session_skb_find_by_offset(session, offset_start);
+}
+
 /* see if we are receiver
  * returns 0 for broadcasts, although we will receive them
  */
@@ -766,7 +773,7 @@ static int j1939_session_tx_dat(struct j1939_session *session)
 	int ret = 0;
 	u8 dat[8];
 
-	se_skb = j1939_session_skb_find(session);
+	se_skb = j1939_session_skb_find_by_offset(session, session->pkt.tx * 7);
 	if (!se_skb)
 		return -ENOBUFS;
 
@@ -1765,7 +1772,8 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
 			    __func__, session);
 		goto out_session_cancel;
 	}
-	se_skb = j1939_session_skb_find(session);
+
+	se_skb = j1939_session_skb_find_by_offset(session, packet * 7);
 	if (!se_skb) {
 		netdev_warn(priv->ndev, "%s: 0x%p: no skb found\n", __func__,
 			    session);
-- 
2.28.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v1 5/5] can: j1939: transport: j1939_xtp_rx_dat_one(): compare own packets to detect corruptions
  2020-08-07 10:51 [PATCH v1 0/5] j1939 fixes Oleksij Rempel
                   ` (3 preceding siblings ...)
  2020-08-07 10:51 ` [PATCH v1 4/5] can: j1939: transport: add j1939_session_skb_find_by_offset() function Oleksij Rempel
@ 2020-08-07 10:52 ` Oleksij Rempel
  4 siblings, 0 replies; 6+ messages in thread
From: Oleksij Rempel @ 2020-08-07 10:52 UTC (permalink / raw)
  To: dev.kurt, mkl, wg; +Cc: Oleksij Rempel, kernel, linux-can, netdev, David Jander

Since the stack relays on receiving own packets, it was overwriting own
transmit buffer from received packets.

At least theoretically, the received echo buffer can be corrupt or
changed and the session partner can request to resend previous data. In
this case we will re-send bad data.

With this patch we will stop to overwrite own TX buffer and use it for
sanity checking.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 net/can/j1939/transport.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
index 90a2baac8a4a..5cf107cb447c 100644
--- a/net/can/j1939/transport.c
+++ b/net/can/j1939/transport.c
@@ -1792,7 +1792,20 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
 	}
 
 	tpdat = se_skb->data;
-	memcpy(&tpdat[offset], &dat[1], nbytes);
+	if (!session->transmission) {
+		memcpy(&tpdat[offset], &dat[1], nbytes);
+	} else {
+		int err;
+
+		err = memcmp(&tpdat[offset], &dat[1], nbytes);
+		if (err)
+			netdev_err_once(priv->ndev,
+					"%s: 0x%p: Data of RX-looped back packet (%*ph) doesn't match TX data (%*ph)!\n",
+					__func__, session,
+					nbytes, &dat[1],
+					nbytes, &tpdat[offset]);
+	}
+
 	if (packet == session->pkt.rx)
 		session->pkt.rx++;
 
-- 
2.28.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-08-07 11:00 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-07 10:51 [PATCH v1 0/5] j1939 fixes Oleksij Rempel
2020-08-07 10:51 ` [PATCH v1 1/5] can: j1939: transport: j1939_simple_recv(): ignore local J1939 messages send not by J1939 stack Oleksij Rempel
2020-08-07 10:51 ` [PATCH v1 2/5] can: j1939: transport: j1939_session_tx_dat(): fix use-after-free read in j1939_tp_txtimer() Oleksij Rempel
2020-08-07 10:51 ` [PATCH v1 3/5] can: j1939: socket: j1939_sk_bind(): make sure ml_priv is allocated Oleksij Rempel
2020-08-07 10:51 ` [PATCH v1 4/5] can: j1939: transport: add j1939_session_skb_find_by_offset() function Oleksij Rempel
2020-08-07 10:52 ` [PATCH v1 5/5] can: j1939: transport: j1939_xtp_rx_dat_one(): compare own packets to detect corruptions Oleksij Rempel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).