aboutsummaryrefslogtreecommitdiffstats
path: root/net/socket.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2008-07-24 00:29:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:27 -0400
commitaaca0bdca573f3f51ea03139f9c7289541e7bca3 (patch)
treed25b0baa73b5301d91a5c848a896bad0fb719acc /net/socket.c
parenta677a039be7243357d93502bff2b40850c942e2d (diff)
flag parameters: paccept
This patch is by far the most complex in the series. It adds a new syscall paccept. This syscall differs from accept in that it adds (at the userlevel) two additional parameters: - a signal mask - a flags value The flags parameter can be used to set flag like SOCK_CLOEXEC. This is imlpemented here as well. Some people argued that this is a property which should be inherited from the file desriptor for the server but this is against POSIX. Additionally, we really want the signal mask parameter as well (similar to pselect, ppoll, etc). So an interface change in inevitable. The flag value is the same as for socket and socketpair. I think diverging here will only create confusion. Similar to the filesystem interfaces where the use of the O_* constants differs, it is acceptable here. The signal mask is handled as for pselect etc. The mask is temporarily installed for the thread and removed before the call returns. I modeled the code after pselect. If there is a problem it's likely also in pselect. For architectures which use socketcall I maintained this interface instead of adding a system call. The symmetry shouldn't be broken. The following test must be adjusted for architectures other than x86 and x86-64 and in case the syscall numbers changed. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #include <errno.h> #include <fcntl.h> #include <pthread.h> #include <signal.h> #include <stdio.h> #include <unistd.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/syscall.h> #ifndef __NR_paccept # ifdef __x86_64__ # define __NR_paccept 288 # elif defined __i386__ # define SYS_PACCEPT 18 # define USE_SOCKETCALL 1 # else # error "need __NR_paccept" # endif #endif #ifdef USE_SOCKETCALL # define paccept(fd, addr, addrlen, mask, flags) \ ({ long args[6] = { \ (long) fd, (long) addr, (long) addrlen, (long) mask, 8, (long) flags }; \ syscall (__NR_socketcall, SYS_PACCEPT, args); }) #else # define paccept(fd, addr, addrlen, mask, flags) \ syscall (__NR_paccept, fd, addr, addrlen, mask, 8, flags) #endif #define PORT 57392 #define SOCK_CLOEXEC O_CLOEXEC static pthread_barrier_t b; static void * tf (void *arg) { pthread_barrier_wait (&b); int s = socket (AF_INET, SOCK_STREAM, 0); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); sin.sin_port = htons (PORT); connect (s, (const struct sockaddr *) &sin, sizeof (sin)); close (s); pthread_barrier_wait (&b); s = socket (AF_INET, SOCK_STREAM, 0); sin.sin_port = htons (PORT); connect (s, (const struct sockaddr *) &sin, sizeof (sin)); close (s); pthread_barrier_wait (&b); pthread_barrier_wait (&b); sleep (2); pthread_kill ((pthread_t) arg, SIGUSR1); return NULL; } static void handler (int s) { } int main (void) { pthread_barrier_init (&b, NULL, 2); struct sockaddr_in sin; pthread_t th; if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) { puts ("pthread_create failed"); return 1; } int s = socket (AF_INET, SOCK_STREAM, 0); int reuse = 1; setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof (reuse)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); sin.sin_port = htons (PORT); bind (s, (struct sockaddr *) &sin, sizeof (sin)); listen (s, SOMAXCONN); pthread_barrier_wait (&b); int s2 = paccept (s, NULL, 0, NULL, 0); if (s2 < 0) { puts ("paccept(0) failed"); return 1; } int coe = fcntl (s2, F_GETFD); if (coe & FD_CLOEXEC) { puts ("paccept(0) set close-on-exec-flag"); return 1; } close (s2); pthread_barrier_wait (&b); s2 = paccept (s, NULL, 0, NULL, SOCK_CLOEXEC); if (s2 < 0) { puts ("paccept(SOCK_CLOEXEC) failed"); return 1; } coe = fcntl (s2, F_GETFD); if ((coe & FD_CLOEXEC) == 0) { puts ("paccept(SOCK_CLOEXEC) does not set close-on-exec flag"); return 1; } close (s2); pthread_barrier_wait (&b); struct sigaction sa; sa.sa_handler = handler; sa.sa_flags = 0; sigemptyset (&sa.sa_mask); sigaction (SIGUSR1, &sa, NULL); sigset_t ss; pthread_sigmask (SIG_SETMASK, NULL, &ss); sigaddset (&ss, SIGUSR1); pthread_sigmask (SIG_SETMASK, &ss, NULL); sigdelset (&ss, SIGUSR1); alarm (4); pthread_barrier_wait (&b); errno = 0 ; s2 = paccept (s, NULL, 0, &ss, 0); if (s2 != -1 || errno != EINTR) { puts ("paccept did not fail with EINTR"); return 1; } close (s); puts ("OK"); return 0; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [akpm@linux-foundation.org: make it compile] [akpm@linux-foundation.org: add sys_ni stub] Signed-off-by: Ulrich Drepper <drepper@redhat.com> Acked-by: Davide Libenzi <davidel@xmailserver.org> Cc: Michael Kerrisk <mtk.manpages@googlemail.com> Cc: <linux-arch@vger.kernel.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Roland McGrath <roland@redhat.com> Cc: Kyle McMartin <kyle@mcmartin.ca> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'net/socket.c')
-rw-r--r--net/socket.c81
1 files changed, 73 insertions, 8 deletions
diff --git a/net/socket.c b/net/socket.c
index 64601f90035..a0ce8ad7225 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;