diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 92 |
1 files changed, 56 insertions, 36 deletions
diff --git a/net/socket.c b/net/socket.c index 66c4a8cf6db9..1ba57d888981 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -90,6 +90,7 @@ | |||
90 | #include <asm/unistd.h> | 90 | #include <asm/unistd.h> |
91 | 91 | ||
92 | #include <net/compat.h> | 92 | #include <net/compat.h> |
93 | #include <net/wext.h> | ||
93 | 94 | ||
94 | #include <net/sock.h> | 95 | #include <net/sock.h> |
95 | #include <linux/netfilter.h> | 96 | #include <linux/netfilter.h> |
@@ -179,9 +180,9 @@ static DEFINE_PER_CPU(int, sockets_in_use) = 0; | |||
179 | * invalid addresses -EFAULT is returned. On a success 0 is returned. | 180 | * invalid addresses -EFAULT is returned. On a success 0 is returned. |
180 | */ | 181 | */ |
181 | 182 | ||
182 | int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr) | 183 | int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr) |
183 | { | 184 | { |
184 | if (ulen < 0 || ulen > MAX_SOCK_ADDR) | 185 | if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) |
185 | return -EINVAL; | 186 | return -EINVAL; |
186 | if (ulen == 0) | 187 | if (ulen == 0) |
187 | return 0; | 188 | return 0; |
@@ -207,7 +208,7 @@ int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr) | |||
207 | * specified. Zero is returned for a success. | 208 | * specified. Zero is returned for a success. |
208 | */ | 209 | */ |
209 | 210 | ||
210 | int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, | 211 | int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uaddr, |
211 | int __user *ulen) | 212 | int __user *ulen) |
212 | { | 213 | { |
213 | int err; | 214 | int err; |
@@ -218,7 +219,7 @@ int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, | |||
218 | return err; | 219 | return err; |
219 | if (len > klen) | 220 | if (len > klen) |
220 | len = klen; | 221 | len = klen; |
221 | if (len < 0 || len > MAX_SOCK_ADDR) | 222 | if (len < 0 || len > sizeof(struct sockaddr_storage)) |
222 | return -EINVAL; | 223 | return -EINVAL; |
223 | if (len) { | 224 | if (len) { |
224 | if (audit_sockaddr(klen, kaddr)) | 225 | if (audit_sockaddr(klen, kaddr)) |
@@ -1341,20 +1342,20 @@ out_fd: | |||
1341 | asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) | 1342 | asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) |
1342 | { | 1343 | { |
1343 | struct socket *sock; | 1344 | struct socket *sock; |
1344 | char address[MAX_SOCK_ADDR]; | 1345 | struct sockaddr_storage address; |
1345 | int err, fput_needed; | 1346 | int err, fput_needed; |
1346 | 1347 | ||
1347 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1348 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1348 | if (sock) { | 1349 | if (sock) { |
1349 | err = move_addr_to_kernel(umyaddr, addrlen, address); | 1350 | err = move_addr_to_kernel(umyaddr, addrlen, (struct sockaddr *)&address); |
1350 | if (err >= 0) { | 1351 | if (err >= 0) { |
1351 | err = security_socket_bind(sock, | 1352 | err = security_socket_bind(sock, |
1352 | (struct sockaddr *)address, | 1353 | (struct sockaddr *)&address, |
1353 | addrlen); | 1354 | addrlen); |
1354 | if (!err) | 1355 | if (!err) |
1355 | err = sock->ops->bind(sock, | 1356 | err = sock->ops->bind(sock, |
1356 | (struct sockaddr *) | 1357 | (struct sockaddr *) |
1357 | address, addrlen); | 1358 | &address, addrlen); |
1358 | } | 1359 | } |
1359 | fput_light(sock->file, fput_needed); | 1360 | fput_light(sock->file, fput_needed); |
1360 | } | 1361 | } |
@@ -1406,7 +1407,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, | |||
1406 | struct socket *sock, *newsock; | 1407 | struct socket *sock, *newsock; |
1407 | struct file *newfile; | 1408 | struct file *newfile; |
1408 | int err, len, newfd, fput_needed; | 1409 | int err, len, newfd, fput_needed; |
1409 | char address[MAX_SOCK_ADDR]; | 1410 | struct sockaddr_storage address; |
1410 | 1411 | ||
1411 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1412 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1412 | if (!sock) | 1413 | if (!sock) |
@@ -1445,13 +1446,13 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, | |||
1445 | goto out_fd; | 1446 | goto out_fd; |
1446 | 1447 | ||
1447 | if (upeer_sockaddr) { | 1448 | if (upeer_sockaddr) { |
1448 | if (newsock->ops->getname(newsock, (struct sockaddr *)address, | 1449 | if (newsock->ops->getname(newsock, (struct sockaddr *)&address, |
1449 | &len, 2) < 0) { | 1450 | &len, 2) < 0) { |
1450 | err = -ECONNABORTED; | 1451 | err = -ECONNABORTED; |
1451 | goto out_fd; | 1452 | goto out_fd; |
1452 | } | 1453 | } |
1453 | err = move_addr_to_user(address, len, upeer_sockaddr, | 1454 | err = move_addr_to_user((struct sockaddr *)&address, |
1454 | upeer_addrlen); | 1455 | len, upeer_sockaddr, upeer_addrlen); |
1455 | if (err < 0) | 1456 | if (err < 0) |
1456 | goto out_fd; | 1457 | goto out_fd; |
1457 | } | 1458 | } |
@@ -1494,22 +1495,22 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, | |||
1494 | int addrlen) | 1495 | int addrlen) |
1495 | { | 1496 | { |
1496 | struct socket *sock; | 1497 | struct socket *sock; |
1497 | char address[MAX_SOCK_ADDR]; | 1498 | struct sockaddr_storage address; |
1498 | int err, fput_needed; | 1499 | int err, fput_needed; |
1499 | 1500 | ||
1500 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1501 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1501 | if (!sock) | 1502 | if (!sock) |
1502 | goto out; | 1503 | goto out; |
1503 | err = move_addr_to_kernel(uservaddr, addrlen, address); | 1504 | err = move_addr_to_kernel(uservaddr, addrlen, (struct sockaddr *)&address); |
1504 | if (err < 0) | 1505 | if (err < 0) |
1505 | goto out_put; | 1506 | goto out_put; |
1506 | 1507 | ||
1507 | err = | 1508 | err = |
1508 | security_socket_connect(sock, (struct sockaddr *)address, addrlen); | 1509 | security_socket_connect(sock, (struct sockaddr *)&address, addrlen); |
1509 | if (err) | 1510 | if (err) |
1510 | goto out_put; | 1511 | goto out_put; |
1511 | 1512 | ||
1512 | err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, | 1513 | err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, |
1513 | sock->file->f_flags); | 1514 | sock->file->f_flags); |
1514 | out_put: | 1515 | out_put: |
1515 | fput_light(sock->file, fput_needed); | 1516 | fput_light(sock->file, fput_needed); |
@@ -1526,7 +1527,7 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, | |||
1526 | int __user *usockaddr_len) | 1527 | int __user *usockaddr_len) |
1527 | { | 1528 | { |
1528 | struct socket *sock; | 1529 | struct socket *sock; |
1529 | char address[MAX_SOCK_ADDR]; | 1530 | struct sockaddr_storage address; |
1530 | int len, err, fput_needed; | 1531 | int len, err, fput_needed; |
1531 | 1532 | ||
1532 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1533 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
@@ -1537,10 +1538,10 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, | |||
1537 | if (err) | 1538 | if (err) |
1538 | goto out_put; | 1539 | goto out_put; |
1539 | 1540 | ||
1540 | err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 0); | 1541 | err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); |
1541 | if (err) | 1542 | if (err) |
1542 | goto out_put; | 1543 | goto out_put; |
1543 | err = move_addr_to_user(address, len, usockaddr, usockaddr_len); | 1544 | err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr, usockaddr_len); |
1544 | 1545 | ||
1545 | out_put: | 1546 | out_put: |
1546 | fput_light(sock->file, fput_needed); | 1547 | fput_light(sock->file, fput_needed); |
@@ -1557,7 +1558,7 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, | |||
1557 | int __user *usockaddr_len) | 1558 | int __user *usockaddr_len) |
1558 | { | 1559 | { |
1559 | struct socket *sock; | 1560 | struct socket *sock; |
1560 | char address[MAX_SOCK_ADDR]; | 1561 | struct sockaddr_storage address; |
1561 | int len, err, fput_needed; | 1562 | int len, err, fput_needed; |
1562 | 1563 | ||
1563 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1564 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
@@ -1569,10 +1570,10 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, | |||
1569 | } | 1570 | } |
1570 | 1571 | ||
1571 | err = | 1572 | err = |
1572 | sock->ops->getname(sock, (struct sockaddr *)address, &len, | 1573 | sock->ops->getname(sock, (struct sockaddr *)&address, &len, |
1573 | 1); | 1574 | 1); |
1574 | if (!err) | 1575 | if (!err) |
1575 | err = move_addr_to_user(address, len, usockaddr, | 1576 | err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr, |
1576 | usockaddr_len); | 1577 | usockaddr_len); |
1577 | fput_light(sock->file, fput_needed); | 1578 | fput_light(sock->file, fput_needed); |
1578 | } | 1579 | } |
@@ -1590,7 +1591,7 @@ asmlinkage long sys_sendto(int fd, void __user *buff, size_t len, | |||
1590 | int addr_len) | 1591 | int addr_len) |
1591 | { | 1592 | { |
1592 | struct socket *sock; | 1593 | struct socket *sock; |
1593 | char address[MAX_SOCK_ADDR]; | 1594 | struct sockaddr_storage address; |
1594 | int err; | 1595 | int err; |
1595 | struct msghdr msg; | 1596 | struct msghdr msg; |
1596 | struct iovec iov; | 1597 | struct iovec iov; |
@@ -1609,10 +1610,10 @@ asmlinkage long sys_sendto(int fd, void __user *buff, size_t len, | |||
1609 | msg.msg_controllen = 0; | 1610 | msg.msg_controllen = 0; |
1610 | msg.msg_namelen = 0; | 1611 | msg.msg_namelen = 0; |
1611 | if (addr) { | 1612 | if (addr) { |
1612 | err = move_addr_to_kernel(addr, addr_len, address); | 1613 | err = move_addr_to_kernel(addr, addr_len, (struct sockaddr *)&address); |
1613 | if (err < 0) | 1614 | if (err < 0) |
1614 | goto out_put; | 1615 | goto out_put; |
1615 | msg.msg_name = address; | 1616 | msg.msg_name = (struct sockaddr *)&address; |
1616 | msg.msg_namelen = addr_len; | 1617 | msg.msg_namelen = addr_len; |
1617 | } | 1618 | } |
1618 | if (sock->file->f_flags & O_NONBLOCK) | 1619 | if (sock->file->f_flags & O_NONBLOCK) |
@@ -1648,7 +1649,7 @@ asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size, | |||
1648 | struct socket *sock; | 1649 | struct socket *sock; |
1649 | struct iovec iov; | 1650 | struct iovec iov; |
1650 | struct msghdr msg; | 1651 | struct msghdr msg; |
1651 | char address[MAX_SOCK_ADDR]; | 1652 | struct sockaddr_storage address; |
1652 | int err, err2; | 1653 | int err, err2; |
1653 | int fput_needed; | 1654 | int fput_needed; |
1654 | 1655 | ||
@@ -1662,14 +1663,15 @@ asmlinkage long sys_recvfrom(int fd, void __user *ubuf, size_t size, | |||
1662 | msg.msg_iov = &iov; | 1663 | msg.msg_iov = &iov; |
1663 | iov.iov_len = size; | 1664 | iov.iov_len = size; |
1664 | iov.iov_base = ubuf; | 1665 | iov.iov_base = ubuf; |
1665 | msg.msg_name = address; | 1666 | msg.msg_name = (struct sockaddr *)&address; |
1666 | msg.msg_namelen = MAX_SOCK_ADDR; | 1667 | msg.msg_namelen = sizeof(address); |
1667 | if (sock->file->f_flags & O_NONBLOCK) | 1668 | if (sock->file->f_flags & O_NONBLOCK) |
1668 | flags |= MSG_DONTWAIT; | 1669 | flags |= MSG_DONTWAIT; |
1669 | err = sock_recvmsg(sock, &msg, size, flags); | 1670 | err = sock_recvmsg(sock, &msg, size, flags); |
1670 | 1671 | ||
1671 | if (err >= 0 && addr != NULL) { | 1672 | if (err >= 0 && addr != NULL) { |
1672 | err2 = move_addr_to_user(address, msg.msg_namelen, addr, addr_len); | 1673 | err2 = move_addr_to_user((struct sockaddr *)&address, |
1674 | msg.msg_namelen, addr, addr_len); | ||
1673 | if (err2 < 0) | 1675 | if (err2 < 0) |
1674 | err = err2; | 1676 | err = err2; |
1675 | } | 1677 | } |
@@ -1789,7 +1791,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | |||
1789 | struct compat_msghdr __user *msg_compat = | 1791 | struct compat_msghdr __user *msg_compat = |
1790 | (struct compat_msghdr __user *)msg; | 1792 | (struct compat_msghdr __user *)msg; |
1791 | struct socket *sock; | 1793 | struct socket *sock; |
1792 | char address[MAX_SOCK_ADDR]; | 1794 | struct sockaddr_storage address; |
1793 | struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; | 1795 | struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; |
1794 | unsigned char ctl[sizeof(struct cmsghdr) + 20] | 1796 | unsigned char ctl[sizeof(struct cmsghdr) + 20] |
1795 | __attribute__ ((aligned(sizeof(__kernel_size_t)))); | 1797 | __attribute__ ((aligned(sizeof(__kernel_size_t)))); |
@@ -1827,9 +1829,13 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) | |||
1827 | 1829 | ||
1828 | /* This will also move the address data into kernel space */ | 1830 | /* This will also move the address data into kernel space */ |
1829 | if (MSG_CMSG_COMPAT & flags) { | 1831 | if (MSG_CMSG_COMPAT & flags) { |
1830 | err = verify_compat_iovec(&msg_sys, iov, address, VERIFY_READ); | 1832 | err = verify_compat_iovec(&msg_sys, iov, |
1833 | (struct sockaddr *)&address, | ||
1834 | VERIFY_READ); | ||
1831 | } else | 1835 | } else |
1832 | err = verify_iovec(&msg_sys, iov, address, VERIFY_READ); | 1836 | err = verify_iovec(&msg_sys, iov, |
1837 | (struct sockaddr *)&address, | ||
1838 | VERIFY_READ); | ||
1833 | if (err < 0) | 1839 | if (err < 0) |
1834 | goto out_freeiov; | 1840 | goto out_freeiov; |
1835 | total_len = err; | 1841 | total_len = err; |
@@ -1900,7 +1906,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, | |||
1900 | int fput_needed; | 1906 | int fput_needed; |
1901 | 1907 | ||
1902 | /* kernel mode address */ | 1908 | /* kernel mode address */ |
1903 | char addr[MAX_SOCK_ADDR]; | 1909 | struct sockaddr_storage addr; |
1904 | 1910 | ||
1905 | /* user mode address pointers */ | 1911 | /* user mode address pointers */ |
1906 | struct sockaddr __user *uaddr; | 1912 | struct sockaddr __user *uaddr; |
@@ -1938,9 +1944,13 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, | |||
1938 | uaddr = (__force void __user *)msg_sys.msg_name; | 1944 | uaddr = (__force void __user *)msg_sys.msg_name; |
1939 | uaddr_len = COMPAT_NAMELEN(msg); | 1945 | uaddr_len = COMPAT_NAMELEN(msg); |
1940 | if (MSG_CMSG_COMPAT & flags) { | 1946 | if (MSG_CMSG_COMPAT & flags) { |
1941 | err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE); | 1947 | err = verify_compat_iovec(&msg_sys, iov, |
1948 | (struct sockaddr *)&addr, | ||
1949 | VERIFY_WRITE); | ||
1942 | } else | 1950 | } else |
1943 | err = verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE); | 1951 | err = verify_iovec(&msg_sys, iov, |
1952 | (struct sockaddr *)&addr, | ||
1953 | VERIFY_WRITE); | ||
1944 | if (err < 0) | 1954 | if (err < 0) |
1945 | goto out_freeiov; | 1955 | goto out_freeiov; |
1946 | total_len = err; | 1956 | total_len = err; |
@@ -1956,7 +1966,8 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, | |||
1956 | len = err; | 1966 | len = err; |
1957 | 1967 | ||
1958 | if (uaddr != NULL) { | 1968 | if (uaddr != NULL) { |
1959 | err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, | 1969 | err = move_addr_to_user((struct sockaddr *)&addr, |
1970 | msg_sys.msg_namelen, uaddr, | ||
1960 | uaddr_len); | 1971 | uaddr_len); |
1961 | if (err < 0) | 1972 | if (err < 0) |
1962 | goto out_freeiov; | 1973 | goto out_freeiov; |
@@ -2210,10 +2221,19 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd, | |||
2210 | { | 2221 | { |
2211 | struct socket *sock = file->private_data; | 2222 | struct socket *sock = file->private_data; |
2212 | int ret = -ENOIOCTLCMD; | 2223 | int ret = -ENOIOCTLCMD; |
2224 | struct sock *sk; | ||
2225 | struct net *net; | ||
2226 | |||
2227 | sk = sock->sk; | ||
2228 | net = sock_net(sk); | ||
2213 | 2229 | ||
2214 | if (sock->ops->compat_ioctl) | 2230 | if (sock->ops->compat_ioctl) |
2215 | ret = sock->ops->compat_ioctl(sock, cmd, arg); | 2231 | ret = sock->ops->compat_ioctl(sock, cmd, arg); |
2216 | 2232 | ||
2233 | if (ret == -ENOIOCTLCMD && | ||
2234 | (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) | ||
2235 | ret = compat_wext_handle_ioctl(net, cmd, arg); | ||
2236 | |||
2217 | return ret; | 2237 | return ret; |
2218 | } | 2238 | } |
2219 | #endif | 2239 | #endif |