Skip to content

Commit

Permalink
can: isotp: sanitize CAN ID checks in isotp_bind()
Browse files Browse the repository at this point in the history
Upstream commit https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=3ea566422cbd

Syzbot created an environment that lead to a state machine status that
can not be reached with a compliant CAN ID address configuration.
The provided address information consisted of CAN ID 0x6000001 and 0xC28001
which both boil down to 11 bit CAN IDs 0x001 in sending and receiving.

Sanitize the SFF/EFF CAN ID values before performing the address checks.

Fixes: e057dd3fc20f ("can: add ISO 15765-2:2016 transport protocol")
Reported-by: syzbot+2339c27f5c66c652843e@syzkaller.appspotmail.com
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
  • Loading branch information
hartkopp committed Mar 17, 2022
1 parent 847a3ac commit dc9bf4e
Showing 1 changed file with 22 additions and 19 deletions.
41 changes: 22 additions & 19 deletions net/can/isotp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1148,15 +1148,26 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
struct net *net = sock_net(sk);
int ifindex;
struct net_device *dev;
canid_t tx_id, rx_id;
int err = 0;
int notify_enetdown = 0;
int do_rx_reg = 1;

if (len < ISOTP_MIN_NAMELEN)
return -EINVAL;

if (addr->can_addr.tp.tx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG))
return -EADDRNOTAVAIL;
/* sanitize tx/rx CAN identifiers */
tx_id = addr->can_addr.tp.tx_id;
if (tx_id & CAN_EFF_FLAG)
tx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK);
else
tx_id &= CAN_SFF_MASK;

rx_id = addr->can_addr.tp.rx_id;
if (rx_id & CAN_EFF_FLAG)
rx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK);
else
rx_id &= CAN_SFF_MASK;

if (!addr->can_ifindex)
return -ENODEV;
Expand All @@ -1168,21 +1179,13 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
do_rx_reg = 0;

/* do not validate rx address for functional addressing */
if (do_rx_reg) {
if (addr->can_addr.tp.rx_id == addr->can_addr.tp.tx_id) {
err = -EADDRNOTAVAIL;
goto out;
}

if (addr->can_addr.tp.rx_id & (CAN_ERR_FLAG | CAN_RTR_FLAG)) {
err = -EADDRNOTAVAIL;
goto out;
}
if (do_rx_reg && rx_id == tx_id) {
err = -EADDRNOTAVAIL;
goto out;
}

if (so->bound && addr->can_ifindex == so->ifindex &&
addr->can_addr.tp.rx_id == so->rxid &&
addr->can_addr.tp.tx_id == so->txid)
rx_id == so->rxid && tx_id == so->txid)
goto out;

dev = dev_get_by_index(net, addr->can_ifindex);
Expand All @@ -1207,11 +1210,11 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)

if (do_rx_reg)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
can_rx_register(net, dev, addr->can_addr.tp.rx_id,
can_rx_register(net, dev, rx_id,
#else
can_rx_register(dev, addr->can_addr.tp.rx_id,
can_rx_register(dev, rx_id,
#endif
SINGLE_MASK(addr->can_addr.tp.rx_id), isotp_rcv, sk,
SINGLE_MASK(rx_id), isotp_rcv, sk,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,11)) || \
((LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,50)) && (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0))) || \
((LINUX_VERSION_CODE >= KERNEL_VERSION(3,18,49)) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0))) || \
Expand Down Expand Up @@ -1241,8 +1244,8 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)

/* switch to new settings */
so->ifindex = ifindex;
so->rxid = addr->can_addr.tp.rx_id;
so->txid = addr->can_addr.tp.tx_id;
so->rxid = rx_id;
so->txid = tx_id;
so->bound = 1;

out:
Expand Down

0 comments on commit dc9bf4e

Please sign in to comment.