diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 123 |
1 files changed, 51 insertions, 72 deletions
diff --git a/net/socket.c b/net/socket.c index e83c416708af..a19ae1968d37 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -450,16 +450,17 @@ EXPORT_SYMBOL(sockfd_lookup); | |||
450 | 450 | ||
451 | static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) | 451 | static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) |
452 | { | 452 | { |
453 | struct file *file; | 453 | struct fd f = fdget(fd); |
454 | struct socket *sock; | 454 | struct socket *sock; |
455 | 455 | ||
456 | *err = -EBADF; | 456 | *err = -EBADF; |
457 | file = fget_light(fd, fput_needed); | 457 | if (f.file) { |
458 | if (file) { | 458 | sock = sock_from_file(f.file, err); |
459 | sock = sock_from_file(file, err); | 459 | if (likely(sock)) { |
460 | if (sock) | 460 | *fput_needed = f.flags; |
461 | return sock; | 461 | return sock; |
462 | fput_light(file, *fput_needed); | 462 | } |
463 | fdput(f); | ||
463 | } | 464 | } |
464 | return NULL; | 465 | return NULL; |
465 | } | 466 | } |
@@ -1445,48 +1446,61 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, | |||
1445 | err = fd1; | 1446 | err = fd1; |
1446 | goto out_release_both; | 1447 | goto out_release_both; |
1447 | } | 1448 | } |
1449 | |||
1448 | fd2 = get_unused_fd_flags(flags); | 1450 | fd2 = get_unused_fd_flags(flags); |
1449 | if (unlikely(fd2 < 0)) { | 1451 | if (unlikely(fd2 < 0)) { |
1450 | err = fd2; | 1452 | err = fd2; |
1451 | put_unused_fd(fd1); | 1453 | goto out_put_unused_1; |
1452 | goto out_release_both; | ||
1453 | } | 1454 | } |
1454 | 1455 | ||
1455 | newfile1 = sock_alloc_file(sock1, flags, NULL); | 1456 | newfile1 = sock_alloc_file(sock1, flags, NULL); |
1456 | if (unlikely(IS_ERR(newfile1))) { | 1457 | if (unlikely(IS_ERR(newfile1))) { |
1457 | err = PTR_ERR(newfile1); | 1458 | err = PTR_ERR(newfile1); |
1458 | put_unused_fd(fd1); | 1459 | goto out_put_unused_both; |
1459 | put_unused_fd(fd2); | ||
1460 | goto out_release_both; | ||
1461 | } | 1460 | } |
1462 | 1461 | ||
1463 | newfile2 = sock_alloc_file(sock2, flags, NULL); | 1462 | newfile2 = sock_alloc_file(sock2, flags, NULL); |
1464 | if (IS_ERR(newfile2)) { | 1463 | if (IS_ERR(newfile2)) { |
1465 | err = PTR_ERR(newfile2); | 1464 | err = PTR_ERR(newfile2); |
1466 | fput(newfile1); | 1465 | goto out_fput_1; |
1467 | put_unused_fd(fd1); | ||
1468 | put_unused_fd(fd2); | ||
1469 | sock_release(sock2); | ||
1470 | goto out; | ||
1471 | } | 1466 | } |
1472 | 1467 | ||
1468 | err = put_user(fd1, &usockvec[0]); | ||
1469 | if (err) | ||
1470 | goto out_fput_both; | ||
1471 | |||
1472 | err = put_user(fd2, &usockvec[1]); | ||
1473 | if (err) | ||
1474 | goto out_fput_both; | ||
1475 | |||
1473 | audit_fd_pair(fd1, fd2); | 1476 | audit_fd_pair(fd1, fd2); |
1477 | |||
1474 | fd_install(fd1, newfile1); | 1478 | fd_install(fd1, newfile1); |
1475 | fd_install(fd2, newfile2); | 1479 | fd_install(fd2, newfile2); |
1476 | /* fd1 and fd2 may be already another descriptors. | 1480 | /* fd1 and fd2 may be already another descriptors. |
1477 | * Not kernel problem. | 1481 | * Not kernel problem. |
1478 | */ | 1482 | */ |
1479 | 1483 | ||
1480 | err = put_user(fd1, &usockvec[0]); | 1484 | return 0; |
1481 | if (!err) | ||
1482 | err = put_user(fd2, &usockvec[1]); | ||
1483 | if (!err) | ||
1484 | return 0; | ||
1485 | 1485 | ||
1486 | sys_close(fd2); | 1486 | out_fput_both: |
1487 | sys_close(fd1); | 1487 | fput(newfile2); |
1488 | return err; | 1488 | fput(newfile1); |
1489 | put_unused_fd(fd2); | ||
1490 | put_unused_fd(fd1); | ||
1491 | goto out; | ||
1492 | |||
1493 | out_fput_1: | ||
1494 | fput(newfile1); | ||
1495 | put_unused_fd(fd2); | ||
1496 | put_unused_fd(fd1); | ||
1497 | sock_release(sock2); | ||
1498 | goto out; | ||
1489 | 1499 | ||
1500 | out_put_unused_both: | ||
1501 | put_unused_fd(fd2); | ||
1502 | out_put_unused_1: | ||
1503 | put_unused_fd(fd1); | ||
1490 | out_release_both: | 1504 | out_release_both: |
1491 | sock_release(sock2); | 1505 | sock_release(sock2); |
1492 | out_release_1: | 1506 | out_release_1: |
@@ -1972,6 +1986,10 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, | |||
1972 | { | 1986 | { |
1973 | if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) | 1987 | if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) |
1974 | return -EFAULT; | 1988 | return -EFAULT; |
1989 | |||
1990 | if (kmsg->msg_namelen < 0) | ||
1991 | return -EINVAL; | ||
1992 | |||
1975 | if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) | 1993 | if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) |
1976 | kmsg->msg_namelen = sizeof(struct sockaddr_storage); | 1994 | kmsg->msg_namelen = sizeof(struct sockaddr_storage); |
1977 | return 0; | 1995 | return 0; |
@@ -2968,11 +2986,8 @@ static int bond_ioctl(struct net *net, unsigned int cmd, | |||
2968 | struct compat_ifreq __user *ifr32) | 2986 | struct compat_ifreq __user *ifr32) |
2969 | { | 2987 | { |
2970 | struct ifreq kifr; | 2988 | struct ifreq kifr; |
2971 | struct ifreq __user *uifr; | ||
2972 | mm_segment_t old_fs; | 2989 | mm_segment_t old_fs; |
2973 | int err; | 2990 | int err; |
2974 | u32 data; | ||
2975 | void __user *datap; | ||
2976 | 2991 | ||
2977 | switch (cmd) { | 2992 | switch (cmd) { |
2978 | case SIOCBONDENSLAVE: | 2993 | case SIOCBONDENSLAVE: |
@@ -2989,26 +3004,13 @@ static int bond_ioctl(struct net *net, unsigned int cmd, | |||
2989 | set_fs(old_fs); | 3004 | set_fs(old_fs); |
2990 | 3005 | ||
2991 | return err; | 3006 | return err; |
2992 | case SIOCBONDSLAVEINFOQUERY: | ||
2993 | case SIOCBONDINFOQUERY: | ||
2994 | uifr = compat_alloc_user_space(sizeof(*uifr)); | ||
2995 | if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) | ||
2996 | return -EFAULT; | ||
2997 | |||
2998 | if (get_user(data, &ifr32->ifr_ifru.ifru_data)) | ||
2999 | return -EFAULT; | ||
3000 | |||
3001 | datap = compat_ptr(data); | ||
3002 | if (put_user(datap, &uifr->ifr_ifru.ifru_data)) | ||
3003 | return -EFAULT; | ||
3004 | |||
3005 | return dev_ioctl(net, cmd, uifr); | ||
3006 | default: | 3007 | default: |
3007 | return -ENOIOCTLCMD; | 3008 | return -ENOIOCTLCMD; |
3008 | } | 3009 | } |
3009 | } | 3010 | } |
3010 | 3011 | ||
3011 | static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, | 3012 | /* Handle ioctls that use ifreq::ifr_data and just need struct ifreq converted */ |
3013 | static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, | ||
3012 | struct compat_ifreq __user *u_ifreq32) | 3014 | struct compat_ifreq __user *u_ifreq32) |
3013 | { | 3015 | { |
3014 | struct ifreq __user *u_ifreq64; | 3016 | struct ifreq __user *u_ifreq64; |
@@ -3019,19 +3021,16 @@ static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, | |||
3019 | if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), | 3021 | if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), |
3020 | IFNAMSIZ)) | 3022 | IFNAMSIZ)) |
3021 | return -EFAULT; | 3023 | return -EFAULT; |
3022 | if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) | 3024 | if (get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) |
3023 | return -EFAULT; | 3025 | return -EFAULT; |
3024 | data64 = compat_ptr(data32); | 3026 | data64 = compat_ptr(data32); |
3025 | 3027 | ||
3026 | u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); | 3028 | u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); |
3027 | 3029 | ||
3028 | /* Don't check these user accesses, just let that get trapped | ||
3029 | * in the ioctl handler instead. | ||
3030 | */ | ||
3031 | if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], | 3030 | if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], |
3032 | IFNAMSIZ)) | 3031 | IFNAMSIZ)) |
3033 | return -EFAULT; | 3032 | return -EFAULT; |
3034 | if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) | 3033 | if (put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) |
3035 | return -EFAULT; | 3034 | return -EFAULT; |
3036 | 3035 | ||
3037 | return dev_ioctl(net, cmd, u_ifreq64); | 3036 | return dev_ioctl(net, cmd, u_ifreq64); |
@@ -3111,27 +3110,6 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd, | |||
3111 | return err; | 3110 | return err; |
3112 | } | 3111 | } |
3113 | 3112 | ||
3114 | static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32) | ||
3115 | { | ||
3116 | void __user *uptr; | ||
3117 | compat_uptr_t uptr32; | ||
3118 | struct ifreq __user *uifr; | ||
3119 | |||
3120 | uifr = compat_alloc_user_space(sizeof(*uifr)); | ||
3121 | if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) | ||
3122 | return -EFAULT; | ||
3123 | |||
3124 | if (get_user(uptr32, &uifr32->ifr_data)) | ||
3125 | return -EFAULT; | ||
3126 | |||
3127 | uptr = compat_ptr(uptr32); | ||
3128 | |||
3129 | if (put_user(uptr, &uifr->ifr_data)) | ||
3130 | return -EFAULT; | ||
3131 | |||
3132 | return dev_ioctl(net, SIOCSHWTSTAMP, uifr); | ||
3133 | } | ||
3134 | |||
3135 | struct rtentry32 { | 3113 | struct rtentry32 { |
3136 | u32 rt_pad1; | 3114 | u32 rt_pad1; |
3137 | struct sockaddr rt_dst; /* target address */ | 3115 | struct sockaddr rt_dst; /* target address */ |
@@ -3243,7 +3221,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | |||
3243 | struct net *net = sock_net(sk); | 3221 | struct net *net = sock_net(sk); |
3244 | 3222 | ||
3245 | if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) | 3223 | if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) |
3246 | return siocdevprivate_ioctl(net, cmd, argp); | 3224 | return compat_ifr_data_ioctl(net, cmd, argp); |
3247 | 3225 | ||
3248 | switch (cmd) { | 3226 | switch (cmd) { |
3249 | case SIOCSIFBR: | 3227 | case SIOCSIFBR: |
@@ -3263,8 +3241,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | |||
3263 | case SIOCBONDENSLAVE: | 3241 | case SIOCBONDENSLAVE: |
3264 | case SIOCBONDRELEASE: | 3242 | case SIOCBONDRELEASE: |
3265 | case SIOCBONDSETHWADDR: | 3243 | case SIOCBONDSETHWADDR: |
3266 | case SIOCBONDSLAVEINFOQUERY: | ||
3267 | case SIOCBONDINFOQUERY: | ||
3268 | case SIOCBONDCHANGEACTIVE: | 3244 | case SIOCBONDCHANGEACTIVE: |
3269 | return bond_ioctl(net, cmd, argp); | 3245 | return bond_ioctl(net, cmd, argp); |
3270 | case SIOCADDRT: | 3246 | case SIOCADDRT: |
@@ -3274,8 +3250,11 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, | |||
3274 | return do_siocgstamp(net, sock, cmd, argp); | 3250 | return do_siocgstamp(net, sock, cmd, argp); |
3275 | case SIOCGSTAMPNS: | 3251 | case SIOCGSTAMPNS: |
3276 | return do_siocgstampns(net, sock, cmd, argp); | 3252 | return do_siocgstampns(net, sock, cmd, argp); |
3253 | case SIOCBONDSLAVEINFOQUERY: | ||
3254 | case SIOCBONDINFOQUERY: | ||
3277 | case SIOCSHWTSTAMP: | 3255 | case SIOCSHWTSTAMP: |
3278 | return compat_siocshwtstamp(net, argp); | 3256 | case SIOCGHWTSTAMP: |
3257 | return compat_ifr_data_ioctl(net, cmd, argp); | ||
3279 | 3258 | ||
3280 | case FIOSETOWN: | 3259 | case FIOSETOWN: |
3281 | case SIOCSPGRP: | 3260 | case SIOCSPGRP: |