Hi Kevin,
> Date: 2026-09-22 11:12:12+0800
> From: "Kevin J. McCarthy" <[email protected]>
>
> The leak was triggered in mutt_make_message_attach() with
> $mime_forward set and $allow_8bit unset, on an attachment with 8-bit
> characters. However, it probably occurred in other situations too.
>
> mutt_make_message_attach() indirectly chains down to
> mutt_message_to_7bit(), which calls the originator of the leak:
> _parse_messageRFC822(). That function overwrites parent->hdr with a
> newly allocated header.
>
> At first I tried to "fix" the problem in that function, but it turns
> out to be difficult to do given the wide variety of callers and
> state of the data structures. Some callers pass a header with
> content set, and other times it's not set.
>
> After further research I discovered other callers of the
> mutt_parse_(part/multipart/messageRFC822) set of functions take care
> to save a top level header and restore it. (Which also made solving
> the leak inside _parse_messageRFC822() difficult.)
>
> After more research I decided the right place to fix was
> mutt_message_to_7bit(): the caller of mutt_parse_messageRFC822() in
> this case.
>
> Since this is a generic function used in different circumstances, I
> made no assumptions about whether a->hdr exists. If so, I save and
> restore it.
>
> The original function frees the a->hdr->content (or a->parts), so I
> kept the same logic.
> ---
> sendlib.c | 15 +++++++++++++--
> 1 file changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/sendlib.c b/sendlib.c
> index dbd3eabe..db73eaf1 100644
> --- a/sendlib.c
> +++ b/sendlib.c
> @@ -1108,6 +1108,7 @@ void mutt_message_to_7bit(BODY *a, FILE *fp)
> FILE *fpin = NULL;
> FILE *fpout = NULL;
> struct stat sb;
> + HEADER *saved_hdr = NULL;
>
> if (!a->filename && fp)
> fpin = fp;
> @@ -1138,6 +1139,10 @@ void mutt_message_to_7bit(BODY *a, FILE *fp)
> }
>
> fseeko(fpin, a->offset, SEEK_SET);
> + /* Note: mutt_parse_messageRFC822() overwrites a->hdr, so it needs to
> + * saved and restored below.
needs to _be_ saved. :)
> + */
> + saved_hdr = a->hdr;
> a->parts = mutt_parse_messageRFC822(fpin, a);
>
> transform_to_7bit(a->parts, fpin);
> @@ -1167,8 +1172,14 @@ void mutt_message_to_7bit(BODY *a, FILE *fp)
> goto cleanup;
> }
> a->length = sb.st_size;
> - mutt_free_body(&a->parts);
> - a->hdr->content = NULL;
> +
> + if (saved_hdr)
> + {
> + mutt_free_header(&a->hdr);
> + a->hdr = saved_hdr;
> + }
> + mutt_free_body(&a->hdr->content);
> + a->parts = NULL;
Have a lovely day!
Alex
>
> cleanup:
> if (fpin && fpin != fp)
> --
> 2.55.0
>
--
<https://www.alejandro-colomar.es>