2.6 KiB
postfix-0002 — Quadratic address masquerade exception check
Target: Postfix (vdukhovni/postfix mirror of postfix.org) Severity: MEDIUM CWE: CWE-407 (Algorithmic Complexity — Quadratic) Status: PATCHED (patch/postfix-0002.patch)
Summary
cleanup_masquerade_external() in cleanup/cleanup_masquerade.c calls
string_list_match(cleanup_masq_exceptions, name) for every address in a message's
envelope and headers. string_list_match is O(E) for E inline exception patterns.
The function is also called for each BCC auto-expansion address. With E exceptions
and N total addresses per message the cost is O(N × E).
Additionally, the masquerade-domain loop inside the same function
(for (masqp = masq_domains->argv; ...; masqp++)) is O(D) per address,
giving O(N × D) for D masquerade domains.
A message with 500 To/Cc recipients and a masquerade_exceptions list of 200
user names produces 100 000 string comparisons in the cleanup daemon per message.
Location
postfix/src/cleanup/cleanup_masquerade.c
line 108 string_list_match(cleanup_masq_exceptions, name) — O(E) per address
line 125 for (masqp = masq_domains->argv; ...) — O(D) per address
postfix/src/cleanup/cleanup_addr.c
line 150 cleanup_masquerade_internal(state, clean_addr, cleanup_masq_domains)
line 218 cleanup_masquerade_internal(state, clean_addr, cleanup_masq_domains)
line 277 cleanup_masquerade_internal(state, clean_addr, cleanup_masq_domains)
postfix/src/cleanup/cleanup_message.c
line 187 cleanup_masquerade_tree(...)
line 244 cleanup_masquerade_tree(...)
Root Cause
string_list_match(cleanup_masq_exceptions, name) performs a linear ARGV scan for
each address. cleanup_masq_exceptions is initialized once from var_masq_exceptions
at startup but never converted to a hash structure. The masquerade domains array is
also a raw ARGV * with no hash index, scanned linearly for every address processed.
Fix
-
Convert
cleanup_masq_exceptionsfromSTRING_LIST(linearARGV) toHTABLE *(Postfix hash table) at initialization time: one O(E) pass at startup, then O(1) per lookup. -
Sort
masq_domains->argvat initialization and binary-search on match; or build a parallelHTABLE *for exact-match domains.
Complexity
- Slow: O(N × (E + D)) — N addresses × E exceptions × D masq domains
- Fast: O(N) — O(1) hash lookup per address for both exceptions and domains
- Speedup at N=500, E=200, D=50: ~250×
Patch
See defects/postfix/patch/postfix-0002.patch
Unit Test
See defects/postfix/unit/PostfixTest.java (combined with postfix-0001)