Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dev_ioctl: pass SIOCDEVPRIVATE data separately

The compat handlers for SIOCDEVPRIVATE are incorrect for any driver that
passes data as part of struct ifreq rather than as an ifr_data pointer, or
that passes data back this way, since the compat_ifr_data_ioctl() helper
overwrites the ifr_data pointer and does not copy anything back out.

Since all drivers using devprivate commands are now converted to the
new .ndo_siocdevprivate callback, fix this by adding the missing piece
and passing the pointer separately the whole way.

This further unifies the native and compat logic for socket ioctls,
as the new code now passes the correct pointer as well as the correct
data for both native and compat ioctls.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Arnd Bergmann and committed by
David S. Miller
a554bf96 8fb75b79

+28 -56
+2 -2
include/linux/netdevice.h
··· 4012 4012 int get_user_ifreq(struct ifreq *ifr, void __user **ifrdata, void __user *arg); 4013 4013 int put_user_ifreq(struct ifreq *ifr, void __user *arg); 4014 4014 int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, 4015 - bool *need_copyout); 4015 + void __user *data, bool *need_copyout); 4016 4016 int dev_ifconf(struct net *net, struct ifconf __user *ifc); 4017 - int dev_ethtool(struct net *net, struct ifreq *); 4017 + int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *userdata); 4018 4018 unsigned int dev_get_flags(const struct net_device *); 4019 4019 int __dev_change_flags(struct net_device *dev, unsigned int flags, 4020 4020 struct netlink_ext_ack *extack);
+12 -10
net/core/dev_ioctl.c
··· 259 259 return err; 260 260 } 261 261 262 - static int dev_siocdevprivate(struct net_device *dev, 263 - struct ifreq *ifr, unsigned int cmd) 262 + static int dev_siocdevprivate(struct net_device *dev, struct ifreq *ifr, 263 + void __user *data, unsigned int cmd) 264 264 { 265 265 const struct net_device_ops *ops = dev->netdev_ops; 266 - void __user *data = ifr->ifr_data; 267 266 268 267 if (ops->ndo_siocdevprivate) { 269 268 if (netif_device_present(dev)) ··· 272 273 } 273 274 274 275 /* fall back to do_ioctl for drivers not yet converted */ 276 + ifr->ifr_data = data; 275 277 return dev_do_ioctl(dev, ifr, cmd); 276 278 } 277 279 278 280 /* 279 281 * Perform the SIOCxIFxxx calls, inside rtnl_lock() 280 282 */ 281 - static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) 283 + static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data, 284 + unsigned int cmd) 282 285 { 283 286 int err; 284 287 struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); ··· 356 355 default: 357 356 if (cmd >= SIOCDEVPRIVATE && 358 357 cmd <= SIOCDEVPRIVATE + 15) 359 - return dev_siocdevprivate(dev, ifr, cmd); 358 + return dev_siocdevprivate(dev, ifr, data, cmd); 360 359 361 360 if (cmd == SIOCBONDENSLAVE || 362 361 cmd == SIOCBONDRELEASE || ··· 425 424 * positive or a negative errno code on error. 426 425 */ 427 426 428 - int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_copyout) 427 + int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, 428 + void __user *data, bool *need_copyout) 429 429 { 430 430 int ret; 431 431 char *colon; ··· 477 475 case SIOCETHTOOL: 478 476 dev_load(net, ifr->ifr_name); 479 477 rtnl_lock(); 480 - ret = dev_ethtool(net, ifr); 478 + ret = dev_ethtool(net, ifr, data); 481 479 rtnl_unlock(); 482 480 if (colon) 483 481 *colon = ':'; ··· 496 494 if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 497 495 return -EPERM; 498 496 rtnl_lock(); 499 - ret = dev_ifsioc(net, ifr, cmd); 497 + ret = dev_ifsioc(net, ifr, data, cmd); 500 498 rtnl_unlock(); 501 499 if (colon) 502 500 *colon = ':'; ··· 542 540 case SIOCBONDINFOQUERY: 543 541 dev_load(net, ifr->ifr_name); 544 542 rtnl_lock(); 545 - ret = dev_ifsioc(net, ifr, cmd); 543 + ret = dev_ifsioc(net, ifr, data, cmd); 546 544 rtnl_unlock(); 547 545 if (need_copyout) 548 546 *need_copyout = false; ··· 567 565 cmd <= SIOCDEVPRIVATE + 15)) { 568 566 dev_load(net, ifr->ifr_name); 569 567 rtnl_lock(); 570 - ret = dev_ifsioc(net, ifr, cmd); 568 + ret = dev_ifsioc(net, ifr, data, cmd); 571 569 rtnl_unlock(); 572 570 return ret; 573 571 }
+1 -2
net/ethtool/ioctl.c
··· 2685 2685 2686 2686 /* The main entry point in this file. Called from net/core/dev_ioctl.c */ 2687 2687 2688 - int dev_ethtool(struct net *net, struct ifreq *ifr) 2688 + int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr) 2689 2689 { 2690 2690 struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); 2691 - void __user *useraddr = ifr->ifr_data; 2692 2691 u32 ethcmd, sub_cmd; 2693 2692 int rc; 2694 2693 netdev_features_t old_features;
+13 -42
net/socket.c
··· 1092 1092 bool need_copyout; 1093 1093 int err; 1094 1094 void __user *argp = (void __user *)arg; 1095 + void __user *data; 1095 1096 1096 1097 err = sock->ops->ioctl(sock, cmd, arg); 1097 1098 ··· 1103 1102 if (err != -ENOIOCTLCMD) 1104 1103 return err; 1105 1104 1106 - if (copy_from_user(&ifr, argp, sizeof(struct ifreq))) 1105 + if (get_user_ifreq(&ifr, &data, argp)) 1107 1106 return -EFAULT; 1108 - err = dev_ioctl(net, cmd, &ifr, &need_copyout); 1107 + err = dev_ioctl(net, cmd, &ifr, data, &need_copyout); 1109 1108 if (!err && need_copyout) 1110 - if (copy_to_user(argp, &ifr, sizeof(struct ifreq))) 1109 + if (put_user_ifreq(&ifr, argp)) 1111 1110 return -EFAULT; 1112 1111 1113 1112 return err; ··· 1131 1130 net = sock_net(sk); 1132 1131 if (unlikely(cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15))) { 1133 1132 struct ifreq ifr; 1133 + void __user *data; 1134 1134 bool need_copyout; 1135 - if (copy_from_user(&ifr, argp, sizeof(struct ifreq))) 1135 + if (get_user_ifreq(&ifr, &data, argp)) 1136 1136 return -EFAULT; 1137 - err = dev_ioctl(net, cmd, &ifr, &need_copyout); 1137 + err = dev_ioctl(net, cmd, &ifr, data, &need_copyout); 1138 1138 if (!err && need_copyout) 1139 - if (copy_to_user(argp, &ifr, sizeof(struct ifreq))) 1139 + if (put_user_ifreq(&ifr, argp)) 1140 1140 return -EFAULT; 1141 1141 } else 1142 1142 #ifdef CONFIG_WEXT_CORE ··· 3188 3186 saved = ifr.ifr_settings.ifs_ifsu.raw_hdlc; 3189 3187 ifr.ifr_settings.ifs_ifsu.raw_hdlc = compat_ptr(uptr32); 3190 3188 3191 - err = dev_ioctl(net, SIOCWANDEV, &ifr, NULL); 3189 + err = dev_ioctl(net, SIOCWANDEV, &ifr, NULL, NULL); 3192 3190 if (!err) { 3193 3191 ifr.ifr_settings.ifs_ifsu.raw_hdlc = saved; 3194 3192 if (put_user_ifreq(&ifr, uifr32)) ··· 3202 3200 struct compat_ifreq __user *u_ifreq32) 3203 3201 { 3204 3202 struct ifreq ifreq; 3205 - u32 data32; 3203 + void __user *data; 3206 3204 3207 - if (copy_from_user(ifreq.ifr_name, u_ifreq32->ifr_name, IFNAMSIZ)) 3205 + if (get_user_ifreq(&ifreq, &data, u_ifreq32)) 3208 3206 return -EFAULT; 3209 - if (get_user(data32, &u_ifreq32->ifr_data)) 3210 - return -EFAULT; 3211 - ifreq.ifr_data = compat_ptr(data32); 3207 + ifreq.ifr_data = data; 3212 3208 3213 - return dev_ioctl(net, cmd, &ifreq, NULL); 3214 - } 3215 - 3216 - static int compat_ifreq_ioctl(struct net *net, struct socket *sock, 3217 - unsigned int cmd, 3218 - unsigned long arg, 3219 - struct compat_ifreq __user *uifr32) 3220 - { 3221 - struct ifreq ifr; 3222 - bool need_copyout; 3223 - int err; 3224 - 3225 - err = sock->ops->ioctl(sock, cmd, arg); 3226 - 3227 - /* If this ioctl is unknown try to hand it down 3228 - * to the NIC driver. 3229 - */ 3230 - if (err != -ENOIOCTLCMD) 3231 - return err; 3232 - 3233 - if (get_user_ifreq(&ifr, NULL, uifr32)) 3234 - return -EFAULT; 3235 - err = dev_ioctl(net, cmd, &ifr, &need_copyout); 3236 - if (!err && need_copyout) 3237 - if (put_user_ifreq(&ifr, uifr32)) 3238 - return -EFAULT; 3239 - 3240 - return err; 3209 + return dev_ioctl(net, cmd, &ifreq, data, NULL); 3241 3210 } 3242 3211 3243 3212 /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE ··· 3310 3337 case SIOCBONDRELEASE: 3311 3338 case SIOCBONDSETHWADDR: 3312 3339 case SIOCBONDCHANGEACTIVE: 3313 - return compat_ifreq_ioctl(net, sock, cmd, arg, argp); 3314 - 3315 3340 case SIOCSARP: 3316 3341 case SIOCGARP: 3317 3342 case SIOCDARP: