diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 82 |
1 files changed, 63 insertions, 19 deletions
diff --git a/net/socket.c b/net/socket.c index e89884e2197b..d80d87a395ea 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -941,8 +941,7 @@ void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) | |||
941 | EXPORT_SYMBOL(dlci_ioctl_set); | 941 | EXPORT_SYMBOL(dlci_ioctl_set); |
942 | 942 | ||
943 | static long sock_do_ioctl(struct net *net, struct socket *sock, | 943 | static long sock_do_ioctl(struct net *net, struct socket *sock, |
944 | unsigned int cmd, unsigned long arg, | 944 | unsigned int cmd, unsigned long arg) |
945 | unsigned int ifreq_size) | ||
946 | { | 945 | { |
947 | int err; | 946 | int err; |
948 | void __user *argp = (void __user *)arg; | 947 | void __user *argp = (void __user *)arg; |
@@ -968,11 +967,11 @@ static long sock_do_ioctl(struct net *net, struct socket *sock, | |||
968 | } else { | 967 | } else { |
969 | struct ifreq ifr; | 968 | struct ifreq ifr; |
970 | bool need_copyout; | 969 | bool need_copyout; |
971 | if (copy_from_user(&ifr, argp, ifreq_size)) | 970 | if (copy_from_user(&ifr, argp, sizeof(struct ifreq))) |
972 | return -EFAULT; | 971 | return -EFAULT; |
973 | err = dev_ioctl(net, cmd, &ifr, &need_copyout); | 972 | err = dev_ioctl(net, cmd, &ifr, &need_copyout); |
974 | if (!err && need_copyout) | 973 | if (!err && need_copyout) |
975 | if (copy_to_user(argp, &ifr, ifreq_size)) | 974 | if (copy_to_user(argp, &ifr, sizeof(struct ifreq))) |
976 | return -EFAULT; | 975 | return -EFAULT; |
977 | } | 976 | } |
978 | return err; | 977 | return err; |
@@ -1071,8 +1070,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
1071 | err = open_related_ns(&net->ns, get_net_ns); | 1070 | err = open_related_ns(&net->ns, get_net_ns); |
1072 | break; | 1071 | break; |
1073 | default: | 1072 | default: |
1074 | err = sock_do_ioctl(net, sock, cmd, arg, | 1073 | err = sock_do_ioctl(net, sock, cmd, arg); |
1075 | sizeof(struct ifreq)); | ||
1076 | break; | 1074 | break; |
1077 | } | 1075 | } |
1078 | return err; | 1076 | return err; |
@@ -2780,8 +2778,7 @@ static int do_siocgstamp(struct net *net, struct socket *sock, | |||
2780 | int err; | 2778 | int err; |
2781 | 2779 | ||
2782 | set_fs(KERNEL_DS); | 2780 | set_fs(KERNEL_DS); |
2783 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv, | 2781 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); |
2784 | sizeof(struct compat_ifreq)); | ||
2785 | set_fs(old_fs); | 2782 | set_fs(old_fs); |
2786 | if (!err) | 2783 | if (!err) |
2787 | err = compat_put_timeval(&ktv, up); | 2784 | err = compat_put_timeval(&ktv, up); |
@@ -2797,8 +2794,7 @@ static int do_siocgstampns(struct net *net, struct socket *sock, | |||
2797 | int err; | 2794 | int err; |
2798 | 2795 | ||
2799 | set_fs(KERNEL_DS); | 2796 | set_fs(KERNEL_DS); |
2800 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts, | 2797 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); |
2801 | sizeof(struct compat_ifreq)); | ||
2802 | set_fs(old_fs); | 2798 | set_fs(old_fs); |
2803 | if (!err) | 2799 | if (!err) |
2804 | err = compat_put_timespec(&kts, up); | 2800 | err = compat_put_timespec(&kts, up); |
@@ -2994,6 +2990,54 @@ static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, | |||
2994 | return dev_ioctl(net, cmd, &ifreq, NULL); | 2990 | return dev_ioctl(net, cmd, &ifreq, NULL); |
2995 | } | 2991 | } |
2996 | 2992 | ||
2993 | static int compat_ifreq_ioctl(struct net *net, struct socket *sock, | ||
2994 | unsigned int cmd, | ||
2995 | struct compat_ifreq __user *uifr32) | ||
2996 | { | ||
2997 | struct ifreq __user *uifr; | ||
2998 | int err; | ||
2999 | |||
3000 | /* Handle the fact that while struct ifreq has the same *layout* on | ||
3001 | * 32/64 for everything but ifreq::ifru_ifmap and ifreq::ifru_data, | ||
3002 | * which are handled elsewhere, it still has different *size* due to | ||
3003 | * ifreq::ifru_ifmap (which is 16 bytes on 32 bit, 24 bytes on 64-bit, | ||
3004 | * resulting in struct ifreq being 32 and 40 bytes respectively). | ||
3005 | * As a result, if the struct happens to be at the end of a page and | ||
3006 | * the next page isn't readable/writable, we get a fault. To prevent | ||
3007 | * that, copy back and forth to the full size. | ||
3008 | */ | ||
3009 | |||
3010 | uifr = compat_alloc_user_space(sizeof(*uifr)); | ||
3011 | if (copy_in_user(uifr, uifr32, sizeof(*uifr32))) | ||
3012 | return -EFAULT; | ||
3013 | |||
3014 | err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr); | ||
3015 | |||
3016 | if (!err) { | ||
3017 | switch (cmd) { | ||
3018 | case SIOCGIFFLAGS: | ||
3019 | case SIOCGIFMETRIC: | ||
3020 | case SIOCGIFMTU: | ||
3021 | case SIOCGIFMEM: | ||
3022 | case SIOCGIFHWADDR: | ||
3023 | case SIOCGIFINDEX: | ||
3024 | case SIOCGIFADDR: | ||
3025 | case SIOCGIFBRDADDR: | ||
3026 | case SIOCGIFDSTADDR: | ||
3027 | case SIOCGIFNETMASK: | ||
3028 | case SIOCGIFPFLAGS: | ||
3029 | case SIOCGIFTXQLEN: | ||
3030 | case SIOCGMIIPHY: | ||
3031 | case SIOCGMIIREG: | ||
3032 | case SIOCGIFNAME: | ||
3033 | if (copy_in_user(uifr32, uifr, sizeof(*uifr32))) | ||
3034 | err = -EFAULT; | ||
3035 | break; | ||
3036 | } | ||
3037 | } | ||
3038 | return err; | ||
3039 | } | ||
3040 | |||
2997 | static int compat_sioc_ifmap(struct net *net, unsigned int cmd, | 3041 | static int compat_sioc_ifmap(struct net *net, unsigned int cmd, |
2998 | struct compat_ifreq __user *uifr32) | 3042 | struct compat_ifreq __user *uifr32) |
2999 | { | 3043 | { |
@@ -3109,8 +3153,7 @@ static int routing_ioctl(struct net *net, struct socket *sock, | |||
3109 | } | 3153 | } |
3110 | 3154 | ||
3111 | set_fs(KERNEL_DS); | 3155 | set_fs(KERNEL_DS); |
3112 | ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r, | 3156 | ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r); |
3113 | sizeof(struct compat_ifreq)); | ||
3114 | set_fs(old_fs); | 3157 | set_fs(old_fs); |
3115 | 3158 | ||
3116 | out: | 3159 | out: |
@@ -3210,21 +3253,22 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | |||
3210 | case SIOCSIFTXQLEN: | 3253 | case SIOCSIFTXQLEN: |
3211 | case SIOCBRADDIF: | 3254 | case SIOCBRADDIF: |
3212 | case SIOCBRDELIF: | 3255 | case SIOCBRDELIF: |
3256 | case SIOCGIFNAME: | ||
3213 | case SIOCSIFNAME: | 3257 | case SIOCSIFNAME: |
3214 | case SIOCGMIIPHY: | 3258 | case SIOCGMIIPHY: |
3215 | case SIOCGMIIREG: | 3259 | case SIOCGMIIREG: |
3216 | case SIOCSMIIREG: | 3260 | case SIOCSMIIREG: |
3217 | case SIOCSARP: | ||
3218 | case SIOCGARP: | ||
3219 | case SIOCDARP: | ||
3220 | case SIOCATMARK: | ||
3221 | case SIOCBONDENSLAVE: | 3261 | case SIOCBONDENSLAVE: |
3222 | case SIOCBONDRELEASE: | 3262 | case SIOCBONDRELEASE: |
3223 | case SIOCBONDSETHWADDR: | 3263 | case SIOCBONDSETHWADDR: |
3224 | case SIOCBONDCHANGEACTIVE: | 3264 | case SIOCBONDCHANGEACTIVE: |
3225 | case SIOCGIFNAME: | 3265 | return compat_ifreq_ioctl(net, sock, cmd, argp); |
3226 | return sock_do_ioctl(net, sock, cmd, arg, | 3266 | |
3227 | sizeof(struct compat_ifreq)); | 3267 | case SIOCSARP: |
3268 | case SIOCGARP: | ||
3269 | case SIOCDARP: | ||
3270 | case SIOCATMARK: | ||
3271 | return sock_do_ioctl(net, sock, cmd, arg); | ||
3228 | } | 3272 | } |
3229 | 3273 | ||
3230 | return -ENOIOCTLCMD; | 3274 | return -ENOIOCTLCMD; |