Commit 87de87d5e47f94b4ea647a5bd1bc8dc1f7930db4
1 parent
a67fa76d8b
Exists in
master
and in
4 other branches
wext: Dispatch and handle compat ioctls entirely in net/wireless/wext.c
Next we can kill the hacks in fs/compat_ioctl.c and also dispatch compat ioctls down into the driver and 80211 protocol helper layers in order to handle iw_point objects embedded in stream replies which need to be translated. Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 5 changed files with 134 additions and 6 deletions Side-by-side Diff
fs/compat_ioctl.c
... | ... | @@ -1757,12 +1757,6 @@ |
1757 | 1757 | return sys_ioctl(fd, cmd, (unsigned long)tdata); |
1758 | 1758 | } |
1759 | 1759 | |
1760 | -struct compat_iw_point { | |
1761 | - compat_caddr_t pointer; | |
1762 | - __u16 length; | |
1763 | - __u16 flags; | |
1764 | -}; | |
1765 | - | |
1766 | 1760 | static int do_wireless_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) |
1767 | 1761 | { |
1768 | 1762 | struct iwreq __user *iwr; |
include/linux/wireless.h
... | ... | @@ -677,6 +677,19 @@ |
677 | 677 | __u16 flags; /* Optional params */ |
678 | 678 | }; |
679 | 679 | |
680 | +#ifdef __KERNEL__ | |
681 | +#ifdef CONFIG_COMPAT | |
682 | + | |
683 | +#include <linux/compat.h> | |
684 | + | |
685 | +struct compat_iw_point { | |
686 | + compat_caddr_t pointer; | |
687 | + __u16 length; | |
688 | + __u16 flags; | |
689 | +}; | |
690 | +#endif | |
691 | +#endif | |
692 | + | |
680 | 693 | /* |
681 | 694 | * A frequency |
682 | 695 | * For numbers lower than 10^9, we encode the number in 'm' and |
include/net/wext.h
... | ... | @@ -12,6 +12,8 @@ |
12 | 12 | extern void wext_proc_exit(struct net *net); |
13 | 13 | extern int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, |
14 | 14 | void __user *arg); |
15 | +extern int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, | |
16 | + unsigned long arg); | |
15 | 17 | #else |
16 | 18 | static inline int wext_proc_init(struct net *net) |
17 | 19 | { |
... | ... | @@ -23,6 +25,11 @@ |
23 | 25 | } |
24 | 26 | static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, |
25 | 27 | void __user *arg) |
28 | +{ | |
29 | + return -EINVAL; | |
30 | +} | |
31 | +static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, | |
32 | + unsigned long arg) | |
26 | 33 | { |
27 | 34 | return -EINVAL; |
28 | 35 | } |
net/socket.c
... | ... | @@ -90,6 +90,7 @@ |
90 | 90 | #include <asm/unistd.h> |
91 | 91 | |
92 | 92 | #include <net/compat.h> |
93 | +#include <net/wext.h> | |
93 | 94 | |
94 | 95 | #include <net/sock.h> |
95 | 96 | #include <linux/netfilter.h> |
96 | 97 | |
97 | 98 | |
... | ... | @@ -2210,9 +2211,18 @@ |
2210 | 2211 | { |
2211 | 2212 | struct socket *sock = file->private_data; |
2212 | 2213 | int ret = -ENOIOCTLCMD; |
2214 | + struct sock *sk; | |
2215 | + struct net *net; | |
2213 | 2216 | |
2217 | + sk = sock->sk; | |
2218 | + net = sock_net(sk); | |
2219 | + | |
2214 | 2220 | if (sock->ops->compat_ioctl) |
2215 | 2221 | ret = sock->ops->compat_ioctl(sock, cmd, arg); |
2222 | + | |
2223 | + if (ret == -ENOIOCTLCMD && | |
2224 | + (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) | |
2225 | + ret = compat_wext_handle_ioctl(net, cmd, arg); | |
2216 | 2226 | |
2217 | 2227 | return ret; |
2218 | 2228 | } |
net/wireless/wext.c
... | ... | @@ -1112,6 +1112,110 @@ |
1112 | 1112 | return ret; |
1113 | 1113 | } |
1114 | 1114 | |
1115 | +#ifdef CONFIG_COMPAT | |
1116 | +static int compat_standard_call(struct net_device *dev, | |
1117 | + struct iwreq *iwr, | |
1118 | + unsigned int cmd, | |
1119 | + iw_handler handler) | |
1120 | +{ | |
1121 | + const struct iw_ioctl_description *descr; | |
1122 | + struct compat_iw_point *iwp_compat; | |
1123 | + struct iw_request_info info; | |
1124 | + struct iw_point iwp; | |
1125 | + int err; | |
1126 | + | |
1127 | + descr = standard_ioctl + (cmd - SIOCIWFIRST); | |
1128 | + | |
1129 | + if (descr->header_type != IW_HEADER_TYPE_POINT) | |
1130 | + return ioctl_standard_call(dev, iwr, cmd, handler); | |
1131 | + | |
1132 | + iwp_compat = (struct compat_iw_point *) &iwr->u.data; | |
1133 | + iwp.pointer = compat_ptr(iwp_compat->pointer); | |
1134 | + iwp.length = iwp_compat->length; | |
1135 | + iwp.flags = iwp_compat->flags; | |
1136 | + | |
1137 | + info.cmd = cmd; | |
1138 | + info.flags = 0; | |
1139 | + | |
1140 | + err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, &info); | |
1141 | + | |
1142 | + iwp_compat->pointer = ptr_to_compat(iwp.pointer); | |
1143 | + iwp_compat->length = iwp.length; | |
1144 | + iwp_compat->flags = iwp.flags; | |
1145 | + | |
1146 | + return err; | |
1147 | +} | |
1148 | + | |
1149 | +static int compat_private_call(struct net_device *dev, struct iwreq *iwr, | |
1150 | + unsigned int cmd, iw_handler handler) | |
1151 | +{ | |
1152 | + const struct iw_priv_args *descr; | |
1153 | + struct iw_request_info info; | |
1154 | + int ret, extra_size; | |
1155 | + | |
1156 | + extra_size = get_priv_descr_and_size(dev, cmd, &descr); | |
1157 | + | |
1158 | + /* Prepare the call */ | |
1159 | + info.cmd = cmd; | |
1160 | + info.flags = 0; | |
1161 | + | |
1162 | + /* Check if we have a pointer to user space data or not. */ | |
1163 | + if (extra_size == 0) { | |
1164 | + /* No extra arguments. Trivial to handle */ | |
1165 | + ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); | |
1166 | + } else { | |
1167 | + struct compat_iw_point *iwp_compat; | |
1168 | + struct iw_point iwp; | |
1169 | + | |
1170 | + iwp_compat = (struct compat_iw_point *) &iwr->u.data; | |
1171 | + iwp.pointer = compat_ptr(iwp_compat->pointer); | |
1172 | + iwp.length = iwp_compat->length; | |
1173 | + iwp.flags = iwp_compat->flags; | |
1174 | + | |
1175 | + ret = ioctl_private_iw_point(&iwp, cmd, descr, | |
1176 | + handler, dev, &info, extra_size); | |
1177 | + | |
1178 | + iwp_compat->pointer = ptr_to_compat(iwp.pointer); | |
1179 | + iwp_compat->length = iwp.length; | |
1180 | + iwp_compat->flags = iwp.flags; | |
1181 | + } | |
1182 | + | |
1183 | + /* Call commit handler if needed and defined */ | |
1184 | + if (ret == -EIWCOMMIT) | |
1185 | + ret = call_commit_handler(dev); | |
1186 | + | |
1187 | + return ret; | |
1188 | +} | |
1189 | + | |
1190 | +int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, | |
1191 | + unsigned long arg) | |
1192 | +{ | |
1193 | + void __user *argp = (void __user *)arg; | |
1194 | + struct iwreq iwr; | |
1195 | + char *colon; | |
1196 | + int ret; | |
1197 | + | |
1198 | + if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) | |
1199 | + return -EFAULT; | |
1200 | + | |
1201 | + iwr.ifr_name[IFNAMSIZ-1] = 0; | |
1202 | + colon = strchr(iwr.ifr_name, ':'); | |
1203 | + if (colon) | |
1204 | + *colon = 0; | |
1205 | + | |
1206 | + ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, | |
1207 | + compat_standard_call, | |
1208 | + compat_private_call); | |
1209 | + | |
1210 | + if (ret >= 0 && | |
1211 | + IW_IS_GET(cmd) && | |
1212 | + copy_to_user(argp, &iwr, sizeof(struct iwreq))) | |
1213 | + return -EFAULT; | |
1214 | + | |
1215 | + return ret; | |
1216 | +} | |
1217 | +#endif | |
1218 | + | |
1115 | 1219 | /************************* EVENT PROCESSING *************************/ |
1116 | 1220 | /* |
1117 | 1221 | * Process events generated by the wireless layer or the driver. |