can: isotp: sanitize CAN ID checks in isotp_bind()
Subsystems (2)
Oliver Hartkopp
maintainerPATCH 1/3 can: isotp: sanitize CAN ID checks in isotp_bind()
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.
--- net/can/isotp.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-)
net/can/isotp.c +21 -20
@@ -1146,19 +1146,30 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)struct sock *sk = sock->sk;struct isotp_sock *so =isotp_sk (sk);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 ;lock_sock (sk);
@@ -1166,25 +1177,17 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)/* do not register frame reception for functional addressing */ if (so->opt.flags &CAN_ISOTP_SF_BROADCAST ) 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);if (!dev) { err = -ENODEV ;
@@ -1204,20 +1207,18 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) notify_enetdown =1 ; ifindex = dev->ifindex;if (do_rx_reg) { -can_rx_register (net, dev, addr->can_addr.tp.rx_id, -SINGLE_MASK (addr->can_addr.tp.rx_id), +can_rx_register (net, dev, rx_id,SINGLE_MASK (rx_id), isotp_rcv, sk,"isotp" , sk);/* no consecutive frame echo skb in flight */ so->cfecho =0 ;/* register for echo skb's */ -can_rx_register (net, dev, addr->can_addr.tp.tx_id, -SINGLE_MASK (addr->can_addr.tp.tx_id), +can_rx_register (net, dev, tx_id,SINGLE_MASK (tx_id), isotp_rcv_echo, sk,"isotpe" , sk); }dev_put (dev);
@@ -1237,12 +1238,12 @@ 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:release_sock (sk);
Signature · 1 line
2.30.2
Oliver Hartkopp
maintainerPATCH 2/3 can: isotp: return -EADDRNOTAVAIL when reading from unbound socket
When reading from an unbound can-isotp socket the syscall blocked indefinitely. As unbound sockets (without given CAN address information) do not make sense anyway we directly return -EADDRNOTAVAIL on read() analogue to the known behavior from sendmsg().
--- net/can/isotp.c | 4 ++++ 1 file changed, 4 insertions(+)
net/can/isotp.c +4 -0
@@ -1044,16 +1044,20 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)static int isotp_recvmsg (struct socket *sock,struct msghdr *msg,size_t size,int flags) {struct sock *sk = sock->sk;struct sk_buff *skb; +struct isotp_sock *so =isotp_sk (sk);int err =0 ;int noblock; noblock = flags &MSG_DONTWAIT ; flags &= ~MSG_DONTWAIT ; +if (!so->bound) +return -EADDRNOTAVAIL ; + skb =skb_recv_datagram (sk, flags, noblock, &err);if (!skb)return err;if (size < skb->len)
Signature · 1 line
2.30.2
Oliver Hartkopp
maintainerPATCH 3/3 can: isotp: support MSG_TRUNC flag when reading from socket
In reply to Oliver HartkoppWhen providing the MSG_TRUNC flag via recvmsg() syscall the return value provides the real length of the packet or datagram, even when it was longer than the passed buffer.
--- net/can/isotp.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-)
net/can/isotp.c +15 -12
@@ -1045,45 +1045,48 @@ static int isotp_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) {struct sock *sk = sock->sk;struct sk_buff *skb;struct isotp_sock *so =isotp_sk (sk); -int err =0 ; -int noblock; +int noblock = flags &MSG_DONTWAIT ; +int ret =0 ; - noblock = flags &MSG_DONTWAIT ; - flags &= ~MSG_DONTWAIT ; +if (flags & ~(MSG_DONTWAIT |MSG_TRUNC )) +return -EINVAL ;if (!so->bound)return -EADDRNOTAVAIL ; - skb =skb_recv_datagram (sk, flags, noblock, &err); + flags &= ~MSG_DONTWAIT ; + skb =skb_recv_datagram (sk, flags, noblock, &ret);if (!skb) -return err; +return ret;if (size < skb->len) msg->msg_flags |=MSG_TRUNC ;else size = skb->len; - err =memcpy_to_msg (msg, skb->data, size); -if (err <0 ) { -skb_free_datagram (sk, skb); -return err; - } + ret =memcpy_to_msg (msg, skb->data, size); +if (ret <0 ) + goto out_err;sock_recv_timestamp (msg, sk, skb);if (msg->msg_name) {__sockaddr_check_size (ISOTP_MIN_NAMELEN ); msg->msg_namelen =ISOTP_MIN_NAMELEN ;memcpy (msg->msg_name, skb->cb, msg->msg_namelen); } +/* set length of return value */ + ret = (flags &MSG_TRUNC ) ? skb->len : size; + +out_err:skb_free_datagram (sk, skb); -return size; +return ret; }static int isotp_release (struct socket *sock) {struct sock *sk = sock->sk;
Signature · 1 line
2.30.2
Marc Kleine-Budde
maintainerQuoted 10 lines · Oliver Hartkopp
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
0x6000001and0xC28001which both boil down to 11 bit CAN IDs0x001in 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 [email protected]Signed-off-by Oliver Hartkopp <[email protected]>
Added to linux-can-next/testing.
Thanks,
Marc
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Embedded Linux | https://www.pengutronix.de | Vertretung West/Dortmund | Phone: +49-231-2826-924 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |