nmap-0002: nmap.cc merge_port_lists O(N²) port dedup → unordered_set O(N); ~65000x at max range haproxy-0004: http_ana.c http_capture_headers O(H×C) cap_hdr walk per request → pre-built HashMap O(H) nginx-0004: ngx_http_upstream_keepalive_module.c keepalive_get_peer O(C) sockaddr scan per upstream request → HashMap O(1) weechat-0003: irc-channel.c irc_channel_search O(C) linked-list scan per message handler → channels_hashtable O(1) zeek-0002: Attr.cc Attributes::AddAttrs O(A²) triple-Find/RemoveAttr per attr → unordered_map index O(A) curl-0004: mime.c search_header O(P×H) 3x per part per mime_add_headers → pre-indexed header name set O(P)
90 lines
3.4 KiB
Java
90 lines
3.4 KiB
Java
package unit;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* nmap-0002 — CWE-407: O(N²) port deduplication in merge_port_lists
|
|
*
|
|
* Models nmap.cc insert_port_into_merge_list():
|
|
* Slow: for each port to insert, linear scan of already-merged list (O(N))
|
|
* called N times → O(N²) total
|
|
* Fast: unordered_set<uint16_t>: O(1) insert + dedup → O(N) total
|
|
*
|
|
* Trigger: nmap -PS<range> -PA<range> with large overlapping port lists.
|
|
* Default lists are tiny (1-2 ports), but user can pass 1-65535 for both.
|
|
*/
|
|
public class NmapMergePortListsTest {
|
|
|
|
// --- SLOW: linear scan dedup (defect) ---
|
|
static long mergePortListsSlow(int[] list1, int[] list2) {
|
|
long ops = 0;
|
|
List<Integer> merged = new ArrayList<>(list1.length + list2.length);
|
|
for (int p : list1) {
|
|
boolean found = false;
|
|
for (int m : merged) { ops++; if (m == p) { found = true; break; } }
|
|
if (!found) merged.add(p);
|
|
}
|
|
for (int p : list2) {
|
|
boolean found = false;
|
|
for (int m : merged) { ops++; if (m == p) { found = true; break; } }
|
|
if (!found) merged.add(p);
|
|
}
|
|
return ops;
|
|
}
|
|
|
|
// --- FAST: hash set dedup (fix) ---
|
|
static long mergePortListsFast(int[] list1, int[] list2) {
|
|
long ops = 0;
|
|
Set<Integer> seen = new HashSet<>((list1.length + list2.length) * 2);
|
|
for (int p : list1) { ops++; seen.add(p); }
|
|
for (int p : list2) { ops++; seen.add(p); }
|
|
return ops;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
System.out.println("nmap-0002 CWE-407: merge_port_lists O(N²) vs O(N)");
|
|
System.out.println("===================================================");
|
|
|
|
// Small test: two overlapping port lists
|
|
int N = 500;
|
|
int[] list1 = new int[N];
|
|
int[] list2 = new int[N];
|
|
for (int i = 0; i < N; i++) {
|
|
list1[i] = i + 1; // ports 1..500
|
|
list2[i] = i + 250; // ports 250..750 (overlap with list1)
|
|
}
|
|
|
|
long slowOps = mergePortListsSlow(list1, list2);
|
|
long fastOps = mergePortListsFast(list1, list2);
|
|
|
|
System.out.printf(" N=%d ports per list (250 overlap)%n", N);
|
|
System.out.printf(" Slow (linear scan): %,d ops%n", slowOps);
|
|
System.out.printf(" Fast (hash set): %,d ops%n", fastOps);
|
|
System.out.printf(" Op ratio: %.0fx%n", (double) slowOps / fastOps);
|
|
|
|
// Larger test
|
|
int N2 = 2000;
|
|
int[] big1 = new int[N2];
|
|
int[] big2 = new int[N2];
|
|
for (int i = 0; i < N2; i++) {
|
|
big1[i] = i + 1;
|
|
big2[i] = i + 1000; // 1000 overlap
|
|
}
|
|
|
|
long slowOps2 = mergePortListsSlow(big1, big2);
|
|
long fastOps2 = mergePortListsFast(big1, big2);
|
|
|
|
System.out.printf("%n N=%d ports per list (1000 overlap)%n", N2);
|
|
System.out.printf(" Slow (linear scan): %,d ops%n", slowOps2);
|
|
System.out.printf(" Fast (hash set): %,d ops%n", fastOps2);
|
|
System.out.printf(" Op ratio: %.0fx%n", (double) slowOps2 / fastOps2);
|
|
|
|
// Assert O(N²) vs O(N)
|
|
assert slowOps > fastOps * (N / 2) :
|
|
"Expected slow > fast*" + (N/2) + " but slow=" + slowOps + " fast=" + fastOps;
|
|
assert slowOps2 > fastOps2 * (N2 / 4) :
|
|
"Expected slow2 > fast2*" + (N2/4) + " but slow2=" + slowOps2 + " fast2=" + fastOps2;
|
|
|
|
System.out.println("\nPASS");
|
|
}
|
|
}
|