Avoid ldisc_ioctl() racing unregister_candev()
authornorly <ny-git@enpas.org>
Fri, 11 Jan 2019 02:38:35 +0000 (03:38 +0100)
committernorly <ny-git@enpas.org>
Wed, 23 Jan 2019 01:44:17 +0000 (02:44 +0100)
When getting the CAN interface's name via the SIOCGIFNAME ioctl,
elm->dev->name may no longer exist because the interface is being shut
down.

Also, print the name of the interface to dmesg.

module/elmcan.c
readme.rst

index 0bf1b8b4910cd8a840db1e1757d0e876d899e780..a62135e74250dd6aeb5dbb556788923b15405fc7 100644 (file)
@@ -78,7 +78,7 @@ struct elmcan {
        struct tty_struct       *tty;
        struct net_device       *dev;
 
-       int                     magic;
+       char                    ifname[IFNAMSIZ];
 
        /* Per-channel lock */
        spinlock_t              lock;
@@ -684,6 +684,18 @@ static void elm327_parse_rxbuf(struct elmcan *elm)
   * (takes elm->lock)                                          *
   ************************************************************************/
 
+static int elmcan_netdev_init(struct net_device *dev)
+{
+       struct elmcan *elm = netdev_priv(dev);
+
+       /* Copy the interface name here, so the SIOCGIFNAME case in
+        * elmcan_ldisc_ioctl() doesn't race against unregister_candev().
+        */
+       memcpy(elm->ifname, dev->name, IFNAMSIZ);
+
+       return 0;
+}
+
 /* Netdevice DOWN -> UP routine */
 static int elmcan_netdev_open(struct net_device *dev)
 {
@@ -791,6 +803,7 @@ static int elmcan_netdev_change_mtu(struct net_device *dev, int new_mtu)
 }
 
 static const struct net_device_ops elmcan_netdev_ops = {
+       .ndo_init       = elmcan_netdev_init,
        .ndo_open       = elmcan_netdev_open,
        .ndo_stop       = elmcan_netdev_close,
        .ndo_start_xmit = elmcan_netdev_start_xmit,
@@ -982,6 +995,8 @@ static int elmcan_ldisc_open(struct tty_struct *tty)
                return err;
        }
 
+       netdev_info(elm->dev, "elmcan on %s.\n", tty->name);
+
        return 0;
 }
 
@@ -1036,8 +1051,8 @@ static int elmcan_ldisc_ioctl(struct tty_struct *tty, struct file *file,
 
        switch (cmd) {
        case SIOCGIFNAME:
-               tmp = strlen(elm->dev->name) + 1;
-               if (copy_to_user((void __user *)arg, elm->dev->name, tmp))
+               tmp = strlen(elm->ifname) + 1;
+               if (copy_to_user((void __user *)arg, elm->ifname, tmp))
                        return -EFAULT;
                return 0;
 
index 49116647ee3ca7af313e29559dbaa766917e9d80..1c3c6d1cc9469e2008320fb650828ccf5d67e5cf 100644 (file)
@@ -270,8 +270,6 @@ To Do list for future development
 
 - ``if (!elm)``: Race with ``ldisc_close()``
 
-- ``elm->dev``: Race in ``ldisc_ioctl()``
-
 - DMA capable rx/tx buffers
 
 - fixup constants, constant for '``>``'