1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-08 21:51:28 +00:00

Added safe fd_set operations.

Only FD_SET and FD_CLR were available. Added a FD_ISSET equivalent.
Implemented them as static inline instead of macros for consistency.

These functions abort() if the FD number is higher than FD_SETSIZE
(except on windows where no check is performed).
This commit is contained in:
henri
2014-01-30 19:02:57 +00:00
parent bf872bf113
commit 64fb5b3482
4 changed files with 64 additions and 56 deletions

View File

@@ -1,4 +1,7 @@
# Nmap Changelog ($Id$); -*-text-*- # Nmap Changelog ($Id$); -*-text-*-
o Added safe fd_set operations. This makes nmap fail gracefully instead of
crashing when the number of file descriptors grows over FD_SETSIZE. Jacek
Wielemborek reported the crash. [Henri Doreau]
o [NSE] Added tls library for functions related to SSLv3 and TLS messages. o [NSE] Added tls library for functions related to SSLv3 and TLS messages.
Existing ssl-enum-ciphers, ssl-date, and tls-nextprotoneg scripts were Existing ssl-enum-ciphers, ssl-date, and tls-nextprotoneg scripts were

View File

@@ -369,37 +369,41 @@ extern "C" int vsnprintf (char *, size_t, const char *, va_list);
#endif #endif
#ifdef WIN32 static inline int checked_fd_isset(int fd, const fd_set *fds) {
#define CHECKED_FD_SET FD_SET #ifndef WIN32
#else if (fd >= FD_SETSIZE) {
#define CHECKED_FD_SET(fd, set) \ fprintf(stderr, "Attempt to FD_ISSET fd %d, which is not less than "
do { \ "FD_SETSIZE (%d). Try using a lower parallelism.",
if ((fd) < FD_SETSIZE) { \ fd, FD_SETSIZE);
FD_SET((fd), (set)); \ abort();
} else { \ }
fprintf(stderr, "%s:%ld: Attempt to FD_SET fd %d, which is not less than" \
" FD_SETSIZE (%d). Try using a lower parallelism.", \
__FILE__, (long int) __LINE__, (fd), FD_SETSIZE); \
abort(); \
} \
} while (0)
#endif #endif
return FD_ISSET(fd, fds);
}
#ifdef WIN32 static inline void checked_fd_clr(int fd, fd_set *fds) {
#define CHECKED_FD_CLR FD_CLR #ifndef WIN32
#else if (fd >= FD_SETSIZE) {
#define CHECKED_FD_CLR(fd, set) \ fprintf(stderr, "Attempt to FD_CLR fd %d, which is not less than "
do { \ "FD_SETSIZE (%d). Try using a lower parallelism.",
if ((fd) < FD_SETSIZE) { \ fd, FD_SETSIZE);
FD_CLR((fd), (set)); \ abort();
} else { \ }
fprintf(stderr, "%s:%ld: Attempt to FD_CLR fd %d, which is not less than" \
" FD_SETSIZE (%d). Try using a lower parallelism.", \
__FILE__, (long int) __LINE__, (fd), FD_SETSIZE); \
abort(); \
} \
} while (0)
#endif #endif
FD_CLR(fd, fds);
}
static inline void checked_fd_set(int fd, fd_set *fds) {
#ifndef WIN32
if (fd >= FD_SETSIZE) {
fprintf(stderr, "Attempt to FD_SET fd %d, which is not less than "
"FD_SETSIZE (%d). Try using a lower parallelism.",
fd, FD_SETSIZE);
abort();
}
#endif
FD_SET(fd, fds);
}
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -175,18 +175,18 @@ int select_iod_unregister(mspool *nsp, msiod *iod) {
if (iod->pcap) { if (iod->pcap) {
int sd = ((mspcap *)iod->pcap)->pcap_desc; int sd = ((mspcap *)iod->pcap)->pcap_desc;
if (sd >= 0) { if (sd >= 0) {
CHECKED_FD_CLR(sd, &sinfo->fds_master_r); checked_fd_clr(sd, &sinfo->fds_master_r);
CHECKED_FD_CLR(sd, &sinfo->fds_results_r); checked_fd_clr(sd, &sinfo->fds_results_r);
} }
} else } else
#endif #endif
{ {
CHECKED_FD_CLR(iod->sd, &sinfo->fds_master_r); checked_fd_clr(iod->sd, &sinfo->fds_master_r);
CHECKED_FD_CLR(iod->sd, &sinfo->fds_master_w); checked_fd_clr(iod->sd, &sinfo->fds_master_w);
CHECKED_FD_CLR(iod->sd, &sinfo->fds_master_x); checked_fd_clr(iod->sd, &sinfo->fds_master_x);
CHECKED_FD_CLR(iod->sd, &sinfo->fds_results_r); checked_fd_clr(iod->sd, &sinfo->fds_results_r);
CHECKED_FD_CLR(iod->sd, &sinfo->fds_results_w); checked_fd_clr(iod->sd, &sinfo->fds_results_w);
CHECKED_FD_CLR(iod->sd, &sinfo->fds_results_x); checked_fd_clr(iod->sd, &sinfo->fds_results_x);
} }
if (sinfo->max_sd == iod->sd) if (sinfo->max_sd == iod->sd)
@@ -210,23 +210,23 @@ int select_iod_modify(mspool *nsp, msiod *iod, int ev_set, int ev_clr) {
/* -- set events -- */ /* -- set events -- */
if (ev_set & EV_READ) if (ev_set & EV_READ)
CHECKED_FD_SET(sd, &sinfo->fds_master_r); checked_fd_set(sd, &sinfo->fds_master_r);
if (ev_set & EV_WRITE) if (ev_set & EV_WRITE)
CHECKED_FD_SET(sd, &sinfo->fds_master_w); checked_fd_set(sd, &sinfo->fds_master_w);
if (ev_set & EV_EXCEPT) if (ev_set & EV_EXCEPT)
CHECKED_FD_SET(sd, &sinfo->fds_master_x); checked_fd_set(sd, &sinfo->fds_master_x);
/* -- clear events -- */ /* -- clear events -- */
if (ev_clr & EV_READ) if (ev_clr & EV_READ)
CHECKED_FD_CLR(sd, &sinfo->fds_master_r); checked_fd_clr(sd, &sinfo->fds_master_r);
if (ev_clr & EV_WRITE) if (ev_clr & EV_WRITE)
CHECKED_FD_CLR(sd, &sinfo->fds_master_w); checked_fd_clr(sd, &sinfo->fds_master_w);
if (ev_clr & EV_EXCEPT) if (ev_clr & EV_EXCEPT)
CHECKED_FD_CLR(sd, &sinfo->fds_master_x); checked_fd_clr(sd, &sinfo->fds_master_x);
/* -- update max_sd -- */ /* -- update max_sd -- */
@@ -339,7 +339,7 @@ static inline int get_evmask(const mspool *nsp, const msiod *nsi) {
#if HAVE_PCAP #if HAVE_PCAP
#ifndef PCAP_CAN_DO_SELECT #ifndef PCAP_CAN_DO_SELECT
if (nsi->pcap) { if (nsi->pcap) {
/* Always assume readable for a non-blocking read. We can't check FD_ISSET /* Always assume readable for a non-blocking read. We can't check checked_fd_isset
because we don't have a pcap_desc. */ because we don't have a pcap_desc. */
evmask |= EV_READ; evmask |= EV_READ;
return evmask; return evmask;
@@ -356,11 +356,11 @@ static inline int get_evmask(const mspool *nsp, const msiod *nsi) {
assert(sd >= 0); assert(sd >= 0);
if (FD_ISSET(sd, &sinfo->fds_results_r)) if (checked_fd_isset(sd, &sinfo->fds_results_r))
evmask |= EV_READ; evmask |= EV_READ;
if (FD_ISSET(sd, &sinfo->fds_results_w)) if (checked_fd_isset(sd, &sinfo->fds_results_w))
evmask |= EV_WRITE; evmask |= EV_WRITE;
if (FD_ISSET(sd, &sinfo->fds_results_x)) if (checked_fd_isset(sd, &sinfo->fds_results_x))
evmask |= EV_EXCEPT; evmask |= EV_EXCEPT;
return evmask; return evmask;

View File

@@ -1029,10 +1029,10 @@ ConnectScanInfo::~ConnectScanInfo() {}
watch an SD that was already being watched. */ watch an SD that was already being watched. */
bool ConnectScanInfo::watchSD(int sd) { bool ConnectScanInfo::watchSD(int sd) {
assert(sd >= 0); assert(sd >= 0);
if (!FD_ISSET(sd, &fds_read)) { if (!checked_fd_isset(sd, &fds_read)) {
CHECKED_FD_SET(sd, &fds_read); checked_fd_set(sd, &fds_read);
CHECKED_FD_SET(sd, &fds_write); checked_fd_set(sd, &fds_write);
CHECKED_FD_SET(sd, &fds_except); checked_fd_set(sd, &fds_except);
numSDs++; numSDs++;
if (sd > maxValidSD) if (sd > maxValidSD)
maxValidSD = sd; maxValidSD = sd;
@@ -1047,10 +1047,10 @@ bool ConnectScanInfo::watchSD(int sd) {
there in the first place. */ there in the first place. */
bool ConnectScanInfo::clearSD(int sd) { bool ConnectScanInfo::clearSD(int sd) {
assert(sd >= 0); assert(sd >= 0);
if (FD_ISSET(sd, &fds_read)) { if (checked_fd_isset(sd, &fds_read)) {
CHECKED_FD_CLR(sd, &fds_read); checked_fd_clr(sd, &fds_read);
CHECKED_FD_CLR(sd, &fds_write); checked_fd_clr(sd, &fds_write);
CHECKED_FD_CLR(sd, &fds_except); checked_fd_clr(sd, &fds_except);
assert(numSDs > 0); assert(numSDs > 0);
numSDs--; numSDs--;
if (sd == maxValidSD) if (sd == maxValidSD)
@@ -4172,8 +4172,9 @@ static bool do_one_select_round(UltraScanInfo *USI, struct timeval *stime) {
assert(probe->type == UltraProbe::UP_CONNECT); assert(probe->type == UltraProbe::UP_CONNECT);
sd = probe->CP()->sd; sd = probe->CP()->sd;
/* Let see if anything has happened! */ /* Let see if anything has happened! */
if (sd >= 0 && (FD_ISSET(sd, &fds_rtmp) || FD_ISSET(sd, &fds_wtmp) || if (sd >= 0 && (checked_fd_isset(sd, &fds_rtmp) ||
FD_ISSET(sd, &fds_xtmp))) { checked_fd_isset(sd, &fds_wtmp) ||
checked_fd_isset(sd, &fds_xtmp))) {
numGoodSD++; numGoodSD++;
newportstate = PORT_UNKNOWN; newportstate = PORT_UNKNOWN;
if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char *) &optval, if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (char *) &optval,