diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3a16d4fdaa05..498dc0d4ba5e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -120,8 +120,8 @@ struct tun_sock; | |||
120 | struct tun_struct { | 120 | struct tun_struct { |
121 | struct tun_file *tfile; | 121 | struct tun_file *tfile; |
122 | unsigned int flags; | 122 | unsigned int flags; |
123 | uid_t owner; | 123 | kuid_t owner; |
124 | gid_t group; | 124 | kgid_t group; |
125 | 125 | ||
126 | struct net_device *dev; | 126 | struct net_device *dev; |
127 | netdev_features_t set_features; | 127 | netdev_features_t set_features; |
@@ -1031,8 +1031,8 @@ static void tun_setup(struct net_device *dev) | |||
1031 | { | 1031 | { |
1032 | struct tun_struct *tun = netdev_priv(dev); | 1032 | struct tun_struct *tun = netdev_priv(dev); |
1033 | 1033 | ||
1034 | tun->owner = -1; | 1034 | tun->owner = INVALID_UID; |
1035 | tun->group = -1; | 1035 | tun->group = INVALID_GID; |
1036 | 1036 | ||
1037 | dev->ethtool_ops = &tun_ethtool_ops; | 1037 | dev->ethtool_ops = &tun_ethtool_ops; |
1038 | dev->destructor = tun_free_netdev; | 1038 | dev->destructor = tun_free_netdev; |
@@ -1155,14 +1155,20 @@ static ssize_t tun_show_owner(struct device *dev, struct device_attribute *attr, | |||
1155 | char *buf) | 1155 | char *buf) |
1156 | { | 1156 | { |
1157 | struct tun_struct *tun = netdev_priv(to_net_dev(dev)); | 1157 | struct tun_struct *tun = netdev_priv(to_net_dev(dev)); |
1158 | return sprintf(buf, "%d\n", tun->owner); | 1158 | return uid_valid(tun->owner)? |
1159 | sprintf(buf, "%u\n", | ||
1160 | from_kuid_munged(current_user_ns(), tun->owner)): | ||
1161 | sprintf(buf, "-1\n"); | ||
1159 | } | 1162 | } |
1160 | 1163 | ||
1161 | static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr, | 1164 | static ssize_t tun_show_group(struct device *dev, struct device_attribute *attr, |
1162 | char *buf) | 1165 | char *buf) |
1163 | { | 1166 | { |
1164 | struct tun_struct *tun = netdev_priv(to_net_dev(dev)); | 1167 | struct tun_struct *tun = netdev_priv(to_net_dev(dev)); |
1165 | return sprintf(buf, "%d\n", tun->group); | 1168 | return gid_valid(tun->group) ? |
1169 | sprintf(buf, "%u\n", | ||
1170 | from_kgid_munged(current_user_ns(), tun->group)): | ||
1171 | sprintf(buf, "-1\n"); | ||
1166 | } | 1172 | } |
1167 | 1173 | ||
1168 | static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL); | 1174 | static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL); |
@@ -1189,8 +1195,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) | |||
1189 | else | 1195 | else |
1190 | return -EINVAL; | 1196 | return -EINVAL; |
1191 | 1197 | ||
1192 | if (((tun->owner != -1 && cred->euid != tun->owner) || | 1198 | if (((uid_valid(tun->owner) && !uid_eq(cred->euid, tun->owner)) || |
1193 | (tun->group != -1 && !in_egroup_p(tun->group))) && | 1199 | (gid_valid(tun->group) && !in_egroup_p(tun->group))) && |
1194 | !capable(CAP_NET_ADMIN)) | 1200 | !capable(CAP_NET_ADMIN)) |
1195 | return -EPERM; | 1201 | return -EPERM; |
1196 | err = security_tun_dev_attach(tun->socket.sk); | 1202 | err = security_tun_dev_attach(tun->socket.sk); |
@@ -1374,6 +1380,8 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1374 | void __user* argp = (void __user*)arg; | 1380 | void __user* argp = (void __user*)arg; |
1375 | struct sock_fprog fprog; | 1381 | struct sock_fprog fprog; |
1376 | struct ifreq ifr; | 1382 | struct ifreq ifr; |
1383 | kuid_t owner; | ||
1384 | kgid_t group; | ||
1377 | int sndbuf; | 1385 | int sndbuf; |
1378 | int vnet_hdr_sz; | 1386 | int vnet_hdr_sz; |
1379 | int ret; | 1387 | int ret; |
@@ -1447,16 +1455,26 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
1447 | 1455 | ||
1448 | case TUNSETOWNER: | 1456 | case TUNSETOWNER: |
1449 | /* Set owner of the device */ | 1457 | /* Set owner of the device */ |
1450 | tun->owner = (uid_t) arg; | 1458 | owner = make_kuid(current_user_ns(), arg); |
1451 | 1459 | if (!uid_valid(owner)) { | |
1452 | tun_debug(KERN_INFO, tun, "owner set to %d\n", tun->owner); | 1460 | ret = -EINVAL; |
1461 | break; | ||
1462 | } | ||
1463 | tun->owner = owner; | ||
1464 | tun_debug(KERN_INFO, tun, "owner set to %d\n", | ||
1465 | from_kuid(&init_user_ns, tun->owner)); | ||
1453 | break; | 1466 | break; |
1454 | 1467 | ||
1455 | case TUNSETGROUP: | 1468 | case TUNSETGROUP: |
1456 | /* Set group of the device */ | 1469 | /* Set group of the device */ |
1457 | tun->group= (gid_t) arg; | 1470 | group = make_kgid(current_user_ns(), arg); |
1458 | 1471 | if (!gid_valid(group)) { | |
1459 | tun_debug(KERN_INFO, tun, "group set to %d\n", tun->group); | 1472 | ret = -EINVAL; |
1473 | break; | ||
1474 | } | ||
1475 | tun->group = group; | ||
1476 | tun_debug(KERN_INFO, tun, "group set to %d\n", | ||
1477 | from_kgid(&init_user_ns, tun->group)); | ||
1460 | break; | 1478 | break; |
1461 | 1479 | ||
1462 | case TUNSETLINK: | 1480 | case TUNSETLINK: |