Bluetooth: 6lowpan: Fix possible race
authorAlexander Aring <alex.aring@gmail.com>
Thu, 30 Jul 2015 07:40:53 +0000 (09:40 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Thu, 30 Jul 2015 12:11:36 +0000 (14:11 +0200)
This patch fix a possible race after calling register_netdev. After
calling netdev_register it could be possible that netdev_ops callbacks
use the uninitialized private data of lowpan_dev. By moving the
initialization of this data before netdev_register we can be sure that
initialized private data is be used after netdev_register.

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
net/bluetooth/6lowpan.c

index 2fb7b306490424c62bafd0fe7de6fd83176ed698..0ffe2e24020aa86b80115221811f324511cc1385 100644 (file)
@@ -859,9 +859,22 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
        SET_NETDEV_DEV(netdev, &chan->conn->hcon->hdev->dev);
        SET_NETDEV_DEVTYPE(netdev, &bt_type);
 
+       *dev = netdev_priv(netdev);
+       (*dev)->netdev = netdev;
+       (*dev)->hdev = chan->conn->hcon->hdev;
+       INIT_LIST_HEAD(&(*dev)->peers);
+
+       spin_lock(&devices_lock);
+       INIT_LIST_HEAD(&(*dev)->list);
+       list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
+       spin_unlock(&devices_lock);
+
        err = register_netdev(netdev);
        if (err < 0) {
                BT_INFO("register_netdev failed %d", err);
+               spin_lock(&devices_lock);
+               list_del_rcu(&(*dev)->list);
+               spin_unlock(&devices_lock);
                free_netdev(netdev);
                goto out;
        }
@@ -871,16 +884,6 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
               &chan->src, chan->src_type);
        set_bit(__LINK_STATE_PRESENT, &netdev->state);
 
-       *dev = netdev_priv(netdev);
-       (*dev)->netdev = netdev;
-       (*dev)->hdev = chan->conn->hcon->hdev;
-       INIT_LIST_HEAD(&(*dev)->peers);
-
-       spin_lock(&devices_lock);
-       INIT_LIST_HEAD(&(*dev)->list);
-       list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
-       spin_unlock(&devices_lock);
-
        return 0;
 
 out: