aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-10-05 12:59:44 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2018-01-24 19:13:45 -0500
commit44c02a2c3dc55835e9f0d8ef73966406cd805001 (patch)
treee75ed9a07fdb0eae51502e0e62f57bb9cf870501
parent6a88fbe7257282c19c777d5fe310166e5b3089e8 (diff)
dev_ioctl(): move copyin/copyout to callers
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--net/core/dev_ioctl.c85
-rw-r--r--net/socket.c91
3 files changed, 71 insertions, 108 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index df5565d0369c..24a62d590350 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3315,7 +3315,8 @@ int netdev_rx_handler_register(struct net_device *dev,
3315void netdev_rx_handler_unregister(struct net_device *dev); 3315void netdev_rx_handler_unregister(struct net_device *dev);
3316 3316
3317bool dev_valid_name(const char *name); 3317bool dev_valid_name(const char *name);
3318int dev_ioctl(struct net *net, unsigned int cmd, void __user *); 3318int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,
3319 bool *need_copyout);
3319int dev_ifconf(struct net *net, struct ifconf *, int); 3320int dev_ifconf(struct net *net, struct ifconf *, int);
3320int dev_ethtool(struct net *net, struct ifreq *); 3321int dev_ethtool(struct net *net, struct ifreq *);
3321unsigned int dev_get_flags(const struct net_device *); 3322unsigned int dev_get_flags(const struct net_device *);
diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c
index d262f159f9fd..0ab1af04296c 100644
--- a/net/core/dev_ioctl.c
+++ b/net/core/dev_ioctl.c
@@ -18,26 +18,10 @@
18 * match. --pb 18 * match. --pb
19 */ 19 */
20 20
21static int dev_ifname(struct net *net, struct ifreq __user *arg) 21static int dev_ifname(struct net *net, struct ifreq *ifr)
22{ 22{
23 struct ifreq ifr; 23 ifr->ifr_name[IFNAMSIZ-1] = 0;
24 int error; 24 return netdev_get_name(net, ifr->ifr_name, ifr->ifr_ifindex);
25
26 /*
27 * Fetch the caller's info block.
28 */
29
30 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
31 return -EFAULT;
32 ifr.ifr_name[IFNAMSIZ-1] = 0;
33
34 error = netdev_get_name(net, ifr.ifr_name, ifr.ifr_ifindex);
35 if (error)
36 return error;
37
38 if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
39 return -EFAULT;
40 return 0;
41} 25}
42 26
43static gifconf_func_t *gifconf_list[NPROTO]; 27static gifconf_func_t *gifconf_list[NPROTO];
@@ -402,24 +386,24 @@ EXPORT_SYMBOL(dev_load);
402 * positive or a negative errno code on error. 386 * positive or a negative errno code on error.
403 */ 387 */
404 388
405int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) 389int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_copyout)
406{ 390{
407 struct ifreq ifr;
408 int ret; 391 int ret;
409 char *colon; 392 char *colon;
410 393
394 if (need_copyout)
395 *need_copyout = true;
411 if (cmd == SIOCGIFNAME) 396 if (cmd == SIOCGIFNAME)
412 return dev_ifname(net, (struct ifreq __user *)arg); 397 return dev_ifname(net, ifr);
413
414 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
415 return -EFAULT;
416 398
417 ifr.ifr_name[IFNAMSIZ-1] = 0; 399 ifr->ifr_name[IFNAMSIZ-1] = 0;
418 400
419 colon = strchr(ifr.ifr_name, ':'); 401 colon = strchr(ifr->ifr_name, ':');
420 if (colon) 402 if (colon)
421 *colon = 0; 403 *colon = 0;
422 404
405 dev_load(net, ifr->ifr_name);
406
423 /* 407 /*
424 * See which interface the caller is talking about. 408 * See which interface the caller is talking about.
425 */ 409 */
@@ -439,31 +423,19 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
439 case SIOCGIFMAP: 423 case SIOCGIFMAP:
440 case SIOCGIFINDEX: 424 case SIOCGIFINDEX:
441 case SIOCGIFTXQLEN: 425 case SIOCGIFTXQLEN:
442 dev_load(net, ifr.ifr_name);
443 rcu_read_lock(); 426 rcu_read_lock();
444 ret = dev_ifsioc_locked(net, &ifr, cmd); 427 ret = dev_ifsioc_locked(net, ifr, cmd);
445 rcu_read_unlock(); 428 rcu_read_unlock();
446 if (!ret) { 429 if (colon)
447 if (colon) 430 *colon = ':';
448 *colon = ':';
449 if (copy_to_user(arg, &ifr,
450 sizeof(struct ifreq)))
451 ret = -EFAULT;
452 }
453 return ret; 431 return ret;
454 432
455 case SIOCETHTOOL: 433 case SIOCETHTOOL:
456 dev_load(net, ifr.ifr_name);
457 rtnl_lock(); 434 rtnl_lock();
458 ret = dev_ethtool(net, &ifr); 435 ret = dev_ethtool(net, ifr);
459 rtnl_unlock(); 436 rtnl_unlock();
460 if (!ret) { 437 if (colon)
461 if (colon) 438 *colon = ':';
462 *colon = ':';
463 if (copy_to_user(arg, &ifr,
464 sizeof(struct ifreq)))
465 ret = -EFAULT;
466 }
467 return ret; 439 return ret;
468 440
469 /* 441 /*
@@ -477,17 +449,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
477 case SIOCSIFNAME: 449 case SIOCSIFNAME:
478 if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 450 if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
479 return -EPERM; 451 return -EPERM;
480 dev_load(net, ifr.ifr_name);
481 rtnl_lock(); 452 rtnl_lock();
482 ret = dev_ifsioc(net, &ifr, cmd); 453 ret = dev_ifsioc(net, ifr, cmd);
483 rtnl_unlock(); 454 rtnl_unlock();
484 if (!ret) { 455 if (colon)
485 if (colon) 456 *colon = ':';
486 *colon = ':';
487 if (copy_to_user(arg, &ifr,
488 sizeof(struct ifreq)))
489 ret = -EFAULT;
490 }
491 return ret; 457 return ret;
492 458
493 /* 459 /*
@@ -528,10 +494,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
528 /* fall through */ 494 /* fall through */
529 case SIOCBONDSLAVEINFOQUERY: 495 case SIOCBONDSLAVEINFOQUERY:
530 case SIOCBONDINFOQUERY: 496 case SIOCBONDINFOQUERY:
531 dev_load(net, ifr.ifr_name);
532 rtnl_lock(); 497 rtnl_lock();
533 ret = dev_ifsioc(net, &ifr, cmd); 498 ret = dev_ifsioc(net, ifr, cmd);
534 rtnl_unlock(); 499 rtnl_unlock();
500 if (need_copyout)
501 *need_copyout = false;
535 return ret; 502 return ret;
536 503
537 case SIOCGIFMEM: 504 case SIOCGIFMEM:
@@ -551,13 +518,9 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
551 cmd == SIOCGHWTSTAMP || 518 cmd == SIOCGHWTSTAMP ||
552 (cmd >= SIOCDEVPRIVATE && 519 (cmd >= SIOCDEVPRIVATE &&
553 cmd <= SIOCDEVPRIVATE + 15)) { 520 cmd <= SIOCDEVPRIVATE + 15)) {
554 dev_load(net, ifr.ifr_name);
555 rtnl_lock(); 521 rtnl_lock();
556 ret = dev_ifsioc(net, &ifr, cmd); 522 ret = dev_ifsioc(net, ifr, cmd);
557 rtnl_unlock(); 523 rtnl_unlock();
558 if (!ret && copy_to_user(arg, &ifr,
559 sizeof(struct ifreq)))
560 ret = -EFAULT;
561 return ret; 524 return ret;
562 } 525 }
563 return -ENOTTY; 526 return -ENOTTY;
diff --git a/net/socket.c b/net/socket.c
index 1ad02d9edbef..45d51555ce47 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -973,10 +973,17 @@ static long sock_do_ioctl(struct net *net, struct socket *sock,
973 rtnl_unlock(); 973 rtnl_unlock();
974 if (!err && copy_to_user(argp, &ifc, sizeof(struct ifconf))) 974 if (!err && copy_to_user(argp, &ifc, sizeof(struct ifconf)))
975 err = -EFAULT; 975 err = -EFAULT;
976 return err; 976 } else {
977 struct ifreq ifr;
978 bool need_copyout;
979 if (copy_from_user(&ifr, argp, sizeof(struct ifreq)))
980 return -EFAULT;
981 err = dev_ioctl(net, cmd, &ifr, &need_copyout);
982 if (!err && need_copyout)
983 if (copy_to_user(argp, &ifr, sizeof(struct ifreq)))
984 return -EFAULT;
977 } 985 }
978 986 return err;
979 return dev_ioctl(net, cmd, argp);
980} 987}
981 988
982/* 989/*
@@ -1000,8 +1007,15 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
1000 sock = file->private_data; 1007 sock = file->private_data;
1001 sk = sock->sk; 1008 sk = sock->sk;
1002 net = sock_net(sk); 1009 net = sock_net(sk);
1003 if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { 1010 if (unlikely(cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15))) {
1004 err = dev_ioctl(net, cmd, argp); 1011 struct ifreq ifr;
1012 bool need_copyout;
1013 if (copy_from_user(&ifr, argp, sizeof(struct ifreq)))
1014 return -EFAULT;
1015 err = dev_ioctl(net, cmd, &ifr, &need_copyout);
1016 if (!err && need_copyout)
1017 if (copy_to_user(argp, &ifr, sizeof(struct ifreq)))
1018 return -EFAULT;
1005 } else 1019 } else
1006#ifdef CONFIG_WEXT_CORE 1020#ifdef CONFIG_WEXT_CORE
1007 if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { 1021 if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
@@ -2695,9 +2709,9 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
2695{ 2709{
2696 struct compat_ethtool_rxnfc __user *compat_rxnfc; 2710 struct compat_ethtool_rxnfc __user *compat_rxnfc;
2697 bool convert_in = false, convert_out = false; 2711 bool convert_in = false, convert_out = false;
2698 size_t buf_size = ALIGN(sizeof(struct ifreq), 8); 2712 size_t buf_size = 0;
2699 struct ethtool_rxnfc __user *rxnfc; 2713 struct ethtool_rxnfc __user *rxnfc = NULL;
2700 struct ifreq __user *ifr; 2714 struct ifreq ifr;
2701 u32 rule_cnt = 0, actual_rule_cnt; 2715 u32 rule_cnt = 0, actual_rule_cnt;
2702 u32 ethcmd; 2716 u32 ethcmd;
2703 u32 data; 2717 u32 data;
@@ -2734,18 +2748,14 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
2734 case ETHTOOL_SRXCLSRLDEL: 2748 case ETHTOOL_SRXCLSRLDEL:
2735 buf_size += sizeof(struct ethtool_rxnfc); 2749 buf_size += sizeof(struct ethtool_rxnfc);
2736 convert_in = true; 2750 convert_in = true;
2751 rxnfc = compat_alloc_user_space(buf_size);
2737 break; 2752 break;
2738 } 2753 }
2739 2754
2740 ifr = compat_alloc_user_space(buf_size); 2755 if (copy_from_user(&ifr.ifr_name, &ifr32->ifr_name, IFNAMSIZ))
2741 rxnfc = (void __user *)ifr + ALIGN(sizeof(struct ifreq), 8);
2742
2743 if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ))
2744 return -EFAULT; 2756 return -EFAULT;
2745 2757
2746 if (put_user(convert_in ? rxnfc : compat_ptr(data), 2758 ifr.ifr_data = convert_in ? rxnfc : (void __user *)compat_rxnfc;
2747 &ifr->ifr_ifru.ifru_data))
2748 return -EFAULT;
2749 2759
2750 if (convert_in) { 2760 if (convert_in) {
2751 /* We expect there to be holes between fs.m_ext and 2761 /* We expect there to be holes between fs.m_ext and
@@ -2773,7 +2783,7 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
2773 return -EFAULT; 2783 return -EFAULT;
2774 } 2784 }
2775 2785
2776 ret = dev_ioctl(net, SIOCETHTOOL, ifr); 2786 ret = dev_ioctl(net, SIOCETHTOOL, &ifr, NULL);
2777 if (ret) 2787 if (ret)
2778 return ret; 2788 return ret;
2779 2789
@@ -2814,50 +2824,43 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
2814 2824
2815static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) 2825static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32)
2816{ 2826{
2817 void __user *uptr;
2818 compat_uptr_t uptr32; 2827 compat_uptr_t uptr32;
2819 struct ifreq __user *uifr; 2828 struct ifreq ifr;
2829 void __user *saved;
2830 int err;
2820 2831
2821 uifr = compat_alloc_user_space(sizeof(*uifr)); 2832 if (copy_from_user(&ifr, uifr32, sizeof(struct compat_ifreq)))
2822 if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
2823 return -EFAULT; 2833 return -EFAULT;
2824 2834
2825 if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu)) 2835 if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu))
2826 return -EFAULT; 2836 return -EFAULT;
2827 2837
2828 uptr = compat_ptr(uptr32); 2838 saved = ifr.ifr_settings.ifs_ifsu.raw_hdlc;
2829 2839 ifr.ifr_settings.ifs_ifsu.raw_hdlc = compat_ptr(uptr32);
2830 if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc))
2831 return -EFAULT;
2832 2840
2833 return dev_ioctl(net, SIOCWANDEV, uifr); 2841 err = dev_ioctl(net, SIOCWANDEV, &ifr, NULL);
2842 if (!err) {
2843 ifr.ifr_settings.ifs_ifsu.raw_hdlc = saved;
2844 if (copy_to_user(uifr32, &ifr, sizeof(struct compat_ifreq)))
2845 err = -EFAULT;
2846 }
2847 return err;
2834} 2848}
2835 2849
2836/* Handle ioctls that use ifreq::ifr_data and just need struct ifreq converted */ 2850/* Handle ioctls that use ifreq::ifr_data and just need struct ifreq converted */
2837static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, 2851static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd,
2838 struct compat_ifreq __user *u_ifreq32) 2852 struct compat_ifreq __user *u_ifreq32)
2839{ 2853{
2840 struct ifreq __user *u_ifreq64; 2854 struct ifreq ifreq;
2841 char tmp_buf[IFNAMSIZ];
2842 void __user *data64;
2843 u32 data32; 2855 u32 data32;
2844 2856
2845 if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), 2857 if (copy_from_user(ifreq.ifr_name, u_ifreq32->ifr_name, IFNAMSIZ))
2846 IFNAMSIZ))
2847 return -EFAULT; 2858 return -EFAULT;
2848 if (get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) 2859 if (get_user(data32, &u_ifreq32->ifr_data))
2849 return -EFAULT; 2860 return -EFAULT;
2850 data64 = compat_ptr(data32); 2861 ifreq.ifr_data = compat_ptr(data32);
2851 2862
2852 u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); 2863 return dev_ioctl(net, cmd, &ifreq, NULL);
2853
2854 if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0],
2855 IFNAMSIZ))
2856 return -EFAULT;
2857 if (put_user(data64, &u_ifreq64->ifr_ifru.ifru_data))
2858 return -EFAULT;
2859
2860 return dev_ioctl(net, cmd, u_ifreq64);
2861} 2864}
2862 2865
2863static int compat_sioc_ifmap(struct net *net, unsigned int cmd, 2866static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
@@ -2865,7 +2868,6 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
2865{ 2868{
2866 struct ifreq ifr; 2869 struct ifreq ifr;
2867 struct compat_ifmap __user *uifmap32; 2870 struct compat_ifmap __user *uifmap32;
2868 mm_segment_t old_fs;
2869 int err; 2871 int err;
2870 2872
2871 uifmap32 = &uifr32->ifr_ifru.ifru_map; 2873 uifmap32 = &uifr32->ifr_ifru.ifru_map;
@@ -2879,10 +2881,7 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
2879 if (err) 2881 if (err)
2880 return -EFAULT; 2882 return -EFAULT;
2881 2883
2882 old_fs = get_fs(); 2884 err = dev_ioctl(net, cmd, &ifr, NULL);
2883 set_fs(KERNEL_DS);
2884 err = dev_ioctl(net, cmd, (void __user __force *)&ifr);
2885 set_fs(old_fs);
2886 2885
2887 if (cmd == SIOCGIFMAP && !err) { 2886 if (cmd == SIOCGIFMAP && !err) {
2888 err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); 2887 err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));