From: Timo Sirainen Date: Fri, 17 Apr 2026 13:57:24 +0000 (+0200) Subject: [PATCH 14/14] lib-mail: Limit total MIME parameter count per message to 200 000 X-Git-Tag: archive/raspbian/1%2.4.1+dfsg1-6+rpi1+deb13u7^2~50 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=2f1b54334c4c49c9ed6036b25e53a08d3cc11db0;p=dovecot.git [PATCH 14/14] lib-mail: Limit total MIME parameter count per message to 200 000 Content-Type and Content-Disposition parameters are both parsed through parse_mime_parameters(). A message with many MIME parts each having many parameters can accumulate millions of struct message_part_param entries. Add remaining_mime_params to struct message_part_data_limits (combined budget for both Content-Type and Content-Disposition), initialised to MESSAGE_PART_DATA_MAX_TOTAL_MIME_PARAMS (200 000). Cap params_count to the remaining budget before allocating and deduct accordingly. Co-Authored-By: Claude Sonnet 4.6 Gbp-Pq: Name 0014-lib-mail-Limit-total-MIME-parameter-count-per-messag.patch --- diff --git a/src/lib-mail/message-part-data.c b/src/lib-mail/message-part-data.c index 2eed994..e0a3676 100644 --- a/src/lib-mail/message-part-data.c +++ b/src/lib-mail/message-part-data.c @@ -263,7 +263,8 @@ void message_part_envelope_parse_from_header(pool_t pool, static void parse_mime_parameters(struct rfc822_parser_context *parser, pool_t pool, const struct message_part_param **params_r, - unsigned int *params_count_r) + unsigned int *params_count_r, + struct message_part_data_limits *limits) { const char *const *results; struct message_part_param *params; @@ -275,6 +276,10 @@ parse_mime_parameters(struct rfc822_parser_context *parser, i_assert((params_count % 2) == 0); params_count /= 2; + if (params_count > limits->remaining_mime_params) + params_count = limits->remaining_mime_params; + limits->remaining_mime_params -= params_count; + if (params_count > 0) { params = p_new(pool, struct message_part_param, params_count); for (i = 0; i < params_count; i++) { @@ -289,7 +294,8 @@ parse_mime_parameters(struct rfc822_parser_context *parser, static void parse_content_type(struct message_part_data *data, - pool_t pool, struct message_header_line *hdr) + pool_t pool, struct message_header_line *hdr, + struct message_part_data_limits *limits) { struct rfc822_parser_context parser; string_t *str; @@ -332,7 +338,7 @@ parse_content_type(struct message_part_data *data, parse_mime_parameters(&parser, pool, &data->content_type_params, - &data->content_type_params_count); + &data->content_type_params_count, limits); rfc822_parser_deinit(&parser); } @@ -357,7 +363,8 @@ parse_content_transfer_encoding(struct message_part_data *data, static void parse_content_disposition(struct message_part_data *data, - pool_t pool, struct message_header_line *hdr) + pool_t pool, struct message_header_line *hdr, + struct message_part_data_limits *limits) { struct rfc822_parser_context parser; string_t *str; @@ -374,7 +381,7 @@ parse_content_disposition(struct message_part_data *data, parse_mime_parameters(&parser, pool, &data->content_disposition_params, - &data->content_disposition_params_count); + &data->content_disposition_params_count, limits); rfc822_parser_deinit(&parser); } @@ -453,7 +460,7 @@ parse_content_header(struct message_part_data *data, case 't': case 'T': if (strcasecmp(name, "Type") == 0 && data->content_type == NULL) - parse_content_type(data, pool, hdr); + parse_content_type(data, pool, hdr, limits); else if (strcasecmp(name, "Transfer-Encoding") == 0 && data->content_transfer_encoding == NULL) parse_content_transfer_encoding(data, pool, hdr); @@ -482,7 +489,7 @@ parse_content_header(struct message_part_data *data, hdr->full_value_len); else if (strcasecmp(name, "Disposition") == 0 && data->content_disposition_params == NULL) - parse_content_disposition(data, pool, hdr); + parse_content_disposition(data, pool, hdr, limits); break; } } diff --git a/src/lib-mail/message-part-data.h b/src/lib-mail/message-part-data.h index 7f1f9c3..f439926 100644 --- a/src/lib-mail/message-part-data.h +++ b/src/lib-mail/message-part-data.h @@ -10,15 +10,19 @@ struct message_header_line; #define MESSAGE_PART_DATA_MAX_TOTAL_ADDRESSES 100000 #define MESSAGE_PART_DATA_MAX_TOTAL_LANGUAGE_TAGS 100000 +/* Combined limit for Content-Type + Content-Disposition parameters */ +#define MESSAGE_PART_DATA_MAX_TOTAL_MIME_PARAMS 200000 struct message_part_data_limits { unsigned int remaining_addresses; unsigned int remaining_language_tags; + unsigned int remaining_mime_params; }; #define MESSAGE_PART_DATA_LIMITS_INIT \ { MESSAGE_PART_DATA_MAX_TOTAL_ADDRESSES, \ - MESSAGE_PART_DATA_MAX_TOTAL_LANGUAGE_TAGS } + MESSAGE_PART_DATA_MAX_TOTAL_LANGUAGE_TAGS, \ + MESSAGE_PART_DATA_MAX_TOTAL_MIME_PARAMS } struct message_part_param { const char *name;