java-topology/docs/tickets/postfix-0002-masquerade-exception-linear-scan.md

68 lines
2.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
1. Convert `cleanup_masq_exceptions` from `STRING_LIST` (linear `ARGV`) to
`HTABLE *` (Postfix hash table) at initialization time: one O(E) pass at startup,
then O(1) per lookup.
2. Sort `masq_domains->argv` at initialization and binary-search on match;
or build a parallel `HTABLE *` 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)