mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-02 15:03:41 +00:00
For the TCP transport, put the listening socket in non-blocking
mode. This addresses a well-known race condition that can cause servers to hang in accept(). The relevant case is when somebody connects to the server and then immediately kills the connection by sending a TCP reset. On the server this causes select to report a ready condition on the socket, after which the accept call blocks because there is no longer any pending connection to accept. In -current there is already a work-around for this in the kernel. It was merged into -stable some time ago, but then David Greenman reverted it because it seemed to be causing a socket leak in some cases. (See uipc_socket.c revision 1.51.2.3.) Hence this userland fix is needed in -stable, and I plan to merge it into that branch soon because it fixes a potential DoS attack. It may also be needed in -current if the suspected socket leak turns out to be real. In any case, after thinking it over I believe the fix belongs in userland. An application shouldn't assume that a ready return from select guarantees that the subsequent I/O operation cannot block. A lot can happen between the select and the accept. A similar fix should most likely be applied to the Unix domain socket transport too. Submitted by: peter Reviewed by: jdp
This commit is contained in:
parent
1815eed869
commit
e2e3d0a401
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=53323
@ -49,6 +49,7 @@ static char *rcsid = "$FreeBSD$";
|
||||
#include <string.h>
|
||||
#include <rpc/rpc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
@ -131,6 +132,7 @@ svctcp_create(sock, sendsize, recvsize)
|
||||
register struct tcp_rendezvous *r;
|
||||
struct sockaddr_in addr;
|
||||
int len = sizeof(struct sockaddr_in);
|
||||
int on;
|
||||
|
||||
if (sock == RPC_ANYSOCK) {
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
||||
@ -139,6 +141,13 @@ svctcp_create(sock, sendsize, recvsize)
|
||||
}
|
||||
madesock = TRUE;
|
||||
}
|
||||
on = 1;
|
||||
if (ioctl(sock, FIONBIO, &on) < 0) {
|
||||
perror("svc_tcp.c - cannot turn on non-blocking mode");
|
||||
if (madesock)
|
||||
(void)close(sock);
|
||||
return ((SVCXPRT *)NULL);
|
||||
}
|
||||
memset(&addr, 0, sizeof (addr));
|
||||
addr.sin_len = sizeof(struct sockaddr_in);
|
||||
addr.sin_family = AF_INET;
|
||||
@ -233,6 +242,7 @@ rendezvous_request(xprt)
|
||||
struct tcp_rendezvous *r;
|
||||
struct sockaddr_in addr;
|
||||
int len;
|
||||
int off;
|
||||
|
||||
r = (struct tcp_rendezvous *)xprt->xp_p1;
|
||||
again:
|
||||
@ -250,6 +260,14 @@ rendezvous_request(xprt)
|
||||
close(sock);
|
||||
return (FALSE);
|
||||
}
|
||||
/*
|
||||
* The listening socket is in FIONBIO mode and we inherit it.
|
||||
*/
|
||||
off = 0;
|
||||
if (ioctl(sock, FIONBIO, &off) < 0) {
|
||||
close(sock);
|
||||
return (FALSE);
|
||||
}
|
||||
/*
|
||||
* make a new transporter (re-uses xprt)
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user