diff options
author | Johannes Berg <johannes.berg@intel.com> | 2019-01-25 16:43:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-01-30 13:19:31 -0500 |
commit | 37ac39bdddc528c998a9f36db36937de923fdf2a (patch) | |
tree | bc49d021e90ae38e4ec4944a06fb415b4ae5d18f /net/socket.c | |
parent | 63ff03ab786ab1bc6cca01d48eacd22c95b9b3eb (diff) |
Revert "kill dev_ifsioc()"
This reverts commit bf4405737f9f ("kill dev_ifsioc()").
This wasn't really unused as implied by the original commit,
it still handles the copy to/from user differently, and the
commit thus caused issues such as
https://bugzilla.kernel.org/show_bug.cgi?id=199469
and
https://bugzilla.kernel.org/show_bug.cgi?id=202273
However, deviating from a strict revert, rename dev_ifsioc()
to compat_ifreq_ioctl() to be clearer as to its purpose and
add a comment.
Cc: stable@vger.kernel.org
Fixes: bf4405737f9f ("kill dev_ifsioc()")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/net/socket.c b/net/socket.c index 63b53af7379b..fbf80f9fb057 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -2990,6 +2990,53 @@ static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, | |||
2990 | return dev_ioctl(net, cmd, &ifreq, NULL); | 2990 | return dev_ioctl(net, cmd, &ifreq, NULL); |
2991 | } | 2991 | } |
2992 | 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 | if (copy_in_user(uifr32, uifr, sizeof(*uifr32))) | ||
3033 | err = -EFAULT; | ||
3034 | break; | ||
3035 | } | ||
3036 | } | ||
3037 | return err; | ||
3038 | } | ||
3039 | |||
2993 | static int compat_sioc_ifmap(struct net *net, unsigned int cmd, | 3040 | static int compat_sioc_ifmap(struct net *net, unsigned int cmd, |
2994 | struct compat_ifreq __user *uifr32) | 3041 | struct compat_ifreq __user *uifr32) |
2995 | { | 3042 | { |
@@ -3209,6 +3256,8 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | |||
3209 | case SIOCGMIIPHY: | 3256 | case SIOCGMIIPHY: |
3210 | case SIOCGMIIREG: | 3257 | case SIOCGMIIREG: |
3211 | case SIOCSMIIREG: | 3258 | case SIOCSMIIREG: |
3259 | return compat_ifreq_ioctl(net, sock, cmd, argp); | ||
3260 | |||
3212 | case SIOCSARP: | 3261 | case SIOCSARP: |
3213 | case SIOCGARP: | 3262 | case SIOCGARP: |
3214 | case SIOCDARP: | 3263 | case SIOCDARP: |