aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-06-26 13:19:16 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2018-01-24 19:13:45 -0500
commit36fd633ec98acd2028585c22128fcaa3da6d5770 (patch)
tree1fa77e8bf1662dea936b52107a0d39485110edb1 /net/ipv4
parentbe1b6e8b5470e8311bfa1a3dfd7bd59e85a99759 (diff)
net: separate SIOCGIFCONF handling from dev_ioctl()
Only two of dev_ioctl() callers may pass SIOCGIFCONF to it. Separating that codepath from the rest of dev_ioctl() allows both to simplify dev_ioctl() itself (all other cases work with struct ifreq *) *and* seriously simplify the compat side of that beast: all it takes is passing to inet_gifconf() an extra argument - the size of individual records (sizeof(struct ifreq) or sizeof(struct compat_ifreq)). With dev_ifconf() called directly from sock_do_ioctl()/compat_dev_ifconf() that's easy to arrange. As the result, compat side of SIOCGIFCONF doesn't need any allocations, copy_in_user() back and forth, etc. Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/devinet.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 7a93359fbc72..1771549d2438 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1188,22 +1188,25 @@ rarok:
1188 goto out; 1188 goto out;
1189} 1189}
1190 1190
1191static int inet_gifconf(struct net_device *dev, char __user *buf, int len) 1191static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
1192{ 1192{
1193 struct in_device *in_dev = __in_dev_get_rtnl(dev); 1193 struct in_device *in_dev = __in_dev_get_rtnl(dev);
1194 struct in_ifaddr *ifa; 1194 struct in_ifaddr *ifa;
1195 struct ifreq ifr; 1195 struct ifreq ifr;
1196 int done = 0; 1196 int done = 0;
1197 1197
1198 if (WARN_ON(size > sizeof(struct ifreq)))
1199 goto out;
1200
1198 if (!in_dev) 1201 if (!in_dev)
1199 goto out; 1202 goto out;
1200 1203
1201 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { 1204 for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
1202 if (!buf) { 1205 if (!buf) {
1203 done += sizeof(ifr); 1206 done += size;
1204 continue; 1207 continue;
1205 } 1208 }
1206 if (len < (int) sizeof(ifr)) 1209 if (len < size)
1207 break; 1210 break;
1208 memset(&ifr, 0, sizeof(struct ifreq)); 1211 memset(&ifr, 0, sizeof(struct ifreq));
1209 strcpy(ifr.ifr_name, ifa->ifa_label); 1212 strcpy(ifr.ifr_name, ifa->ifa_label);
@@ -1212,13 +1215,12 @@ static int inet_gifconf(struct net_device *dev, char __user *buf, int len)
1212 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr = 1215 (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
1213 ifa->ifa_local; 1216 ifa->ifa_local;
1214 1217
1215 if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) { 1218 if (copy_to_user(buf + done, &ifr, size)) {
1216 done = -EFAULT; 1219 done = -EFAULT;
1217 break; 1220 break;
1218 } 1221 }
1219 buf += sizeof(struct ifreq); 1222 len -= size;
1220 len -= sizeof(struct ifreq); 1223 done += size;
1221 done += sizeof(struct ifreq);
1222 } 1224 }
1223out: 1225out:
1224 return done; 1226 return done;