1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-06 04:31:29 +00:00

Check for sd > FD_SETSIZE before it is unrecoverable. Fixes #1857

This commit is contained in:
dmiller
2022-09-29 00:13:10 +00:00
parent de9f84d080
commit b5dd2956dd
3 changed files with 56 additions and 6 deletions

View File

@@ -327,8 +327,7 @@ bool GroupScanStats::sendOK(struct timeval *when) const {
if (when)
TIMEVAL_MSEC_ADD(*when, USI->now, 1000);
if ((USI->scantype == CONNECT_SCAN || USI->ptech.connecttcpscan)
&& CSI->numSDs >= CSI->maxSocketsAllowed)
if (CSI && !CSI->sendOK())
return false;
/* We need to stop sending if it has been a long time since

View File

@@ -244,11 +244,17 @@ public:
was in the list, false if you tried to clear an sd that wasn't
there in the first place. */
bool clearSD(int sd);
/* Try to get a socket that's good for select(). Return true if it worked;
* false if it didn't. */
bool sendOK();
int maxValidSD; /* The maximum socket descriptor in any of the fd_sets */
fd_set fds_read;
fd_set fds_write;
fd_set fds_except;
int numSDs; /* Number of socket descriptors being watched */
int getSocket();
private:
int nextSD;
int maxSocketsAllowed; /* No more than this many sockets may be created @once */
};

View File

@@ -88,9 +88,12 @@ void UltraProbe::setConnect(u16 portno) {
ConnectScanInfo::ConnectScanInfo() {
maxValidSD = -1;
numSDs = 0;
nextSD = -1;
if (o.max_parallelism > 0) {
maxSocketsAllowed = o.max_parallelism;
} else {
}
#ifndef WIN32
else {
/* Subtracting 10 from max_sd accounts for
stdin
stdout
@@ -106,7 +109,17 @@ ConnectScanInfo::ConnectScanInfo() {
if (maxSocketsAllowed < 5)
maxSocketsAllowed = 5;
}
/* We can't issue a FD_SET operation with a socket descriptor greater than
* FD_SETSIZE, and we can't stop the OS from handing us ones that are greater
* than that, either, so leave a buffer here. */
maxSocketsAllowed = MIN(maxSocketsAllowed, FD_SETSIZE - 10);
#else
/* Windows does not have an explicit limit, but we have to keep it below
* FD_SETSIZE or select() will fail. Fortunately, it's about the *number* of
* sockets, not the socket descriptor number, so we can run right up to that
* limit. */
maxSocketsAllowed = MIN(maxSocketsAllowed, FD_SETSIZE - 1);
#endif
FD_ZERO(&fds_read);
FD_ZERO(&fds_write);
FD_ZERO(&fds_except);
@@ -115,6 +128,38 @@ ConnectScanInfo::ConnectScanInfo() {
/* Nothing really to do here. */
ConnectScanInfo::~ConnectScanInfo() {}
bool ConnectScanInfo::sendOK() {
if (numSDs >= maxSocketsAllowed)
return false;
if (nextSD > 0)
return true;
nextSD = socket(o.af(), SOCK_STREAM, IPPROTO_TCP);
if (nextSD == -1)
pfatal("Socket creation in %s", __func__);
#ifndef WIN32
/* Check here whether this socket descriptor number will be a problem. If so,
* close it and tell the engine to slow down. Windows doesn't have this
* limit, only maxSocketsAllowed. */
if (nextSD >= FD_SETSIZE) {
if (o.debugging) {
log_write(LOG_STDOUT, "Socket descriptor %d greater than FD_SETSIZE: slow down.\n", nextSD);
}
close(nextSD);
nextSD = -1;
return false;
}
#endif
return true;
}
int ConnectScanInfo::getSocket() {
int sd = nextSD;
nextSD = -1;
return sd;
}
/* Watch a socket descriptor (add to fd_sets and maxValidSD). Returns
true if the SD was absent from the list, false if you tried to
watch an SD that was already being watched. */
@@ -370,15 +415,15 @@ UltraProbe *sendConnectScanProbe(UltraScanInfo *USI, HostScanStats *hss,
#endif
size_t socklen;
ConnectProbe *CP;
ConnectScanInfo *CSI = USI->gstats->CSI;
probe->tryno = tryno;
/* First build the probe */
probe->setConnect(destport);
CP = probe->CP();
/* Initiate the connection */
CP->sd = socket(o.af(), SOCK_STREAM, IPPROTO_TCP);
if (CP->sd == -1)
pfatal("Socket creation in %s", __func__);
CP->sd = CSI->getSocket();
assert(CP->sd > 0);
unblock_socket(CP->sd);
init_socket(CP->sd);
set_ttl(CP->sd, o.ttl);