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:
parent
421f3352c7
commit
ba818693db
21 changed files with 2213 additions and 0 deletions
90
defects/nginx/unit/NginxKeepaliveCacheLinearScanTest.java
Normal file
90
defects/nginx/unit/NginxKeepaliveCacheLinearScanTest.java
Normal 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 100–10000 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");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue