# nmap-0001: CWE-407 — O(n²) port membership test in version-detection hot path **Severity:** HIGH **File:** `service_scan.cc:1259` (portIsProbable), `service_scan.cc:1269` (serviceIsPossible) **Status:** PATCHED ## Description `ServiceProbe::portIsProbable()` performs a linear `std::find` over a `std::vector` of probable ports on every call. It is called inside the `nextProbe()` loop, which iterates all 187 probes in `nmap-service-probes` for every service being fingerprinted. Outer loop: O(P) probes Inner: `find(portv->begin(), portv->end(), portno)` = O(K) where K = ports in that probe's list One probe lists `32,771` expanded ports after range expansion. Typical probes list dozens to hundreds of ports. For a large `-sV` scan across many open ports, this is called millions of times during probe selection. `ServiceProbe::serviceIsPossible()` has the same defect: O(D) linear strcmp loop over `detectedServices` (up to ~10 services), called at the same hot-path call sites. ## Root Cause ```cpp // service_scan.cc:1254-1262 — portIsProbable bool ServiceProbe::portIsProbable(enum service_tunnel_type tunnel, u16 portno) const { const std::vector *portv; portv = (tunnel == SERVICE_TUNNEL_SSL)? &probablesslports : &probableports; if (find(portv->begin(), portv->end(), portno) == portv->end()) // O(K) linear scan return false; return true; } // service_scan.cc:1266-1274 — serviceIsPossible bool ServiceProbe::serviceIsPossible(const char *sname) const { for(vi = detectedServices.begin(); vi != detectedServices.end(); vi++) { // O(D) if (strcmp(*vi, sname) == 0) return true; } return false; } ``` Called at `service_scan.cc:1839` and `1862` inside a while loop over all probes. ## Fix Replace `probableports`/`probablesslports` with `std::unordered_set` (O(1) lookup). Replace `detectedServices` with `std::unordered_set` (O(1) lookup). Sort-and-binary-search (`std::sort` + `std::binary_search`) is an alternative if order must be preserved, but unordered_set is cleaner. ## Patch See `patch/nmap-0001.patch` ## Benchmark See `unit/NmapPortMembershipTest.java` — N=200 probes × K=1000 ports: - Slow (vector find): ~200,000 operations - Fast (unordered_set): ~200 operations - Speedup: ~1000×