From: Timo Sirainen Date: Fri, 17 Apr 2026 13:56:37 +0000 (+0200) Subject: [PATCH 13/14] lib-mail: Limit total Content-Language tag count per message to 100 000 X-Git-Tag: archive/raspbian/1%2.4.1+dfsg1-6+rpi1+deb13u7^2~51 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=a5df978bb0e258b0bde97f07daa77a08e106bf1a;p=dovecot.git [PATCH 13/14] lib-mail: Limit total Content-Language tag count per message to 100 000 A multipart message with many MIME parts each containing many language tags can exhaust memory: the per-part RFC 2231 parser had no cumulative limit. Add remaining_language_tags to struct message_part_data_limits, initialised to MESSAGE_PART_DATA_MAX_TOTAL_LANGUAGE_TAGS (100 000). Break out of the tag-parsing loop in parse_content_language() once the budget reaches zero. Co-Authored-By: Claude Sonnet 4.6 Gbp-Pq: Name 0013-lib-mail-Limit-total-Content-Language-tag-count-per-.patch --- diff --git a/src/lib-mail/message-part-data.c b/src/lib-mail/message-part-data.c index 24e1a31..2eed994 100644 --- a/src/lib-mail/message-part-data.c +++ b/src/lib-mail/message-part-data.c @@ -380,7 +380,8 @@ parse_content_disposition(struct message_part_data *data, static void parse_content_language(struct message_part_data *data, - pool_t pool, const unsigned char *value, size_t value_len) + pool_t pool, const unsigned char *value, size_t value_len, + struct message_part_data_limits *limits) { struct rfc822_parser_context parser; ARRAY_TYPE(const_string) langs; @@ -398,8 +399,11 @@ parse_content_language(struct message_part_data *data, rfc822_skip_lwsp(&parser); while (rfc822_parse_atom(&parser, str) >= 0) { - const char *lang = p_strdup(pool, str_c(str)); + if (limits->remaining_language_tags == 0) + break; + limits->remaining_language_tags--; + const char *lang = p_strdup(pool, str_c(str)); array_push_back(&langs, &lang); str_truncate(str, 0); @@ -419,7 +423,8 @@ parse_content_language(struct message_part_data *data, static void parse_content_header(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) { const char *name = hdr->name + strlen("Content-"); @@ -459,7 +464,7 @@ parse_content_header(struct message_part_data *data, if (strcasecmp(name, "Language") == 0 && data->content_language == NULL) { parse_content_language(data, pool, - hdr->full_value, hdr->full_value_len); + hdr->full_value, hdr->full_value_len, limits); } else if (strcasecmp(name, "Location") == 0 && data->content_location == NULL) { data->content_location = @@ -524,7 +529,7 @@ void message_part_data_parse_from_header(pool_t pool, if (str_begins_icase_with(hdr->name, "Content-")) { T_BEGIN { - parse_content_header(part_data, pool, hdr); + parse_content_header(part_data, pool, hdr, limits); } T_END; } diff --git a/src/lib-mail/message-part-data.h b/src/lib-mail/message-part-data.h index af09ea7..7f1f9c3 100644 --- a/src/lib-mail/message-part-data.h +++ b/src/lib-mail/message-part-data.h @@ -9,13 +9,16 @@ struct message_header_line; #define MESSAGE_PART_DATA_MAX_TOTAL_ADDRESSES 100000 +#define MESSAGE_PART_DATA_MAX_TOTAL_LANGUAGE_TAGS 100000 struct message_part_data_limits { unsigned int remaining_addresses; + unsigned int remaining_language_tags; }; #define MESSAGE_PART_DATA_LIMITS_INIT \ - { MESSAGE_PART_DATA_MAX_TOTAL_ADDRESSES } + { MESSAGE_PART_DATA_MAX_TOTAL_ADDRESSES, \ + MESSAGE_PART_DATA_MAX_TOTAL_LANGUAGE_TAGS } struct message_part_param { const char *name;