Small OK ping for this one.
Please test when you have some time.

----- Forwarded message from Renaud Allard <[email protected]> -----

> From: Renaud Allard <[email protected]>
> To: [email protected]
> Subject: tsort(1): heap buffer overread with embedded null bytes in input
> Date: Wed, 1 Apr 2026 08:19:51 +0200
> 
> The word parser in tsort(1) does not treat null bytes as word
> delimiters.  When input contains embedded null bytes, they become
> part of node name strings passed to ohash.
> 
> This causes a heap buffer overread in ohash_lookup_interval()
> at lib/libutil/ohash.c line 244:
> 
>   strncmp(stored_key, start, end - start) == 0 &&
>   stored_key[end-start] == '\0'
> 
> When a stored key contains an embedded null (e.g., "a\0bc", 4
> bytes), strncmp treats the null as end-of-string and returns 0
> for any lookup key sharing the same prefix (e.g., "a\0xyz", 5
> bytes).  The check stored_key[end-start] then reads past the
> stored key's allocation.
> 
> Fix: treat null bytes as word delimiters in read_pairs(), the
> same way whitespace characters are handled.  This ensures no
> node name contains embedded nulls, which is consistent with
> how ohash uses strncmp for key comparison.
> 
> Found by AFL++ fuzzing.
> 
> Index: usr.bin/tsort/tsort.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/tsort/tsort.c,v
> retrieving revision 1.38
> diff -u -p -r1.38 tsort.c
> --- usr.bin/tsort/tsort.c     18 Jan 2024 15:34:29 -0000      1.38
> +++ usr.bin/tsort/tsort.c
> @@ -318,12 +318,13 @@ read_pairs(FILE *f, struct ohash *h, int
>                       char *e;
> 
>                       while (str < sentinel &&
> -                         isspace((unsigned char)*str))
> +                         (isspace((unsigned char)*str) || *str == '\0'))
>                               str++;
>                       if (str == sentinel)
>                               break;
>                       for (e = str;
> -                         e < sentinel && !isspace((unsigned char)*e); e++)
> +                         e < sentinel && !isspace((unsigned char)*e) &&
> +                         *e != '\0'; e++)
>                               continue;
>                       if (toggle) {
>                               a = node_lookup(h, str, e);
> 

----- End forwarded message -----

Reply via email to