]> git.ipfire.org Git - thirdparty/rspamd.git/commit
[Fix] mime_parser: bound S/MIME recursion depth
authorVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 30 May 2026 12:21:37 +0000 (13:21 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 30 May 2026 12:39:40 +0000 (13:39 +0100)
commitf6536945f137c2d200acd0644069cb448fea9045
tree3a38a4cb7c932a52aeeb547e42012a03abfbc7e7
parentf70285614752390127811f47c61eae695f5fa4a4
[Fix] mime_parser: bound S/MIME recursion depth

Nested S/MIME structures re-entered the parser through
rspamd_mime_parse_normal_part -> rspamd_mime_process_multipart_node ->
rspamd_mime_parse_normal_part without passing through the
multipart/message nesting checks, so st->nesting was never incremented
on that path. application/pkcs7-mime only sets the SMIME content-type
flag (not MESSAGE/MULTIPART), so such parts take the normal-part branch.
A crafted message with deeply nested application/pkcs7-mime layers could
therefore recurse to a depth bounded only by message size rather than by
max_nested, exhausting the worker stack (DoS) and accumulating the
CMS/PKCS7/BIO objects of every level simultaneously.

Account for the S/MIME re-entry against max_nested and free the
CMS/PKCS7/BIO objects on the new error path; the nesting cap also bounds
the peak memory held during unwinding.

Two related defensive guards:
- rspamd_mime_preprocess_message now looks back one byte before the body
  only when that stays within the buffer, avoiding a potential 1-byte
  out-of-bounds read when raw_data.begin == st->start.
- guard the boundary-stack pop in rspamd_mime_parse_multipart_part with
  len > 0, mirroring the guarded pop in rspamd_mime_parse_message.
src/libmime/mime_parser.c