aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/tun.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2009-11-07 01:52:32 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-07 01:52:32 -0500
commit50857e2a59d8beddc6bb76137df026d67f30d5ca (patch)
tree7b6d244ad6fa07ff199c7d1436750d535b6b8dcd /drivers/net/tun.c
parent2dceba14ef0e62738d58777a1bd4018130d47a74 (diff)
net/tun: handle compat_ioctl directly
The tun driver is the only code in the kernel that operates on a character device with struct ifreq. Change the driver to handle the conversion itself so we can contain the remaining ifreq handling in the socket layer. This also fixes a bug in the handling of invalid ioctl numbers on an unbound tun device. The driver treats this as a TUNSETIFF in native mode, but there is no way for the generic compat_ioctl() function to emulate this behaviour. Possibly the driver was only doing this accidentally anyway, but if any code relies on this misfeature, it now also works in compat mode. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r--drivers/net/tun.c53
1 files changed, 46 insertions, 7 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 9c59a82784dc..01e99f22210e 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -53,6 +53,7 @@
53#include <linux/miscdevice.h> 53#include <linux/miscdevice.h>
54#include <linux/ethtool.h> 54#include <linux/ethtool.h>
55#include <linux/rtnetlink.h> 55#include <linux/rtnetlink.h>
56#include <linux/compat.h>
56#include <linux/if.h> 57#include <linux/if.h>
57#include <linux/if_arp.h> 58#include <linux/if_arp.h>
58#include <linux/if_ether.h> 59#include <linux/if_ether.h>
@@ -1109,8 +1110,8 @@ static int set_offload(struct net_device *dev, unsigned long arg)
1109 return 0; 1110 return 0;
1110} 1111}
1111 1112
1112static long tun_chr_ioctl(struct file *file, unsigned int cmd, 1113static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
1113 unsigned long arg) 1114 unsigned long arg, int ifreq_len)
1114{ 1115{
1115 struct tun_file *tfile = file->private_data; 1116 struct tun_file *tfile = file->private_data;
1116 struct tun_struct *tun; 1117 struct tun_struct *tun;
@@ -1120,7 +1121,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd,
1120 int ret; 1121 int ret;
1121 1122
1122 if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) 1123 if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
1123 if (copy_from_user(&ifr, argp, sizeof ifr)) 1124 if (copy_from_user(&ifr, argp, ifreq_len))
1124 return -EFAULT; 1125 return -EFAULT;
1125 1126
1126 if (cmd == TUNGETFEATURES) { 1127 if (cmd == TUNGETFEATURES) {
@@ -1143,7 +1144,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd,
1143 if (ret) 1144 if (ret)
1144 goto unlock; 1145 goto unlock;
1145 1146
1146 if (copy_to_user(argp, &ifr, sizeof(ifr))) 1147 if (copy_to_user(argp, &ifr, ifreq_len))
1147 ret = -EFAULT; 1148 ret = -EFAULT;
1148 goto unlock; 1149 goto unlock;
1149 } 1150 }
@@ -1161,7 +1162,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd,
1161 if (ret) 1162 if (ret)
1162 break; 1163 break;
1163 1164
1164 if (copy_to_user(argp, &ifr, sizeof(ifr))) 1165 if (copy_to_user(argp, &ifr, ifreq_len))
1165 ret = -EFAULT; 1166 ret = -EFAULT;
1166 break; 1167 break;
1167 1168
@@ -1235,7 +1236,7 @@ static long tun_chr_ioctl(struct file *file, unsigned int cmd,
1235 /* Get hw addres */ 1236 /* Get hw addres */
1236 memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN); 1237 memcpy(ifr.ifr_hwaddr.sa_data, tun->dev->dev_addr, ETH_ALEN);
1237 ifr.ifr_hwaddr.sa_family = tun->dev->type; 1238 ifr.ifr_hwaddr.sa_family = tun->dev->type;
1238 if (copy_to_user(argp, &ifr, sizeof ifr)) 1239 if (copy_to_user(argp, &ifr, ifreq_len))
1239 ret = -EFAULT; 1240 ret = -EFAULT;
1240 break; 1241 break;
1241 1242
@@ -1274,6 +1275,41 @@ unlock:
1274 return ret; 1275 return ret;
1275} 1276}
1276 1277
1278static long tun_chr_ioctl(struct file *file,
1279 unsigned int cmd, unsigned long arg)
1280{
1281 return __tun_chr_ioctl(file, cmd, arg, sizeof (struct ifreq));
1282}
1283
1284#ifdef CONFIG_COMPAT
1285static long tun_chr_compat_ioctl(struct file *file,
1286 unsigned int cmd, unsigned long arg)
1287{
1288 switch (cmd) {
1289 case TUNSETIFF:
1290 case TUNGETIFF:
1291 case TUNSETTXFILTER:
1292 case TUNGETSNDBUF:
1293 case TUNSETSNDBUF:
1294 case SIOCGIFHWADDR:
1295 case SIOCSIFHWADDR:
1296 arg = (unsigned long)compat_ptr(arg);
1297 break;
1298 default:
1299 arg = (compat_ulong_t)arg;
1300 break;
1301 }
1302
1303 /*
1304 * compat_ifreq is shorter than ifreq, so we must not access beyond
1305 * the end of that structure. All fields that are used in this
1306 * driver are compatible though, we don't need to convert the
1307 * contents.
1308 */
1309 return __tun_chr_ioctl(file, cmd, arg, sizeof(struct compat_ifreq));
1310}
1311#endif /* CONFIG_COMPAT */
1312
1277static int tun_chr_fasync(int fd, struct file *file, int on) 1313static int tun_chr_fasync(int fd, struct file *file, int on)
1278{ 1314{
1279 struct tun_struct *tun = tun_get(file); 1315 struct tun_struct *tun = tun_get(file);
@@ -1356,7 +1392,10 @@ static const struct file_operations tun_fops = {
1356 .write = do_sync_write, 1392 .write = do_sync_write,
1357 .aio_write = tun_chr_aio_write, 1393 .aio_write = tun_chr_aio_write,
1358 .poll = tun_chr_poll, 1394 .poll = tun_chr_poll,
1359 .unlocked_ioctl = tun_chr_ioctl, 1395 .unlocked_ioctl = tun_chr_ioctl,
1396#ifdef CONFIG_COMPAT
1397 .compat_ioctl = tun_chr_compat_ioctl,
1398#endif
1360 .open = tun_chr_open, 1399 .open = tun_chr_open,
1361 .release = tun_chr_close, 1400 .release = tun_chr_close,
1362 .fasync = tun_chr_fasync 1401 .fasync = tun_chr_fasync