diff options
Diffstat (limited to 'net/socket.c')
-rw-r--r-- | net/socket.c | 81 |
1 files changed, 73 insertions, 8 deletions
diff --git a/net/socket.c b/net/socket.c index 64601f900352..a0ce8ad72252 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -63,6 +63,7 @@ | |||
63 | #include <linux/file.h> | 63 | #include <linux/file.h> |
64 | #include <linux/net.h> | 64 | #include <linux/net.h> |
65 | #include <linux/interrupt.h> | 65 | #include <linux/interrupt.h> |
66 | #include <linux/thread_info.h> | ||
66 | #include <linux/rcupdate.h> | 67 | #include <linux/rcupdate.h> |
67 | #include <linux/netdevice.h> | 68 | #include <linux/netdevice.h> |
68 | #include <linux/proc_fs.h> | 69 | #include <linux/proc_fs.h> |
@@ -1225,6 +1226,9 @@ asmlinkage long sys_socket(int family, int type, int protocol) | |||
1225 | return -EINVAL; | 1226 | return -EINVAL; |
1226 | type &= SOCK_TYPE_MASK; | 1227 | type &= SOCK_TYPE_MASK; |
1227 | 1228 | ||
1229 | if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) | ||
1230 | flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; | ||
1231 | |||
1228 | retval = sock_create(family, type, protocol, &sock); | 1232 | retval = sock_create(family, type, protocol, &sock); |
1229 | if (retval < 0) | 1233 | if (retval < 0) |
1230 | goto out; | 1234 | goto out; |
@@ -1259,6 +1263,9 @@ asmlinkage long sys_socketpair(int family, int type, int protocol, | |||
1259 | return -EINVAL; | 1263 | return -EINVAL; |
1260 | type &= SOCK_TYPE_MASK; | 1264 | type &= SOCK_TYPE_MASK; |
1261 | 1265 | ||
1266 | if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) | ||
1267 | flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; | ||
1268 | |||
1262 | /* | 1269 | /* |
1263 | * Obtain the first socket and check if the underlying protocol | 1270 | * Obtain the first socket and check if the underlying protocol |
1264 | * supports the socketpair call. | 1271 | * supports the socketpair call. |
@@ -1413,14 +1420,20 @@ asmlinkage long sys_listen(int fd, int backlog) | |||
1413 | * clean when we restucture accept also. | 1420 | * clean when we restucture accept also. |
1414 | */ | 1421 | */ |
1415 | 1422 | ||
1416 | asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, | 1423 | long do_accept(int fd, struct sockaddr __user *upeer_sockaddr, |
1417 | int __user *upeer_addrlen) | 1424 | int __user *upeer_addrlen, int flags) |
1418 | { | 1425 | { |
1419 | struct socket *sock, *newsock; | 1426 | struct socket *sock, *newsock; |
1420 | struct file *newfile; | 1427 | struct file *newfile; |
1421 | int err, len, newfd, fput_needed; | 1428 | int err, len, newfd, fput_needed; |
1422 | struct sockaddr_storage address; | 1429 | struct sockaddr_storage address; |
1423 | 1430 | ||
1431 | if (flags & ~SOCK_CLOEXEC) | ||
1432 | return -EINVAL; | ||
1433 | |||
1434 | if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) | ||
1435 | flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; | ||
1436 | |||
1424 | sock = sockfd_lookup_light(fd, &err, &fput_needed); | 1437 | sock = sockfd_lookup_light(fd, &err, &fput_needed); |
1425 | if (!sock) | 1438 | if (!sock) |
1426 | goto out; | 1439 | goto out; |
@@ -1438,7 +1451,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, | |||
1438 | */ | 1451 | */ |
1439 | __module_get(newsock->ops->owner); | 1452 | __module_get(newsock->ops->owner); |
1440 | 1453 | ||
1441 | newfd = sock_alloc_fd(&newfile, 0); | 1454 | newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC); |
1442 | if (unlikely(newfd < 0)) { | 1455 | if (unlikely(newfd < 0)) { |
1443 | err = newfd; | 1456 | err = newfd; |
1444 | sock_release(newsock); | 1457 | sock_release(newsock); |
@@ -1491,6 +1504,50 @@ out_fd: | |||
1491 | goto out_put; | 1504 | goto out_put; |
1492 | } | 1505 | } |
1493 | 1506 | ||
1507 | asmlinkage long sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr, | ||
1508 | int __user *upeer_addrlen, | ||
1509 | const sigset_t __user *sigmask, | ||
1510 | size_t sigsetsize, int flags) | ||
1511 | { | ||
1512 | sigset_t ksigmask, sigsaved; | ||
1513 | int ret; | ||
1514 | |||
1515 | if (sigmask) { | ||
1516 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
1517 | if (sigsetsize != sizeof(sigset_t)) | ||
1518 | return -EINVAL; | ||
1519 | if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) | ||
1520 | return -EFAULT; | ||
1521 | |||
1522 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
1523 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1524 | } | ||
1525 | |||
1526 | ret = do_accept(fd, upeer_sockaddr, upeer_addrlen, flags); | ||
1527 | |||
1528 | if (ret < 0 && signal_pending(current)) { | ||
1529 | /* | ||
1530 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
1531 | * the signal on the way back to userspace, before the signal | ||
1532 | * mask is restored. | ||
1533 | */ | ||
1534 | if (sigmask) { | ||
1535 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1536 | sizeof(sigsaved)); | ||
1537 | set_restore_sigmask(); | ||
1538 | } | ||
1539 | } else if (sigmask) | ||
1540 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1541 | |||
1542 | return ret; | ||
1543 | } | ||
1544 | |||
1545 | asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, | ||
1546 | int __user *upeer_addrlen) | ||
1547 | { | ||
1548 | return do_accept(fd, upeer_sockaddr, upeer_addrlen, 0); | ||
1549 | } | ||
1550 | |||
1494 | /* | 1551 | /* |
1495 | * Attempt to connect to a socket with the server address. The address | 1552 | * Attempt to connect to a socket with the server address. The address |
1496 | * is in user space so we verify it is OK and move it to kernel space. | 1553 | * is in user space so we verify it is OK and move it to kernel space. |
@@ -2011,10 +2068,11 @@ out: | |||
2011 | 2068 | ||
2012 | /* Argument list sizes for sys_socketcall */ | 2069 | /* Argument list sizes for sys_socketcall */ |
2013 | #define AL(x) ((x) * sizeof(unsigned long)) | 2070 | #define AL(x) ((x) * sizeof(unsigned long)) |
2014 | static const unsigned char nargs[18]={ | 2071 | static const unsigned char nargs[19]={ |
2015 | AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), | 2072 | AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), |
2016 | AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), | 2073 | AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), |
2017 | AL(6),AL(2),AL(5),AL(5),AL(3),AL(3) | 2074 | AL(6),AL(2),AL(5),AL(5),AL(3),AL(3), |
2075 | AL(6) | ||
2018 | }; | 2076 | }; |
2019 | 2077 | ||
2020 | #undef AL | 2078 | #undef AL |
@@ -2033,7 +2091,7 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args) | |||
2033 | unsigned long a0, a1; | 2091 | unsigned long a0, a1; |
2034 | int err; | 2092 | int err; |
2035 | 2093 | ||
2036 | if (call < 1 || call > SYS_RECVMSG) | 2094 | if (call < 1 || call > SYS_PACCEPT) |
2037 | return -EINVAL; | 2095 | return -EINVAL; |
2038 | 2096 | ||
2039 | /* copy_from_user should be SMP safe. */ | 2097 | /* copy_from_user should be SMP safe. */ |
@@ -2062,8 +2120,8 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args) | |||
2062 | break; | 2120 | break; |
2063 | case SYS_ACCEPT: | 2121 | case SYS_ACCEPT: |
2064 | err = | 2122 | err = |
2065 | sys_accept(a0, (struct sockaddr __user *)a1, | 2123 | do_accept(a0, (struct sockaddr __user *)a1, |
2066 | (int __user *)a[2]); | 2124 | (int __user *)a[2], 0); |
2067 | break; | 2125 | break; |
2068 | case SYS_GETSOCKNAME: | 2126 | case SYS_GETSOCKNAME: |
2069 | err = | 2127 | err = |
@@ -2110,6 +2168,13 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args) | |||
2110 | case SYS_RECVMSG: | 2168 | case SYS_RECVMSG: |
2111 | err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); | 2169 | err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); |
2112 | break; | 2170 | break; |
2171 | case SYS_PACCEPT: | ||
2172 | err = | ||
2173 | sys_paccept(a0, (struct sockaddr __user *)a1, | ||
2174 | (int __user *)a[2], | ||
2175 | (const sigset_t __user *) a[3], | ||
2176 | a[4], a[5]); | ||
2177 | break; | ||
2113 | default: | 2178 | default: |
2114 | err = -EINVAL; | 2179 | err = -EINVAL; |
2115 | break; | 2180 | break; |