aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@parallels.com>2013-08-21 06:32:21 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-21 15:21:45 -0400
commit849c9b6f93cc4cb5eb59301b6380a7a81b43f414 (patch)
treecb938256bfd152792ccf4457eb80a2eb1575a7b6 /drivers/net/tun.c
parent3d407a80b62fc5891b41fe9045f23aba4437fc33 (diff)
tun: Allow to skip filter on attach
There's a small problem with sk-filters on tun devices. Consider an application doing this sequence of steps: fd = open("/dev/net/tun"); ioctl(fd, TUNSETIFF, { .ifr_name = "tun0" }); ioctl(fd, TUNATTACHFILTER, &my_filter); ioctl(fd, TUNSETPERSIST, 1); close(fd); At that point the tun0 will remain in the system and will keep in mind that there should be a socket filter at address '&my_filter'. If after that we do fd = open("/dev/net/tun"); ioctl(fd, TUNSETIFF, { .ifr_name = "tun0" }); we most likely receive the -EFAULT error, since tun_attach() would try to connect the filter back. But (!) if we provide a filter at address &my_filter, then tun0 will be created and the "new" filter would be attached, but application may not know about that. This may create certain problems to anyone using tun-s, but it's critical problem for c/r -- if we meet a persistent tun device with a filter in mind, we will not be able to attach to it to dump its state (flags, owner, address, vnethdr size, etc.). The proposal is to allow to attach to tun device (with TUNSETIFF) w/o attaching the filter to the tun-file's socket. After this attach app may e.g clean the device by dropping the filter, it doesn't want to have one, or (in case of c/r) get information about the device with tun ioctls. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r--drivers/net/tun.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index db43a2409733..6acbdbccebcd 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -501,7 +501,7 @@ static void tun_detach_all(struct net_device *dev)
501 module_put(THIS_MODULE); 501 module_put(THIS_MODULE);
502} 502}
503 503
504static int tun_attach(struct tun_struct *tun, struct file *file) 504static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filter)
505{ 505{
506 struct tun_file *tfile = file->private_data; 506 struct tun_file *tfile = file->private_data;
507 int err; 507 int err;
@@ -526,7 +526,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file)
526 err = 0; 526 err = 0;
527 527
528 /* Re-attach the filter to presist device */ 528 /* Re-attach the filter to presist device */
529 if (tun->filter_attached == true) { 529 if (!skip_filter && (tun->filter_attached == true)) {
530 err = sk_attach_filter(&tun->fprog, tfile->socket.sk); 530 err = sk_attach_filter(&tun->fprog, tfile->socket.sk);
531 if (!err) 531 if (!err)
532 goto out; 532 goto out;
@@ -1557,7 +1557,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
1557 if (err < 0) 1557 if (err < 0)
1558 return err; 1558 return err;
1559 1559
1560 err = tun_attach(tun, file); 1560 err = tun_attach(tun, file, ifr->ifr_flags & IFF_NOFILTER);
1561 if (err < 0) 1561 if (err < 0)
1562 return err; 1562 return err;
1563 1563
@@ -1631,7 +1631,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
1631 dev->vlan_features = dev->features; 1631 dev->vlan_features = dev->features;
1632 1632
1633 INIT_LIST_HEAD(&tun->disabled); 1633 INIT_LIST_HEAD(&tun->disabled);
1634 err = tun_attach(tun, file); 1634 err = tun_attach(tun, file, false);
1635 if (err < 0) 1635 if (err < 0)
1636 goto err_free_dev; 1636 goto err_free_dev;
1637 1637
@@ -1795,7 +1795,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
1795 ret = security_tun_dev_attach_queue(tun->security); 1795 ret = security_tun_dev_attach_queue(tun->security);
1796 if (ret < 0) 1796 if (ret < 0)
1797 goto unlock; 1797 goto unlock;
1798 ret = tun_attach(tun, file); 1798 ret = tun_attach(tun, file, false);
1799 } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) { 1799 } else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
1800 tun = rtnl_dereference(tfile->tun); 1800 tun = rtnl_dereference(tfile->tun);
1801 if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached) 1801 if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached)
@@ -1883,6 +1883,8 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
1883 1883
1884 if (tfile->detached) 1884 if (tfile->detached)
1885 ifr.ifr_flags |= IFF_DETACH_QUEUE; 1885 ifr.ifr_flags |= IFF_DETACH_QUEUE;
1886 if (!tfile->socket.sk->sk_filter)
1887 ifr.ifr_flags |= IFF_NOFILTER;
1886 1888
1887 if (copy_to_user(argp, &ifr, ifreq_len)) 1889 if (copy_to_user(argp, &ifr, ifreq_len))
1888 ret = -EFAULT; 1890 ret = -EFAULT;