Skip to content

Commit e591d29

Browse files
committed
Merge tag 'linux-can-fixes-for-5.9-20200814' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can
Marc Kleine-Budde says: ==================== pull-request: can 2020-08-14 this is a pull request of 6 patches for net/master. All patches fix problems in the j1939 CAN networking stack. The first patch is by Eric Dumazet fixes a kernel-infoleak in j1939_sk_sock2sockaddr_can(). The remaining 5 patches are by Oleksij Rempel and fix recption of j1939 messages not orginated by the stack, a use-after-free in j1939_tp_txtimer(), ensure that the CAN driver has a ml_priv allocated. These problem were found by google's syzbot. Further ETP sessions with block size of less than 255 are fixed and a sanity check was added to j1939_xtp_rx_dat_one() to detect packet corruption. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 7fca4de + e052d05 commit e591d29

File tree

2 files changed

+62
-8
lines changed

2 files changed

+62
-8
lines changed

net/can/j1939/socket.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ static int j1939_sk_init(struct sock *sk)
398398
spin_lock_init(&jsk->sk_session_queue_lock);
399399
INIT_LIST_HEAD(&jsk->sk_session_queue);
400400
sk->sk_destruct = j1939_sk_sock_destruct;
401+
sk->sk_protocol = CAN_J1939;
401402

402403
return 0;
403404
}
@@ -466,6 +467,14 @@ static int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len)
466467
goto out_release_sock;
467468
}
468469

470+
if (!ndev->ml_priv) {
471+
netdev_warn_once(ndev,
472+
"No CAN mid layer private allocated, please fix your driver and use alloc_candev()!\n");
473+
dev_put(ndev);
474+
ret = -ENODEV;
475+
goto out_release_sock;
476+
}
477+
469478
priv = j1939_netdev_start(ndev);
470479
dev_put(ndev);
471480
if (IS_ERR(priv)) {
@@ -553,6 +562,11 @@ static int j1939_sk_connect(struct socket *sock, struct sockaddr *uaddr,
553562
static void j1939_sk_sock2sockaddr_can(struct sockaddr_can *addr,
554563
const struct j1939_sock *jsk, int peer)
555564
{
565+
/* There are two holes (2 bytes and 3 bytes) to clear to avoid
566+
* leaking kernel information to user space.
567+
*/
568+
memset(addr, 0, J1939_MIN_NAMELEN);
569+
556570
addr->can_family = AF_CAN;
557571
addr->can_ifindex = jsk->ifindex;
558572
addr->can_addr.j1939.pgn = jsk->addr.pgn;

net/can/j1939/transport.c

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -352,17 +352,16 @@ void j1939_session_skb_queue(struct j1939_session *session,
352352
skb_queue_tail(&session->skb_queue, skb);
353353
}
354354

355-
static struct sk_buff *j1939_session_skb_find(struct j1939_session *session)
355+
static struct
356+
sk_buff *j1939_session_skb_find_by_offset(struct j1939_session *session,
357+
unsigned int offset_start)
356358
{
357359
struct j1939_priv *priv = session->priv;
360+
struct j1939_sk_buff_cb *do_skcb;
358361
struct sk_buff *skb = NULL;
359362
struct sk_buff *do_skb;
360-
struct j1939_sk_buff_cb *do_skcb;
361-
unsigned int offset_start;
362363
unsigned long flags;
363364

364-
offset_start = session->pkt.dpo * 7;
365-
366365
spin_lock_irqsave(&session->skb_queue.lock, flags);
367366
skb_queue_walk(&session->skb_queue, do_skb) {
368367
do_skcb = j1939_skb_to_cb(do_skb);
@@ -382,6 +381,14 @@ static struct sk_buff *j1939_session_skb_find(struct j1939_session *session)
382381
return skb;
383382
}
384383

384+
static struct sk_buff *j1939_session_skb_find(struct j1939_session *session)
385+
{
386+
unsigned int offset_start;
387+
388+
offset_start = session->pkt.dpo * 7;
389+
return j1939_session_skb_find_by_offset(session, offset_start);
390+
}
391+
385392
/* see if we are receiver
386393
* returns 0 for broadcasts, although we will receive them
387394
*/
@@ -766,7 +773,7 @@ static int j1939_session_tx_dat(struct j1939_session *session)
766773
int ret = 0;
767774
u8 dat[8];
768775

769-
se_skb = j1939_session_skb_find(session);
776+
se_skb = j1939_session_skb_find_by_offset(session, session->pkt.tx * 7);
770777
if (!se_skb)
771778
return -ENOBUFS;
772779

@@ -787,6 +794,18 @@ static int j1939_session_tx_dat(struct j1939_session *session)
787794
if (len > 7)
788795
len = 7;
789796

797+
if (offset + len > se_skb->len) {
798+
netdev_err_once(priv->ndev,
799+
"%s: 0x%p: requested data outside of queued buffer: offset %i, len %i, pkt.tx: %i\n",
800+
__func__, session, skcb->offset, se_skb->len , session->pkt.tx);
801+
return -EOVERFLOW;
802+
}
803+
804+
if (!len) {
805+
ret = -ENOBUFS;
806+
break;
807+
}
808+
790809
memcpy(&dat[1], &tpdat[offset], len);
791810
ret = j1939_tp_tx_dat(session, dat, len + 1);
792811
if (ret < 0) {
@@ -1120,6 +1139,9 @@ static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer)
11201139
* cleanup including propagation of the error to user space.
11211140
*/
11221141
break;
1142+
case -EOVERFLOW:
1143+
j1939_session_cancel(session, J1939_XTP_ABORT_ECTS_TOO_BIG);
1144+
break;
11231145
case 0:
11241146
session->tx_retry = 0;
11251147
break;
@@ -1750,7 +1772,8 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
17501772
__func__, session);
17511773
goto out_session_cancel;
17521774
}
1753-
se_skb = j1939_session_skb_find(session);
1775+
1776+
se_skb = j1939_session_skb_find_by_offset(session, packet * 7);
17541777
if (!se_skb) {
17551778
netdev_warn(priv->ndev, "%s: 0x%p: no skb found\n", __func__,
17561779
session);
@@ -1769,7 +1792,20 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
17691792
}
17701793

17711794
tpdat = se_skb->data;
1772-
memcpy(&tpdat[offset], &dat[1], nbytes);
1795+
if (!session->transmission) {
1796+
memcpy(&tpdat[offset], &dat[1], nbytes);
1797+
} else {
1798+
int err;
1799+
1800+
err = memcmp(&tpdat[offset], &dat[1], nbytes);
1801+
if (err)
1802+
netdev_err_once(priv->ndev,
1803+
"%s: 0x%p: Data of RX-looped back packet (%*ph) doesn't match TX data (%*ph)!\n",
1804+
__func__, session,
1805+
nbytes, &dat[1],
1806+
nbytes, &tpdat[offset]);
1807+
}
1808+
17731809
if (packet == session->pkt.rx)
17741810
session->pkt.rx++;
17751811

@@ -2017,6 +2053,10 @@ void j1939_simple_recv(struct j1939_priv *priv, struct sk_buff *skb)
20172053
if (!skb->sk)
20182054
return;
20192055

2056+
if (skb->sk->sk_family != AF_CAN ||
2057+
skb->sk->sk_protocol != CAN_J1939)
2058+
return;
2059+
20202060
j1939_session_list_lock(priv);
20212061
session = j1939_session_get_simple(priv, skb);
20222062
j1939_session_list_unlock(priv);

0 commit comments

Comments
 (0)