Commit d52f9b22 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-fixes-for-5.13-20210619' of...

Merge tag 'linux-can-fixes-for-5.13-20210619' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2021-06-19

this is a pull request of 5 patches for net/master.

The first patch is by Thadeu Lima de Souza Cascardo and fixes a
potential use-after-free in the CAN broadcast manager socket, by
delaying the release of struct bcm_op after synchronize_rcu().

Oliver Hartkopp's patch fixes a similar potential user-after-free in
the CAN gateway socket by synchronizing RCU operations before removing
gw job entry.

Another patch by Oliver Hartkopp fixes a potential use-after-free in
the ISOTP socket by omitting unintended hrtimer restarts on socket
release.

Oleksij Rempel's patch for the j1939 socket fixes a potential
use-after-free by setting the SOCK_RCU_FREE flag on the socket.

The last patch is by Pavel Skripkin and fixes a use-after-free in the
ems_usb CAN driver.

All patches are intended for stable and have stable@v.k.o on Cc.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 0d98ec87 ab4a0b8f
...@@ -1053,7 +1053,6 @@ static void ems_usb_disconnect(struct usb_interface *intf) ...@@ -1053,7 +1053,6 @@ static void ems_usb_disconnect(struct usb_interface *intf)
if (dev) { if (dev) {
unregister_netdev(dev->netdev); unregister_netdev(dev->netdev);
free_candev(dev->netdev);
unlink_all_urbs(dev); unlink_all_urbs(dev);
...@@ -1061,6 +1060,8 @@ static void ems_usb_disconnect(struct usb_interface *intf) ...@@ -1061,6 +1060,8 @@ static void ems_usb_disconnect(struct usb_interface *intf)
kfree(dev->intr_in_buffer); kfree(dev->intr_in_buffer);
kfree(dev->tx_msg_buffer); kfree(dev->tx_msg_buffer);
free_candev(dev->netdev);
} }
} }
......
...@@ -785,6 +785,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh, ...@@ -785,6 +785,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
bcm_rx_handler, op); bcm_rx_handler, op);
list_del(&op->list); list_del(&op->list);
synchronize_rcu();
bcm_remove_op(op); bcm_remove_op(op);
return 1; /* done */ return 1; /* done */
} }
...@@ -1533,9 +1534,13 @@ static int bcm_release(struct socket *sock) ...@@ -1533,9 +1534,13 @@ static int bcm_release(struct socket *sock)
REGMASK(op->can_id), REGMASK(op->can_id),
bcm_rx_handler, op); bcm_rx_handler, op);
bcm_remove_op(op);
} }
synchronize_rcu();
list_for_each_entry_safe(op, next, &bo->rx_ops, list)
bcm_remove_op(op);
#if IS_ENABLED(CONFIG_PROC_FS) #if IS_ENABLED(CONFIG_PROC_FS)
/* remove procfs entry */ /* remove procfs entry */
if (net->can.bcmproc_dir && bo->bcm_proc_read) if (net->can.bcmproc_dir && bo->bcm_proc_read)
......
...@@ -596,6 +596,7 @@ static int cgw_notifier(struct notifier_block *nb, ...@@ -596,6 +596,7 @@ static int cgw_notifier(struct notifier_block *nb,
if (gwj->src.dev == dev || gwj->dst.dev == dev) { if (gwj->src.dev == dev || gwj->dst.dev == dev) {
hlist_del(&gwj->list); hlist_del(&gwj->list);
cgw_unregister_filter(net, gwj); cgw_unregister_filter(net, gwj);
synchronize_rcu();
kmem_cache_free(cgw_cache, gwj); kmem_cache_free(cgw_cache, gwj);
} }
} }
...@@ -1154,6 +1155,7 @@ static void cgw_remove_all_jobs(struct net *net) ...@@ -1154,6 +1155,7 @@ static void cgw_remove_all_jobs(struct net *net)
hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) { hlist_for_each_entry_safe(gwj, nx, &net->can.cgw_list, list) {
hlist_del(&gwj->list); hlist_del(&gwj->list);
cgw_unregister_filter(net, gwj); cgw_unregister_filter(net, gwj);
synchronize_rcu();
kmem_cache_free(cgw_cache, gwj); kmem_cache_free(cgw_cache, gwj);
} }
} }
...@@ -1222,6 +1224,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1222,6 +1224,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
hlist_del(&gwj->list); hlist_del(&gwj->list);
cgw_unregister_filter(net, gwj); cgw_unregister_filter(net, gwj);
synchronize_rcu();
kmem_cache_free(cgw_cache, gwj); kmem_cache_free(cgw_cache, gwj);
err = 0; err = 0;
break; break;
......
...@@ -1028,9 +1028,6 @@ static int isotp_release(struct socket *sock) ...@@ -1028,9 +1028,6 @@ static int isotp_release(struct socket *sock)
lock_sock(sk); lock_sock(sk);
hrtimer_cancel(&so->txtimer);
hrtimer_cancel(&so->rxtimer);
/* remove current filters & unregister */ /* remove current filters & unregister */
if (so->bound && (!(so->opt.flags & CAN_ISOTP_SF_BROADCAST))) { if (so->bound && (!(so->opt.flags & CAN_ISOTP_SF_BROADCAST))) {
if (so->ifindex) { if (so->ifindex) {
...@@ -1042,10 +1039,14 @@ static int isotp_release(struct socket *sock) ...@@ -1042,10 +1039,14 @@ static int isotp_release(struct socket *sock)
SINGLE_MASK(so->rxid), SINGLE_MASK(so->rxid),
isotp_rcv, sk); isotp_rcv, sk);
dev_put(dev); dev_put(dev);
synchronize_rcu();
} }
} }
} }
hrtimer_cancel(&so->txtimer);
hrtimer_cancel(&so->rxtimer);
so->ifindex = 0; so->ifindex = 0;
so->bound = 0; so->bound = 0;
......
...@@ -193,6 +193,10 @@ static void j1939_can_rx_unregister(struct j1939_priv *priv) ...@@ -193,6 +193,10 @@ static void j1939_can_rx_unregister(struct j1939_priv *priv)
can_rx_unregister(dev_net(ndev), ndev, J1939_CAN_ID, J1939_CAN_MASK, can_rx_unregister(dev_net(ndev), ndev, J1939_CAN_ID, J1939_CAN_MASK,
j1939_can_recv, priv); j1939_can_recv, priv);
/* The last reference of priv is dropped by the RCU deferred
* j1939_sk_sock_destruct() of the last socket, so we can
* safely drop this reference here.
*/
j1939_priv_put(priv); j1939_priv_put(priv);
} }
......
...@@ -398,6 +398,9 @@ static int j1939_sk_init(struct sock *sk) ...@@ -398,6 +398,9 @@ static int j1939_sk_init(struct sock *sk)
atomic_set(&jsk->skb_pending, 0); atomic_set(&jsk->skb_pending, 0);
spin_lock_init(&jsk->sk_session_queue_lock); spin_lock_init(&jsk->sk_session_queue_lock);
INIT_LIST_HEAD(&jsk->sk_session_queue); INIT_LIST_HEAD(&jsk->sk_session_queue);
/* j1939_sk_sock_destruct() depends on SOCK_RCU_FREE flag */
sock_set_flag(sk, SOCK_RCU_FREE);
sk->sk_destruct = j1939_sk_sock_destruct; sk->sk_destruct = j1939_sk_sock_destruct;
sk->sk_protocol = CAN_J1939; sk->sk_protocol = CAN_J1939;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment