aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2009-01-20 06:02:28 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-21 19:00:45 -0500
commit38231b7a8d1b74c920822640d1ce8eb8046377fb (patch)
treefc7f1c3cc8ef34a64a740a2938934dbd598f0d93 /drivers/net/tun.c
parent36b50bab53207daf34be63ca62fb8b0b08dc6e6b (diff)
tun: Make tun_net_xmit atomic wrt tun_attach && tun_detach
Currently this small race allows for a packet to be received when we detach from an tun device and still be enqueued. Not especially important but not what the code is trying to do. Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r--drivers/net/tun.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index dfbf58659771..fa93160bf522 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -115,25 +115,33 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
115{ 115{
116 struct tun_file *tfile = file->private_data; 116 struct tun_file *tfile = file->private_data;
117 const struct cred *cred = current_cred(); 117 const struct cred *cred = current_cred();
118 int err;
118 119
119 ASSERT_RTNL(); 120 ASSERT_RTNL();
120 121
121 if (tfile->tun)
122 return -EINVAL;
123
124 if (tun->tfile)
125 return -EBUSY;
126
127 /* Check permissions */ 122 /* Check permissions */
128 if (((tun->owner != -1 && cred->euid != tun->owner) || 123 if (((tun->owner != -1 && cred->euid != tun->owner) ||
129 (tun->group != -1 && cred->egid != tun->group)) && 124 (tun->group != -1 && cred->egid != tun->group)) &&
130 !capable(CAP_NET_ADMIN)) 125 !capable(CAP_NET_ADMIN))
131 return -EPERM; 126 return -EPERM;
132 127
128 netif_tx_lock_bh(tun->dev);
129
130 err = -EINVAL;
131 if (tfile->tun)
132 goto out;
133
134 err = -EBUSY;
135 if (tun->tfile)
136 goto out;
137
138 err = 0;
133 tfile->tun = tun; 139 tfile->tun = tun;
134 tun->tfile = tfile; 140 tun->tfile = tfile;
135 141
136 return 0; 142out:
143 netif_tx_unlock_bh(tun->dev);
144 return err;
137} 145}
138 146
139static void __tun_detach(struct tun_struct *tun) 147static void __tun_detach(struct tun_struct *tun)
@@ -141,8 +149,10 @@ static void __tun_detach(struct tun_struct *tun)
141 struct tun_file *tfile = tun->tfile; 149 struct tun_file *tfile = tun->tfile;
142 150
143 /* Detach from net device */ 151 /* Detach from net device */
152 netif_tx_lock_bh(tun->dev);
144 tfile->tun = NULL; 153 tfile->tun = NULL;
145 tun->tfile = NULL; 154 tun->tfile = NULL;
155 netif_tx_unlock_bh(tun->dev);
146 156
147 /* Drop read queue */ 157 /* Drop read queue */
148 skb_queue_purge(&tun->readq); 158 skb_queue_purge(&tun->readq);