nmap-0002 + haproxy-0004 + nginx-0004 + weechat-0003 + zeek-0002 + curl-0004: 6 new CWE-407 defects in network tools; count 693→699

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)
This commit is contained in:
russell@unturf.com 2026-03-29 22:22:11 -04:00
parent 421f3352c7
commit ba818693db
21 changed files with 2213 additions and 0 deletions

View file

@ -0,0 +1,90 @@
package unit;
import java.util.*;
/**
* nginx-0004 CWE-407: ngx_http_upstream_keepalive_get_peer O(C) per upstream request
*
* Models src/http/modules/ngx_http_upstream_keepalive_module.c
* ngx_http_upstream_keepalive_get_peer() (~line 212):
* Slow: iterates free[] queue scanning for matching sockaddr O(C) per request
* where C = keepalive cache size (default 0, but configured 10010000 in production)
* Fast: HashMap<sockaddrKey, connection> O(1) per request
*
* Hot path: called on every upstream HTTP request that could reuse a keepalive connection.
* With `keepalive 1000` configured and many distinct upstreams, degrades to O(1000) per request.
*/
public class NginxKeepaliveCacheLinearScanTest {
// Simulates ngx_connection_t / ngx_peer_connection_t with a sockaddr key
static class KeepaliveConn {
final String sockaddrKey; // e.g., "192.168.1.1:8080"
KeepaliveConn(String sockaddrKey) { this.sockaddrKey = sockaddrKey; }
}
// --- SLOW: O(C) linear scan (defect) ---
// Models: for (q = ngx_queue_head(cache); q != ngx_queue_sentinel(cache); q = ngx_queue_next(q))
// item = ngx_queue_data(q, ...); if (ngx_memn2cmp(sockaddr, item->sockaddr) == 0) found
static long keepaliveGetPeerSlow(List<KeepaliveConn> cache, String target) {
long ops = 0;
for (KeepaliveConn conn : cache) {
ops++;
if (conn.sockaddrKey.equals(target)) break;
}
return ops;
}
// --- FAST: O(1) hash lookup (fix) ---
// Models: pre-built HashMap keyed by sockaddr at connection cache time
static long keepaliveGetPeerFast(Map<String, KeepaliveConn> index, String target) {
index.get(target);
return 1;
}
// Build a keepalive cache with C connections to distinct upstream addresses
static List<KeepaliveConn> buildCache(int C) {
List<KeepaliveConn> cache = new ArrayList<>(C);
for (int i = 0; i < C; i++)
cache.add(new KeepaliveConn("10.0." + (i / 256) + "." + (i % 256) + ":8080"));
return cache;
}
static Map<String, KeepaliveConn> buildIndex(List<KeepaliveConn> cache) {
Map<String, KeepaliveConn> map = new HashMap<>(cache.size() * 2);
for (KeepaliveConn c : cache) map.put(c.sockaddrKey, c);
return map;
}
public static void main(String[] args) {
System.out.println("nginx-0004 CWE-407: keepalive_get_peer O(C) vs O(1)");
System.out.println("======================================================");
// R = number of upstream requests, C = keepalive cache size
// target is the last entry (worst-case scan)
int[][] params = { {100, 100}, {500, 500}, {1000, 1000} };
for (int[] p : params) {
int R = p[0], C = p[1];
List<KeepaliveConn> cache = buildCache(C);
Map<String, KeepaliveConn> index = buildIndex(cache);
// Worst-case: target is the last connection in the cache
String target = cache.get(C - 1).sockaddrKey;
long slowTotal = 0, fastTotal = 0;
for (int r = 0; r < R; r++) {
slowTotal += keepaliveGetPeerSlow(cache, target);
fastTotal += keepaliveGetPeerFast(index, target);
}
double ratio = (double) slowTotal / fastTotal;
System.out.printf(" C=%4d cache, R=%4d requests (worst-case): slow=%,8d ops fast=%,5d ops speedup=%.0fx%n",
C, R, slowTotal, fastTotal, ratio);
assert ratio >= (double) C / 2 :
"Expected speedup >= " + (C/2) + "x but got " + ratio + " (C=" + C + ")";
}
System.out.println("\nPASS");
}
}