diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-07-01 07:53:12 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2018-01-24 19:13:45 -0500 |
commit | 03aef17bb79b3dc02b1352ee2f55fca799dbad7f (patch) | |
tree | 3055b1bbf427f2ee82da08d3a2a95ccabfc75ebb | |
parent | 36fd633ec98acd2028585c22128fcaa3da6d5770 (diff) |
devinet_ioctl(): take copyin/copyout to caller
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | include/linux/inetdevice.h | 2 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 21 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 41 | ||||
-rw-r--r-- | net/ipv4/ipconfig.c | 17 |
4 files changed, 35 insertions, 46 deletions
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 1ac5bf95bfdd..e16fe7d44a71 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h | |||
@@ -173,7 +173,7 @@ static inline struct net_device *ip_dev_find(struct net *net, __be32 addr) | |||
173 | } | 173 | } |
174 | 174 | ||
175 | int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b); | 175 | int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b); |
176 | int devinet_ioctl(struct net *net, unsigned int cmd, void __user *); | 176 | int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *); |
177 | void devinet_init(void); | 177 | void devinet_init(void); |
178 | struct in_device *inetdev_by_index(struct net *, int); | 178 | struct in_device *inetdev_by_index(struct net *, int); |
179 | __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); | 179 | __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 54cccdd8b1e3..1c2bfee2e249 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -872,6 +872,8 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
872 | struct sock *sk = sock->sk; | 872 | struct sock *sk = sock->sk; |
873 | int err = 0; | 873 | int err = 0; |
874 | struct net *net = sock_net(sk); | 874 | struct net *net = sock_net(sk); |
875 | void __user *p = (void __user *)arg; | ||
876 | struct ifreq ifr; | ||
875 | 877 | ||
876 | switch (cmd) { | 878 | switch (cmd) { |
877 | case SIOCGSTAMP: | 879 | case SIOCGSTAMP: |
@@ -891,17 +893,26 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
891 | err = arp_ioctl(net, cmd, (void __user *)arg); | 893 | err = arp_ioctl(net, cmd, (void __user *)arg); |
892 | break; | 894 | break; |
893 | case SIOCGIFADDR: | 895 | case SIOCGIFADDR: |
894 | case SIOCSIFADDR: | ||
895 | case SIOCGIFBRDADDR: | 896 | case SIOCGIFBRDADDR: |
896 | case SIOCSIFBRDADDR: | ||
897 | case SIOCGIFNETMASK: | 897 | case SIOCGIFNETMASK: |
898 | case SIOCSIFNETMASK: | ||
899 | case SIOCGIFDSTADDR: | 898 | case SIOCGIFDSTADDR: |
899 | case SIOCGIFPFLAGS: | ||
900 | if (copy_from_user(&ifr, p, sizeof(struct ifreq))) | ||
901 | return -EFAULT; | ||
902 | err = devinet_ioctl(net, cmd, &ifr); | ||
903 | if (!err && copy_to_user(p, &ifr, sizeof(struct ifreq))) | ||
904 | err = -EFAULT; | ||
905 | break; | ||
906 | |||
907 | case SIOCSIFADDR: | ||
908 | case SIOCSIFBRDADDR: | ||
909 | case SIOCSIFNETMASK: | ||
900 | case SIOCSIFDSTADDR: | 910 | case SIOCSIFDSTADDR: |
901 | case SIOCSIFPFLAGS: | 911 | case SIOCSIFPFLAGS: |
902 | case SIOCGIFPFLAGS: | ||
903 | case SIOCSIFFLAGS: | 912 | case SIOCSIFFLAGS: |
904 | err = devinet_ioctl(net, cmd, (void __user *)arg); | 913 | if (copy_from_user(&ifr, p, sizeof(struct ifreq))) |
914 | return -EFAULT; | ||
915 | err = devinet_ioctl(net, cmd, &ifr); | ||
905 | break; | 916 | break; |
906 | default: | 917 | default: |
907 | if (sk->sk_prot->ioctl) | 918 | if (sk->sk_prot->ioctl) |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 1771549d2438..e056c0067f2c 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -946,11 +946,10 @@ static int inet_abc_len(__be32 addr) | |||
946 | } | 946 | } |
947 | 947 | ||
948 | 948 | ||
949 | int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) | 949 | int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr) |
950 | { | 950 | { |
951 | struct ifreq ifr; | ||
952 | struct sockaddr_in sin_orig; | 951 | struct sockaddr_in sin_orig; |
953 | struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; | 952 | struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr; |
954 | struct in_device *in_dev; | 953 | struct in_device *in_dev; |
955 | struct in_ifaddr **ifap = NULL; | 954 | struct in_ifaddr **ifap = NULL; |
956 | struct in_ifaddr *ifa = NULL; | 955 | struct in_ifaddr *ifa = NULL; |
@@ -959,22 +958,16 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
959 | int ret = -EFAULT; | 958 | int ret = -EFAULT; |
960 | int tryaddrmatch = 0; | 959 | int tryaddrmatch = 0; |
961 | 960 | ||
962 | /* | 961 | ifr->ifr_name[IFNAMSIZ - 1] = 0; |
963 | * Fetch the caller's info block into kernel space | ||
964 | */ | ||
965 | |||
966 | if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) | ||
967 | goto out; | ||
968 | ifr.ifr_name[IFNAMSIZ - 1] = 0; | ||
969 | 962 | ||
970 | /* save original address for comparison */ | 963 | /* save original address for comparison */ |
971 | memcpy(&sin_orig, sin, sizeof(*sin)); | 964 | memcpy(&sin_orig, sin, sizeof(*sin)); |
972 | 965 | ||
973 | colon = strchr(ifr.ifr_name, ':'); | 966 | colon = strchr(ifr->ifr_name, ':'); |
974 | if (colon) | 967 | if (colon) |
975 | *colon = 0; | 968 | *colon = 0; |
976 | 969 | ||
977 | dev_load(net, ifr.ifr_name); | 970 | dev_load(net, ifr->ifr_name); |
978 | 971 | ||
979 | switch (cmd) { | 972 | switch (cmd) { |
980 | case SIOCGIFADDR: /* Get interface address */ | 973 | case SIOCGIFADDR: /* Get interface address */ |
@@ -1014,7 +1007,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
1014 | rtnl_lock(); | 1007 | rtnl_lock(); |
1015 | 1008 | ||
1016 | ret = -ENODEV; | 1009 | ret = -ENODEV; |
1017 | dev = __dev_get_by_name(net, ifr.ifr_name); | 1010 | dev = __dev_get_by_name(net, ifr->ifr_name); |
1018 | if (!dev) | 1011 | if (!dev) |
1019 | goto done; | 1012 | goto done; |
1020 | 1013 | ||
@@ -1031,7 +1024,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
1031 | This is checked above. */ | 1024 | This is checked above. */ |
1032 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; | 1025 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; |
1033 | ifap = &ifa->ifa_next) { | 1026 | ifap = &ifa->ifa_next) { |
1034 | if (!strcmp(ifr.ifr_name, ifa->ifa_label) && | 1027 | if (!strcmp(ifr->ifr_name, ifa->ifa_label) && |
1035 | sin_orig.sin_addr.s_addr == | 1028 | sin_orig.sin_addr.s_addr == |
1036 | ifa->ifa_local) { | 1029 | ifa->ifa_local) { |
1037 | break; /* found */ | 1030 | break; /* found */ |
@@ -1044,7 +1037,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
1044 | if (!ifa) { | 1037 | if (!ifa) { |
1045 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; | 1038 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; |
1046 | ifap = &ifa->ifa_next) | 1039 | ifap = &ifa->ifa_next) |
1047 | if (!strcmp(ifr.ifr_name, ifa->ifa_label)) | 1040 | if (!strcmp(ifr->ifr_name, ifa->ifa_label)) |
1048 | break; | 1041 | break; |
1049 | } | 1042 | } |
1050 | } | 1043 | } |
@@ -1056,19 +1049,19 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
1056 | switch (cmd) { | 1049 | switch (cmd) { |
1057 | case SIOCGIFADDR: /* Get interface address */ | 1050 | case SIOCGIFADDR: /* Get interface address */ |
1058 | sin->sin_addr.s_addr = ifa->ifa_local; | 1051 | sin->sin_addr.s_addr = ifa->ifa_local; |
1059 | goto rarok; | 1052 | break; |
1060 | 1053 | ||
1061 | case SIOCGIFBRDADDR: /* Get the broadcast address */ | 1054 | case SIOCGIFBRDADDR: /* Get the broadcast address */ |
1062 | sin->sin_addr.s_addr = ifa->ifa_broadcast; | 1055 | sin->sin_addr.s_addr = ifa->ifa_broadcast; |
1063 | goto rarok; | 1056 | break; |
1064 | 1057 | ||
1065 | case SIOCGIFDSTADDR: /* Get the destination address */ | 1058 | case SIOCGIFDSTADDR: /* Get the destination address */ |
1066 | sin->sin_addr.s_addr = ifa->ifa_address; | 1059 | sin->sin_addr.s_addr = ifa->ifa_address; |
1067 | goto rarok; | 1060 | break; |
1068 | 1061 | ||
1069 | case SIOCGIFNETMASK: /* Get the netmask for the interface */ | 1062 | case SIOCGIFNETMASK: /* Get the netmask for the interface */ |
1070 | sin->sin_addr.s_addr = ifa->ifa_mask; | 1063 | sin->sin_addr.s_addr = ifa->ifa_mask; |
1071 | goto rarok; | 1064 | break; |
1072 | 1065 | ||
1073 | case SIOCSIFFLAGS: | 1066 | case SIOCSIFFLAGS: |
1074 | if (colon) { | 1067 | if (colon) { |
@@ -1076,11 +1069,11 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
1076 | if (!ifa) | 1069 | if (!ifa) |
1077 | break; | 1070 | break; |
1078 | ret = 0; | 1071 | ret = 0; |
1079 | if (!(ifr.ifr_flags & IFF_UP)) | 1072 | if (!(ifr->ifr_flags & IFF_UP)) |
1080 | inet_del_ifa(in_dev, ifap, 1); | 1073 | inet_del_ifa(in_dev, ifap, 1); |
1081 | break; | 1074 | break; |
1082 | } | 1075 | } |
1083 | ret = dev_change_flags(dev, ifr.ifr_flags); | 1076 | ret = dev_change_flags(dev, ifr->ifr_flags); |
1084 | break; | 1077 | break; |
1085 | 1078 | ||
1086 | case SIOCSIFADDR: /* Set interface address (and family) */ | 1079 | case SIOCSIFADDR: /* Set interface address (and family) */ |
@@ -1095,7 +1088,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
1095 | break; | 1088 | break; |
1096 | INIT_HLIST_NODE(&ifa->hash); | 1089 | INIT_HLIST_NODE(&ifa->hash); |
1097 | if (colon) | 1090 | if (colon) |
1098 | memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ); | 1091 | memcpy(ifa->ifa_label, ifr->ifr_name, IFNAMSIZ); |
1099 | else | 1092 | else |
1100 | memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); | 1093 | memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); |
1101 | } else { | 1094 | } else { |
@@ -1182,10 +1175,6 @@ done: | |||
1182 | rtnl_unlock(); | 1175 | rtnl_unlock(); |
1183 | out: | 1176 | out: |
1184 | return ret; | 1177 | return ret; |
1185 | rarok: | ||
1186 | rtnl_unlock(); | ||
1187 | ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0; | ||
1188 | goto out; | ||
1189 | } | 1178 | } |
1190 | 1179 | ||
1191 | static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size) | 1180 | static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size) |
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index e9e488e72900..6895fff609b1 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
@@ -329,17 +329,6 @@ set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) | |||
329 | sin->sin_port = port; | 329 | sin->sin_port = port; |
330 | } | 330 | } |
331 | 331 | ||
332 | static int __init ic_devinet_ioctl(unsigned int cmd, struct ifreq *arg) | ||
333 | { | ||
334 | int res; | ||
335 | |||
336 | mm_segment_t oldfs = get_fs(); | ||
337 | set_fs(get_ds()); | ||
338 | res = devinet_ioctl(&init_net, cmd, (struct ifreq __user *) arg); | ||
339 | set_fs(oldfs); | ||
340 | return res; | ||
341 | } | ||
342 | |||
343 | static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) | 332 | static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) |
344 | { | 333 | { |
345 | int res; | 334 | int res; |
@@ -375,19 +364,19 @@ static int __init ic_setup_if(void) | |||
375 | memset(&ir, 0, sizeof(ir)); | 364 | memset(&ir, 0, sizeof(ir)); |
376 | strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->dev->name); | 365 | strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->dev->name); |
377 | set_sockaddr(sin, ic_myaddr, 0); | 366 | set_sockaddr(sin, ic_myaddr, 0); |
378 | if ((err = ic_devinet_ioctl(SIOCSIFADDR, &ir)) < 0) { | 367 | if ((err = devinet_ioctl(&init_net, SIOCSIFADDR, &ir)) < 0) { |
379 | pr_err("IP-Config: Unable to set interface address (%d)\n", | 368 | pr_err("IP-Config: Unable to set interface address (%d)\n", |
380 | err); | 369 | err); |
381 | return -1; | 370 | return -1; |
382 | } | 371 | } |
383 | set_sockaddr(sin, ic_netmask, 0); | 372 | set_sockaddr(sin, ic_netmask, 0); |
384 | if ((err = ic_devinet_ioctl(SIOCSIFNETMASK, &ir)) < 0) { | 373 | if ((err = devinet_ioctl(&init_net, SIOCSIFNETMASK, &ir)) < 0) { |
385 | pr_err("IP-Config: Unable to set interface netmask (%d)\n", | 374 | pr_err("IP-Config: Unable to set interface netmask (%d)\n", |
386 | err); | 375 | err); |
387 | return -1; | 376 | return -1; |
388 | } | 377 | } |
389 | set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0); | 378 | set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0); |
390 | if ((err = ic_devinet_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { | 379 | if ((err = devinet_ioctl(&init_net, SIOCSIFBRDADDR, &ir)) < 0) { |
391 | pr_err("IP-Config: Unable to set interface broadcast address (%d)\n", | 380 | pr_err("IP-Config: Unable to set interface broadcast address (%d)\n", |
392 | err); | 381 | err); |
393 | return -1; | 382 | return -1; |