summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
authoryar <yar@FreeBSD.org>2001-11-19 21:52:03 +0000
committeryar <yar@FreeBSD.org>2001-11-19 21:52:03 +0000
commite2a8ecd17c985b878ee3cf6bc555b9513b2fd0da (patch)
treef798093db9fae35b826f7b78e1400ccc20826815 /libexec
parent440100677428ecb8a09339410b28422af62b398f (diff)
downloadFreeBSD-src-e2a8ecd17c985b878ee3cf6bc555b9513b2fd0da.zip
FreeBSD-src-e2a8ecd17c985b878ee3cf6bc555b9513b2fd0da.tar.gz
Eliminate another instance of the old and well-known
DoS bug that the select(2)/accept(2) pair is called on a socket that is in the blocking I/O mode. The bug is triggered if a selected connection dies before the accept(2) leading to the accept(2) blocking virtually forever. MFC after: 1 week
Diffstat (limited to 'libexec')
-rw-r--r--libexec/ftpd/ftpd.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index abc98c8..c78b2c1 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -1663,6 +1663,7 @@ dataconn(name, size, mode)
*sizebuf = '\0';
if (pdata >= 0) {
union sockunion from;
+ int flags;
int s, fromlen = ctrl_addr.su_len;
struct timeval timeout;
fd_set set;
@@ -1673,15 +1674,27 @@ dataconn(name, size, mode)
timeout.tv_usec = 0;
timeout.tv_sec = 120;
- if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 ||
- (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) {
- reply(425, "Can't open data connection.");
- (void) close(pdata);
- pdata = -1;
- return (NULL);
- }
+ /*
+ * Granted a socket is in the blocking I/O mode,
+ * accept() will block after a successful select()
+ * if the selected connection dies in between.
+ * Therefore set the non-blocking I/O flag here.
+ */
+ if ((flags = fcntl(pdata, F_GETFL, 0)) == -1 ||
+ fcntl(pdata, F_SETFL, flags | O_NONBLOCK) == -1)
+ goto pdata_err;
+ if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) <= 0 ||
+ (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0)
+ goto pdata_err;
(void) close(pdata);
pdata = s;
+ /*
+ * Unset the blocking I/O flag on the child socket
+ * again so stdio can work on it.
+ */
+ if ((flags = fcntl(pdata, F_GETFL, 0)) == -1 ||
+ fcntl(pdata, F_SETFL, flags & ~O_NONBLOCK) == -1)
+ goto pdata_err;
#ifdef IP_TOS
if (from.su_family == AF_INET)
{
@@ -1693,6 +1706,11 @@ dataconn(name, size, mode)
reply(150, "Opening %s mode data connection for '%s'%s.",
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
return (fdopen(pdata, mode));
+pdata_err:
+ reply(425, "Can't open data connection.");
+ (void) close(pdata);
+ pdata = -1;
+ return (NULL);
}
if (data >= 0) {
reply(125, "Using existing data connection for '%s'%s.",
OpenPOWER on IntegriCloud