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

2.6 KiB
Raw Blame History

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)