Merge tag 'linux-can-fixes-for-5.13-20210619' of git://git.kernel.org/pub/scm/linux...
authorDavid S. Miller <davem@davemloft.net>
Mon, 21 Jun 2021 19:23:49 +0000 (12:23 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 21 Jun 2021 19:23:49 +0000 (12:23 -0700)
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: David S. Miller <davem@davemloft.net>
drivers/net/can/usb/ems_usb.c
net/can/bcm.c
net/can/gw.c
net/can/isotp.c
net/can/j1939/main.c
net/can/j1939/socket.c

index 5af6978..0a37af4 100644 (file)
@@ -1053,7 +1053,6 @@ static void ems_usb_disconnect(struct usb_interface *intf)
 
        if (dev) {
                unregister_netdev(dev->netdev);
-               free_candev(dev->netdev);
 
                unlink_all_urbs(dev);
 
@@ -1061,6 +1060,8 @@ static void ems_usb_disconnect(struct usb_interface *intf)
 
                kfree(dev->intr_in_buffer);
                kfree(dev->tx_msg_buffer);
+
+               free_candev(dev->netdev);
        }
 }
 
index f3e4d95..0928a39 100644 (file)
@@ -785,6 +785,7 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
                                                  bcm_rx_handler, op);
 
                        list_del(&op->list);
+                       synchronize_rcu();
                        bcm_remove_op(op);
                        return 1; /* done */
                }
@@ -1533,9 +1534,13 @@ static int bcm_release(struct socket *sock)
                                          REGMASK(op->can_id),
                                          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)
        /* remove procfs entry */
        if (net->can.bcmproc_dir && bo->bcm_proc_read)
index ba41248..d8861e8 100644 (file)
@@ -596,6 +596,7 @@ static int cgw_notifier(struct notifier_block *nb,
                        if (gwj->src.dev == dev || gwj->dst.dev == dev) {
                                hlist_del(&gwj->list);
                                cgw_unregister_filter(net, gwj);
+                               synchronize_rcu();
                                kmem_cache_free(cgw_cache, gwj);
                        }
                }
@@ -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_del(&gwj->list);
                cgw_unregister_filter(net, gwj);
+               synchronize_rcu();
                kmem_cache_free(cgw_cache, gwj);
        }
 }
@@ -1222,6 +1224,7 @@ static int cgw_remove_job(struct sk_buff *skb, struct nlmsghdr *nlh,
 
                hlist_del(&gwj->list);
                cgw_unregister_filter(net, gwj);
+               synchronize_rcu();
                kmem_cache_free(cgw_cache, gwj);
                err = 0;
                break;
index be6183f..234cc4a 100644 (file)
@@ -1028,9 +1028,6 @@ static int isotp_release(struct socket *sock)
 
        lock_sock(sk);
 
-       hrtimer_cancel(&so->txtimer);
-       hrtimer_cancel(&so->rxtimer);
-
        /* remove current filters & unregister */
        if (so->bound && (!(so->opt.flags & CAN_ISOTP_SF_BROADCAST))) {
                if (so->ifindex) {
@@ -1042,10 +1039,14 @@ static int isotp_release(struct socket *sock)
                                                  SINGLE_MASK(so->rxid),
                                                  isotp_rcv, sk);
                                dev_put(dev);
+                               synchronize_rcu();
                        }
                }
        }
 
+       hrtimer_cancel(&so->txtimer);
+       hrtimer_cancel(&so->rxtimer);
+
        so->ifindex = 0;
        so->bound = 0;
 
index da3a7a7..08c8606 100644 (file)
@@ -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,
                          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);
 }
 
index 56aa661..fce8bc8 100644 (file)
@@ -398,6 +398,9 @@ static int j1939_sk_init(struct sock *sk)
        atomic_set(&jsk->skb_pending, 0);
        spin_lock_init(&jsk->sk_session_queue_lock);
        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_protocol = CAN_J1939;