Skip to content

Commit

Permalink
tun: Fix device unregister race
Browse files Browse the repository at this point in the history
It is currently possible for an asynchronous device unregister
to cause the same tun device to be unregistered twice.  This
is because the unregister in tun_chr_close only checks whether
__tun_get(tfile) != NULL.  This however has nothing to do with
whether the device has already been unregistered.  All it tells
you is whether __tun_detach has been called.

This patch fixes this by using the most obvious thing to test
whether the device has been unregistered.

It also moves __tun_detach outside of rtnl_unlock since nothing
that it does requires that lock.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Herbert Xu authored and David S. Miller committed Jul 6, 2009
1 parent c001c21 commit d23e436
Showing 1 changed file with 9 additions and 7 deletions.
16 changes: 9 additions & 7 deletions drivers/net/tun.c
Original file line number Diff line number Diff line change
Expand Up @@ -1324,20 +1324,22 @@ static int tun_chr_close(struct inode *inode, struct file *file)
struct tun_file *tfile = file->private_data;
struct tun_struct *tun;


rtnl_lock();
tun = __tun_get(tfile);
if (tun) {
DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name);
struct net_device *dev = tun->dev;

DBG(KERN_INFO "%s: tun_chr_close\n", dev->name);

__tun_detach(tun);

/* If desireable, unregister the netdevice. */
if (!(tun->flags & TUN_PERSIST))
unregister_netdevice(tun->dev);

if (!(tun->flags & TUN_PERSIST)) {
rtnl_lock();
if (dev->reg_state == NETREG_REGISTERED)
unregister_netdevice(dev);
rtnl_unlock();
}
}
rtnl_unlock();

tun = tfile->tun;
if (tun)
Expand Down

0 comments on commit d23e436

Please sign in to comment.