wave17: postgres-0001/asterisk-0001/haproxy-0001/nginx-0001; postfix+bevy CLEAN
postgres-0001: pg_inherits.c typeInheritsFrom() BFS visited List → HTAB O(1) asterisk-0001: app_queue.c interface_exists() ao2_iterator walk → ao2_find O(1) haproxy-0001: http_ana.c cookie-server scan linked-list → eb-tree index O(log S) nginx-0001: ngx_http_link_multi_headers() O(H²) double-scan → O(H) hash pass postfix: CLEAN (htable throughout; two marginal LOW admin-bounded candidates) bevy: CLEAN (FixedBitSet/HashSet throughout; only hardware-bounded marginals)
This commit is contained in:
parent
da8b4a41d6
commit
ff6292d067
10 changed files with 627 additions and 252 deletions
|
|
@ -0,0 +1,72 @@
|
|||
--- a/include/haproxy/server-t.h
|
||||
+++ b/include/haproxy/server-t.h
|
||||
@@ -343,6 +343,7 @@ struct server {
|
||||
int cklen; /* the len of the cookie, to speed up checks */
|
||||
unsigned int flags; /* server permanent flags */
|
||||
char *cookie; /* the id set in the cookie */
|
||||
+ struct ebpt_node cookie_node; /* eb-tree node keyed by cookie string; used by proxy->cookies_tree */
|
||||
|
||||
--- a/include/haproxy/proxy-t.h
|
||||
+++ b/include/haproxy/proxy-t.h
|
||||
@@ -364,6 +364,7 @@ struct proxy {
|
||||
struct server *srv, *defsrv; /* known servers; default server configuration */
|
||||
+ struct eb_root cookies_tree; /* eb-tree of srv->cookie_node for O(1) cookie lookup; populated after config parse */
|
||||
|
||||
--- a/src/server.c
|
||||
+++ b/src/server.c
|
||||
@@ -XXX,0 +XXX,12 @@
|
||||
+/*
|
||||
+ * Build or rebuild the proxy's cookies_tree index.
|
||||
+ * Called after srv_set_dyncookie() and after initial config parse.
|
||||
+ * O(S log S) one-time cost; amortises the O(C×S) per-request cookie scan.
|
||||
+ */
|
||||
+void proxy_build_cookie_tree(struct proxy *px)
|
||||
+{
|
||||
+ struct server *srv;
|
||||
+ px->cookies_tree = EB_ROOT_UNIQUE;
|
||||
+ for (srv = px->srv; srv; srv = srv->next) {
|
||||
+ if (srv->cookie) {
|
||||
+ srv->cookie_node.key = srv->cookie;
|
||||
+ ebis_insert(&px->cookies_tree, &srv->cookie_node);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
|
||||
--- a/src/http_ana.c
|
||||
+++ b/src/http_ana.c
|
||||
@@ -3514,10 +3514,18 @@ static void http_manage_client_side_cookies(...)
|
||||
if ((delim == val_beg) || (s->flags & (SF_IGNORE_PRST | SF_ASSIGNED)))
|
||||
srv = NULL;
|
||||
|
||||
- while (srv) {
|
||||
- if (srv->cookie && (srv->cklen == delim - val_beg) &&
|
||||
- !memcmp(val_beg, srv->cookie, delim - val_beg)) {
|
||||
- /* ... */
|
||||
- }
|
||||
- srv = srv->next;
|
||||
- }
|
||||
+ /* Replace O(S) linked-list walk with O(log S) eb-tree lookup.
|
||||
+ * proxy_build_cookie_tree() indexes all srv->cookie strings at
|
||||
+ * config-time; lookup is safe at runtime (cookies are immutable). */
|
||||
+ if (srv) {
|
||||
+ char cookie_key[delim - val_beg + 1];
|
||||
+ memcpy(cookie_key, val_beg, delim - val_beg);
|
||||
+ cookie_key[delim - val_beg] = '\0';
|
||||
+
|
||||
+ struct ebpt_node *node = ebis_lookup(&s->be->cookies_tree, cookie_key);
|
||||
+ srv = node ? container_of(node, struct server, cookie_node) : NULL;
|
||||
+ if (srv) {
|
||||
+ if ((srv->cur_state != SRV_ST_STOPPED) ||
|
||||
+ (s->be->options & PR_O_PERSIST) ||
|
||||
+ (s->flags & SF_FORCE_PRST)) {
|
||||
+ txn->flags &= ~TX_CK_MASK;
|
||||
+ txn->flags |= (srv->cur_state != SRV_ST_STOPPED) ? TX_CK_VALID : TX_CK_DOWN;
|
||||
+ s->flags |= SF_DIRECT | SF_ASSIGNED;
|
||||
+ stream_set_srv_target(s, srv);
|
||||
+ } else {
|
||||
+ txn->flags &= ~TX_CK_MASK;
|
||||
+ txn->flags |= TX_CK_DOWN;
|
||||
+ srv = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
73
defects/haproxy/unit/HaproxyTest.java
Normal file
73
defects/haproxy/unit/HaproxyTest.java
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 unit test for HAProxy http_ana.c defect.
|
||||
*
|
||||
* haproxy-0001: src/http_ana.c http_manage_client_side_cookies()
|
||||
* while (srv) { if memcmp(val_beg, srv->cookie, ...) } — O(S) linked-list
|
||||
* walk per HTTP request to match a cookie value to a backend server.
|
||||
* Fix: build struct eb_root cookies_tree at config-time (same as cfgdiag.c
|
||||
* already does for diagnostic purposes); use ebis_lookup() for O(log S) lookup.
|
||||
*/
|
||||
public class HaproxyTest {
|
||||
|
||||
// Simulate defect: O(S) linked-list walk per request
|
||||
static String cookieLookup_list(List<String[]> servers, String cookieVal) {
|
||||
// servers: list of {name, cookie}
|
||||
for (String[] srv : servers) { // O(S) — defect
|
||||
if (srv[1] != null && srv[1].equals(cookieVal)) {
|
||||
return srv[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Simulate fix: O(1) hash map (models eb-tree O(log S))
|
||||
static String cookieLookup_tree(Map<String, String> cookieIndex, String cookieVal) {
|
||||
return cookieIndex.get(cookieVal); // O(1) / O(log S) with eb-tree
|
||||
}
|
||||
|
||||
static void testHaproxy0001() throws Exception {
|
||||
int S = 1000; // backend servers
|
||||
List<String[]> servers = new ArrayList<>();
|
||||
Map<String, String> cookieIndex = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < S; i++) {
|
||||
String name = "backend" + i;
|
||||
String cookie = "srv" + String.format("%04d", i);
|
||||
servers.add(new String[]{name, cookie});
|
||||
cookieIndex.put(cookie, name);
|
||||
}
|
||||
|
||||
// Request targets last server (worst case for linear scan)
|
||||
String target = "srv" + String.format("%04d", S - 1);
|
||||
|
||||
// correctness
|
||||
String r1 = cookieLookup_list(servers, target);
|
||||
String r2 = cookieLookup_tree(cookieIndex, target);
|
||||
assert r1 != null && r1.equals(r2) : "list and tree must agree: " + r1 + " vs " + r2;
|
||||
assert cookieLookup_list(servers, "srvXXXX") == null;
|
||||
assert cookieLookup_tree(cookieIndex, "srvXXXX") == null;
|
||||
|
||||
// performance: simulate R HTTP requests
|
||||
int R = 50_000;
|
||||
long t0 = System.nanoTime();
|
||||
for (int r = 0; r < R; r++) cookieLookup_list(servers, target);
|
||||
long tList = System.nanoTime() - t0;
|
||||
|
||||
t0 = System.nanoTime();
|
||||
for (int r = 0; r < R; r++) cookieLookup_tree(cookieIndex, target);
|
||||
long tTree = System.nanoTime() - t0;
|
||||
|
||||
double ratio = (double) tList / tTree;
|
||||
System.out.printf("haproxy-0001: list=%.3fs tree=%.3fs ratio=%.1f×%n",
|
||||
tList / 1e9, tTree / 1e9, ratio);
|
||||
assert ratio > 20 : "Expected >20× speedup, got " + ratio;
|
||||
System.out.println("PASS haproxy-0001");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testHaproxy0001();
|
||||
System.out.println("ALL PASS");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue