|
@@ -63,6 +63,7 @@
|
|
|
#include <linux/file.h>
|
|
|
#include <linux/net.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
+#include <linux/thread_info.h>
|
|
|
#include <linux/rcupdate.h>
|
|
|
#include <linux/netdevice.h>
|
|
|
#include <linux/proc_fs.h>
|
|
@@ -1225,6 +1226,9 @@ asmlinkage long sys_socket(int family, int type, int protocol)
|
|
|
return -EINVAL;
|
|
|
type &= SOCK_TYPE_MASK;
|
|
|
|
|
|
+ if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
|
|
|
+ flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
|
|
|
+
|
|
|
retval = sock_create(family, type, protocol, &sock);
|
|
|
if (retval < 0)
|
|
|
goto out;
|
|
@@ -1259,6 +1263,9 @@ asmlinkage long sys_socketpair(int family, int type, int protocol,
|
|
|
return -EINVAL;
|
|
|
type &= SOCK_TYPE_MASK;
|
|
|
|
|
|
+ if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
|
|
|
+ flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
|
|
|
+
|
|
|
/*
|
|
|
* Obtain the first socket and check if the underlying protocol
|
|
|
* supports the socketpair call.
|
|
@@ -1413,14 +1420,20 @@ asmlinkage long sys_listen(int fd, int backlog)
|
|
|
* clean when we restucture accept also.
|
|
|
*/
|
|
|
|
|
|
-asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
|
|
|
- int __user *upeer_addrlen)
|
|
|
+long do_accept(int fd, struct sockaddr __user *upeer_sockaddr,
|
|
|
+ int __user *upeer_addrlen, int flags)
|
|
|
{
|
|
|
struct socket *sock, *newsock;
|
|
|
struct file *newfile;
|
|
|
int err, len, newfd, fput_needed;
|
|
|
struct sockaddr_storage address;
|
|
|
|
|
|
+ if (flags & ~SOCK_CLOEXEC)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
|
|
|
+ flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
|
|
|
+
|
|
|
sock = sockfd_lookup_light(fd, &err, &fput_needed);
|
|
|
if (!sock)
|
|
|
goto out;
|
|
@@ -1438,7 +1451,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
|
|
|
*/
|
|
|
__module_get(newsock->ops->owner);
|
|
|
|
|
|
- newfd = sock_alloc_fd(&newfile, 0);
|
|
|
+ newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC);
|
|
|
if (unlikely(newfd < 0)) {
|
|
|
err = newfd;
|
|
|
sock_release(newsock);
|
|
@@ -1491,6 +1504,50 @@ out_fd:
|
|
|
goto out_put;
|
|
|
}
|
|
|
|
|
|
+asmlinkage long sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
|
|
|
+ int __user *upeer_addrlen,
|
|
|
+ const sigset_t __user *sigmask,
|
|
|
+ size_t sigsetsize, int flags)
|
|
|
+{
|
|
|
+ sigset_t ksigmask, sigsaved;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (sigmask) {
|
|
|
+ /* XXX: Don't preclude handling different sized sigset_t's. */
|
|
|
+ if (sigsetsize != sizeof(sigset_t))
|
|
|
+ return -EINVAL;
|
|
|
+ if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
|
|
|
+ sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
|
|
|
+
|
|
|
+ if (ret < 0 && signal_pending(current)) {
|
|
|
+ /*
|
|
|
+ * Don't restore the signal mask yet. Let do_signal() deliver
|
|
|
+ * the signal on the way back to userspace, before the signal
|
|
|
+ * mask is restored.
|
|
|
+ */
|
|
|
+ if (sigmask) {
|
|
|
+ memcpy(¤t->saved_sigmask, &sigsaved,
|
|
|
+ sizeof(sigsaved));
|
|
|
+ set_restore_sigmask();
|
|
|
+ }
|
|
|
+ } else if (sigmask)
|
|
|
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
|
|
|
+ int __user *upeer_addrlen)
|
|
|
+{
|
|
|
+ return do_accept(fd, upeer_sockaddr, upeer_addrlen, 0);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Attempt to connect to a socket with the server address. The address
|
|
|
* is in user space so we verify it is OK and move it to kernel space.
|
|
@@ -2011,10 +2068,11 @@ out:
|
|
|
|
|
|
/* Argument list sizes for sys_socketcall */
|
|
|
#define AL(x) ((x) * sizeof(unsigned long))
|
|
|
-static const unsigned char nargs[18]={
|
|
|
+static const unsigned char nargs[19]={
|
|
|
AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
|
|
|
AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
|
|
|
- AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)
|
|
|
+ AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
|
|
|
+ AL(6)
|
|
|
};
|
|
|
|
|
|
#undef AL
|
|
@@ -2033,7 +2091,7 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
|
|
|
unsigned long a0, a1;
|
|
|
int err;
|
|
|
|
|
|
- if (call < 1 || call > SYS_RECVMSG)
|
|
|
+ if (call < 1 || call > SYS_PACCEPT)
|
|
|
return -EINVAL;
|
|
|
|
|
|
/* copy_from_user should be SMP safe. */
|
|
@@ -2062,8 +2120,8 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
|
|
|
break;
|
|
|
case SYS_ACCEPT:
|
|
|
err =
|
|
|
- sys_accept(a0, (struct sockaddr __user *)a1,
|
|
|
- (int __user *)a[2]);
|
|
|
+ do_accept(a0, (struct sockaddr __user *)a1,
|
|
|
+ (int __user *)a[2], 0);
|
|
|
break;
|
|
|
case SYS_GETSOCKNAME:
|
|
|
err =
|
|
@@ -2110,6 +2168,13 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
|
|
|
case SYS_RECVMSG:
|
|
|
err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
|
|
|
break;
|
|
|
+ case SYS_PACCEPT:
|
|
|
+ err =
|
|
|
+ sys_paccept(a0, (struct sockaddr __user *)a1,
|
|
|
+ (int __user *)a[2],
|
|
|
+ (const sigset_t __user *) a[3],
|
|
|
+ a[4], a[5]);
|
|
|
+ break;
|
|
|
default:
|
|
|
err = -EINVAL;
|
|
|
break;
|