linux-can-fixes-for-5.9-20200814
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEK3kIWJt9yTYMP3ehqclaivrt76kFAl82a18THG1rbEBwZW5n dXRyb25peC5kZQAKCRCpyVqK+u3vqVbYB/9wF0ekQk66ES0PlIKkTDqDlt8hH8gN a86yOFow3jjOWOlol1wDyCqh4i+JD0PgRPTCmXJoFYfXUsNwjRQt2ZqVgOlS0dR3 wmxxNw0i7SQ3+LDEf3Dofgk39Y5+VSQGfT3fvM8FfHWi9Mkxmswi2EwCBMx7Cqyp lghxsJyZoeSnwfx7Wcel75NnYID1WscKUyXR6Qd240V1h7s3oAt6ZdDnYLPJnd7M zeRSY+HgDa98HBUMmQi627douQcTtXyE5Zpx/PkkRGEOYIS/SEF8XmA2cQ0Vu8R/ R/u/htBqoV7OlL5XdyH1l2+HDOu0M1EKZiNWYMV34yobUqkrGg0oiJut =NuYv -----END PGP SIGNATURE----- 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 <davem@davemloft.net>
This commit is contained in:
commit
e591d298cc
|
@ -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;
|
||||
}
|
||||
|
@ -466,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)) {
|
||||
|
@ -553,6 +562,11 @@ static int j1939_sk_connect(struct socket *sock, struct sockaddr *uaddr,
|
|||
static void j1939_sk_sock2sockaddr_can(struct sockaddr_can *addr,
|
||||
const struct j1939_sock *jsk, int peer)
|
||||
{
|
||||
/* There are two holes (2 bytes and 3 bytes) to clear to avoid
|
||||
* leaking kernel information to user space.
|
||||
*/
|
||||
memset(addr, 0, J1939_MIN_NAMELEN);
|
||||
|
||||
addr->can_family = AF_CAN;
|
||||
addr->can_ifindex = jsk->ifindex;
|
||||
addr->can_addr.j1939.pgn = jsk->addr.pgn;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -787,6 +794,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 +1139,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;
|
||||
|
@ -1750,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);
|
||||
|
@ -1769,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++;
|
||||
|
||||
|
@ -2017,6 +2053,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);
|
||||
|
|
Loading…
Reference in New Issue