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:
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user