From 5857d1dbae7d5bf4219efc39996ad002362a2951 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 30 Jul 2015 09:40:53 +0200 Subject: [PATCH] Bluetooth: 6lowpan: Fix possible race 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 Signed-off-by: Marcel Holtmann --- net/bluetooth/6lowpan.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 2fb7b3064904..0ffe2e24020a 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -859,18 +859,6 @@ 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); - err = register_netdev(netdev); - if (err < 0) { - BT_INFO("register_netdev failed %d", err); - free_netdev(netdev); - goto out; - } - - BT_DBG("ifindex %d peer bdaddr %pMR type %d my addr %pMR type %d", - netdev->ifindex, &chan->dst, chan->dst_type, - &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; @@ -881,6 +869,21 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) 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; + } + + BT_DBG("ifindex %d peer bdaddr %pMR type %d my addr %pMR type %d", + netdev->ifindex, &chan->dst, chan->dst_type, + &chan->src, chan->src_type); + set_bit(__LINK_STATE_PRESENT, &netdev->state); + return 0; out: