aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/asm-alpha/socket.h5
-rw-r--r--include/asm-parisc/socket.h5
-rw-r--r--include/asm-x86/unistd_64.h2
-rw-r--r--include/linux/net.h3
-rw-r--r--include/linux/syscalls.h2
-rw-r--r--kernel/sys_ni.c1
-rw-r--r--net/compat.c52
-rw-r--r--net/socket.c81
8 files changed, 139 insertions, 12 deletions
diff --git a/include/asm-alpha/socket.h b/include/asm-alpha/socket.h
index 08c979319929..a1057c2d95e7 100644
--- a/include/asm-alpha/socket.h
+++ b/include/asm-alpha/socket.h
@@ -62,4 +62,9 @@
62 62
63#define SO_MARK 36 63#define SO_MARK 36
64 64
65/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
66 * have to define SOCK_NONBLOCK to a different value here.
67 */
68#define SOCK_NONBLOCK 0x40000000
69
65#endif /* _ASM_SOCKET_H */ 70#endif /* _ASM_SOCKET_H */
diff --git a/include/asm-parisc/socket.h b/include/asm-parisc/socket.h
index 69a7a0d30b02..fba402c95ac2 100644
--- a/include/asm-parisc/socket.h
+++ b/include/asm-parisc/socket.h
@@ -54,4 +54,9 @@
54 54
55#define SO_MARK 0x401f 55#define SO_MARK 0x401f
56 56
57/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
58 * have to define SOCK_NONBLOCK to a different value here.
59 */
60#define SOCK_NONBLOCK 0x40000000
61
57#endif /* _ASM_SOCKET_H */ 62#endif /* _ASM_SOCKET_H */
diff --git a/include/asm-x86/unistd_64.h b/include/asm-x86/unistd_64.h
index 9c1a4a3470d9..e323994a370f 100644
--- a/include/asm-x86/unistd_64.h
+++ b/include/asm-x86/unistd_64.h
@@ -639,6 +639,8 @@ __SYSCALL(__NR_fallocate, sys_fallocate)
639__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime) 639__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
640#define __NR_timerfd_gettime 287 640#define __NR_timerfd_gettime 287
641__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime) 641__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
642#define __NR_paccept 288
643__SYSCALL(__NR_paccept, sys_paccept)
642 644
643 645
644#ifndef __NO_STUBS 646#ifndef __NO_STUBS
diff --git a/include/linux/net.h b/include/linux/net.h
index 8b5383c45b45..3a9b06d4d0fe 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -47,6 +47,7 @@ struct net;
47#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */ 47#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */
48#define SYS_SENDMSG 16 /* sys_sendmsg(2) */ 48#define SYS_SENDMSG 16 /* sys_sendmsg(2) */
49#define SYS_RECVMSG 17 /* sys_recvmsg(2) */ 49#define SYS_RECVMSG 17 /* sys_recvmsg(2) */
50#define SYS_PACCEPT 18 /* sys_paccept(2) */
50 51
51typedef enum { 52typedef enum {
52 SS_FREE = 0, /* not allocated */ 53 SS_FREE = 0, /* not allocated */
@@ -219,6 +220,8 @@ extern int sock_map_fd(struct socket *sock, int flags);
219extern struct socket *sockfd_lookup(int fd, int *err); 220extern struct socket *sockfd_lookup(int fd, int *err);
220#define sockfd_put(sock) fput(sock->file) 221#define sockfd_put(sock) fput(sock->file)
221extern int net_ratelimit(void); 222extern int net_ratelimit(void);
223extern long do_accept(int fd, struct sockaddr __user *upeer_sockaddr,
224 int __user *upeer_addrlen, int flags);
222 225
223#define net_random() random32() 226#define net_random() random32()
224#define net_srandom(seed) srandom32((__force u32)seed) 227#define net_srandom(seed) srandom32((__force u32)seed)
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 4394dadff813..2a2a40af6b2c 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -409,6 +409,8 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname,
409asmlinkage long sys_bind(int, struct sockaddr __user *, int); 409asmlinkage long sys_bind(int, struct sockaddr __user *, int);
410asmlinkage long sys_connect(int, struct sockaddr __user *, int); 410asmlinkage long sys_connect(int, struct sockaddr __user *, int);
411asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *); 411asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *);
412asmlinkage long sys_paccept(int, struct sockaddr __user *, int __user *,
413 const sigset_t *, size_t, int);
412asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *); 414asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *);
413asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *); 415asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *);
414asmlinkage long sys_send(int, void __user *, size_t, unsigned); 416asmlinkage long sys_send(int, void __user *, size_t, unsigned);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 0fea0ee12da9..2f0b8a2e600f 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -31,6 +31,7 @@ cond_syscall(sys_socketpair);
31cond_syscall(sys_bind); 31cond_syscall(sys_bind);
32cond_syscall(sys_listen); 32cond_syscall(sys_listen);
33cond_syscall(sys_accept); 33cond_syscall(sys_accept);
34cond_syscall(sys_paccept);
34cond_syscall(sys_connect); 35cond_syscall(sys_connect);
35cond_syscall(sys_getsockname); 36cond_syscall(sys_getsockname);
36cond_syscall(sys_getpeername); 37cond_syscall(sys_getpeername);
diff --git a/net/compat.c b/net/compat.c
index 6e1b03b51933..67fb6a3834a3 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -722,9 +722,10 @@ EXPORT_SYMBOL(compat_mc_getsockopt);
722 722
723/* Argument list sizes for compat_sys_socketcall */ 723/* Argument list sizes for compat_sys_socketcall */
724#define AL(x) ((x) * sizeof(u32)) 724#define AL(x) ((x) * sizeof(u32))
725static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), 725static unsigned char nas[19]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
726 AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), 726 AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
727 AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; 727 AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
728 AL(6)};
728#undef AL 729#undef AL
729 730
730asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags) 731asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
@@ -737,13 +738,52 @@ asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, uns
737 return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); 738 return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
738} 739}
739 740
741asmlinkage long compat_sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
742 int __user *upeer_addrlen,
743 const compat_sigset_t __user *sigmask,
744 compat_size_t sigsetsize, int flags)
745{
746 compat_sigset_t ss32;
747 sigset_t ksigmask, sigsaved;
748 int ret;
749
750 if (sigmask) {
751 if (sigsetsize != sizeof(compat_sigset_t))
752 return -EINVAL;
753 if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
754 return -EFAULT;
755 sigset_from_compat(&ksigmask, &ss32);
756
757 sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
758 sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
759 }
760
761 ret = do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
762
763 if (ret == -ERESTARTNOHAND) {
764 /*
765 * Don't restore the signal mask yet. Let do_signal() deliver
766 * the signal on the way back to userspace, before the signal
767 * mask is restored.
768 */
769 if (sigmask) {
770 memcpy(&current->saved_sigmask, &sigsaved,
771 sizeof(sigsaved));
772 set_restore_sigmask();
773 }
774 } else if (sigmask)
775 sigprocmask(SIG_SETMASK, &sigsaved, NULL);
776
777 return ret;
778}
779
740asmlinkage long compat_sys_socketcall(int call, u32 __user *args) 780asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
741{ 781{
742 int ret; 782 int ret;
743 u32 a[6]; 783 u32 a[6];
744 u32 a0, a1; 784 u32 a0, a1;
745 785
746 if (call < SYS_SOCKET || call > SYS_RECVMSG) 786 if (call < SYS_SOCKET || call > SYS_PACCEPT)
747 return -EINVAL; 787 return -EINVAL;
748 if (copy_from_user(a, args, nas[call])) 788 if (copy_from_user(a, args, nas[call]))
749 return -EFAULT; 789 return -EFAULT;
@@ -764,7 +804,7 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
764 ret = sys_listen(a0, a1); 804 ret = sys_listen(a0, a1);
765 break; 805 break;
766 case SYS_ACCEPT: 806 case SYS_ACCEPT:
767 ret = sys_accept(a0, compat_ptr(a1), compat_ptr(a[2])); 807 ret = do_accept(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
768 break; 808 break;
769 case SYS_GETSOCKNAME: 809 case SYS_GETSOCKNAME:
770 ret = sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2])); 810 ret = sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
@@ -804,6 +844,10 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
804 case SYS_RECVMSG: 844 case SYS_RECVMSG:
805 ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); 845 ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
806 break; 846 break;
847 case SYS_PACCEPT:
848 ret = compat_sys_paccept(a0, compat_ptr(a1), compat_ptr(a[2]),
849 compat_ptr(a[3]), a[4], a[5]);
850 break;
807 default: 851 default:
808 ret = -EINVAL; 852 ret = -EINVAL;
809 break; 853 break;
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
1416asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, 1423long 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
1507asmlinkage 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(&current->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
1545asmlinkage 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))
2014static const unsigned char nargs[18]={ 2071static 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;