diff options
-rw-r--r-- | include/asm-alpha/socket.h | 5 | ||||
-rw-r--r-- | include/asm-parisc/socket.h | 5 | ||||
-rw-r--r-- | include/asm-x86/unistd_64.h | 2 | ||||
-rw-r--r-- | include/linux/net.h | 3 | ||||
-rw-r--r-- | include/linux/syscalls.h | 2 | ||||
-rw-r--r-- | kernel/sys_ni.c | 1 | ||||
-rw-r--r-- | net/compat.c | 52 | ||||
-rw-r--r-- | net/socket.c | 81 |
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 | ||
51 | typedef enum { | 52 | typedef 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); | |||
219 | extern struct socket *sockfd_lookup(int fd, int *err); | 220 | extern struct socket *sockfd_lookup(int fd, int *err); |
220 | #define sockfd_put(sock) fput(sock->file) | 221 | #define sockfd_put(sock) fput(sock->file) |
221 | extern int net_ratelimit(void); | 222 | extern int net_ratelimit(void); |
223 | extern 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, | |||
409 | asmlinkage long sys_bind(int, struct sockaddr __user *, int); | 409 | asmlinkage long sys_bind(int, struct sockaddr __user *, int); |
410 | asmlinkage long sys_connect(int, struct sockaddr __user *, int); | 410 | asmlinkage long sys_connect(int, struct sockaddr __user *, int); |
411 | asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *); | 411 | asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *); |
412 | asmlinkage long sys_paccept(int, struct sockaddr __user *, int __user *, | ||
413 | const sigset_t *, size_t, int); | ||
412 | asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *); | 414 | asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *); |
413 | asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *); | 415 | asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *); |
414 | asmlinkage long sys_send(int, void __user *, size_t, unsigned); | 416 | asmlinkage 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); | |||
31 | cond_syscall(sys_bind); | 31 | cond_syscall(sys_bind); |
32 | cond_syscall(sys_listen); | 32 | cond_syscall(sys_listen); |
33 | cond_syscall(sys_accept); | 33 | cond_syscall(sys_accept); |
34 | cond_syscall(sys_paccept); | ||
34 | cond_syscall(sys_connect); | 35 | cond_syscall(sys_connect); |
35 | cond_syscall(sys_getsockname); | 36 | cond_syscall(sys_getsockname); |
36 | cond_syscall(sys_getpeername); | 37 | cond_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)) |
725 | static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), | 725 | static 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 | ||
730 | asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags) | 731 | asmlinkage 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 | ||
741 | asmlinkage 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(¤t->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 | |||
740 | asmlinkage long compat_sys_socketcall(int call, u32 __user *args) | 780 | asmlinkage 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 | ||
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; |