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
This commit is contained in:
parent
3e9fbbe1df
commit
4cd48bace6
@ -1663,6 +1663,7 @@ dataconn(name, size, mode)
|
|||||||
*sizebuf = '\0';
|
*sizebuf = '\0';
|
||||||
if (pdata >= 0) {
|
if (pdata >= 0) {
|
||||||
union sockunion from;
|
union sockunion from;
|
||||||
|
int flags;
|
||||||
int s, fromlen = ctrl_addr.su_len;
|
int s, fromlen = ctrl_addr.su_len;
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
fd_set set;
|
fd_set set;
|
||||||
@ -1673,15 +1674,27 @@ dataconn(name, size, mode)
|
|||||||
timeout.tv_usec = 0;
|
timeout.tv_usec = 0;
|
||||||
timeout.tv_sec = 120;
|
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) {
|
* Granted a socket is in the blocking I/O mode,
|
||||||
reply(425, "Can't open data connection.");
|
* accept() will block after a successful select()
|
||||||
(void) close(pdata);
|
* if the selected connection dies in between.
|
||||||
pdata = -1;
|
* Therefore set the non-blocking I/O flag here.
|
||||||
return (NULL);
|
*/
|
||||||
}
|
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);
|
(void) close(pdata);
|
||||||
pdata = s;
|
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
|
#ifdef IP_TOS
|
||||||
if (from.su_family == AF_INET)
|
if (from.su_family == AF_INET)
|
||||||
{
|
{
|
||||||
@ -1693,6 +1706,11 @@ dataconn(name, size, mode)
|
|||||||
reply(150, "Opening %s mode data connection for '%s'%s.",
|
reply(150, "Opening %s mode data connection for '%s'%s.",
|
||||||
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
|
type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
|
||||||
return (fdopen(pdata, mode));
|
return (fdopen(pdata, mode));
|
||||||
|
pdata_err:
|
||||||
|
reply(425, "Can't open data connection.");
|
||||||
|
(void) close(pdata);
|
||||||
|
pdata = -1;
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
if (data >= 0) {
|
if (data >= 0) {
|
||||||
reply(125, "Using existing data connection for '%s'%s.",
|
reply(125, "Using existing data connection for '%s'%s.",
|
||||||
|
Loading…
Reference in New Issue
Block a user