]> git.ipfire.org Git - thirdparty/rspamd.git/commit
[Fix] multipattern: bound URL query scan reentrancy
authorVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 4 Jun 2026 08:55:22 +0000 (09:55 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 4 Jun 2026 08:55:51 +0000 (09:55 +0100)
commitf068a1156a7dc4fd73dd02743e1e56cd7b820813
treef0a10b20eace0d09dc753db409feae062f62fcbe
parentccc181fa0e3b9278dcbd357454e50f0c1dd4fa34
[Fix] multipattern: bound URL query scan reentrancy

A URL whose query embeds a percent-escaped URL is unwrapped
recursively (PR #6066): rspamd_url_find_in_query re-enters
rspamd_multipattern_lookup on the URL trie while the enclosing scan
is still on the stack. Each scan borrows one of MAX_SCRATCH hyperscan
scratch contexts; once the recursion nests deeper than the pool, the
slot loop leaves scr == NULL and g_assert(scr != NULL) aborts the
worker. A crafted message with a few levels of nested query URLs thus
crashes a normal worker (DoS).

The peak number of simultaneously-held scratch contexts on the
deepest chain is RSPAMD_URL_QUERY_MAX_NESTING + 2: one for the
enclosing text/subject scan and one for the per-URL TLD lookup that
rspamd_url_parse runs on each freshly extracted leaf. The old pool of
4 with a nesting cap of 5 needed 7 -> assertion.

- Introduce RSPAMD_MULTIPATTERN_MAX_REENTRANCY (10) and size the
  scratch stack from it; a scratch context is ~2.5-4 KiB, so the
  deeper stack costs only tens of KiB per multipattern.
- Tie RSPAMD_URL_QUERY_MAX_NESTING to that budget (minus the two
  implicit levels) so normal nesting stays on the fast path.
- Make scratch exhaustion non-fatal: allocate a one-off scratch for
  the scan instead of aborting the worker on attacker input.
- Guard the unsigned-int scratch bitmask with a static assert.

Add functional regression test 170_url_query_nesting.
src/libserver/url.h
src/libutil/multipattern.c
src/libutil/multipattern.h
test/functional/cases/170_url_query_nesting.robot [new file with mode: 0644]
test/functional/configs/url_query_nesting.conf [new file with mode: 0644]
test/functional/messages/url_query_nesting.eml [new file with mode: 0644]