git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 01/10] loose_object_info(): BUG() on inflating content with unknown type

From
Patrick Steinhardt <ps@pks.im>
Date
Feb 25, 2025, 11:42 UTC
Message-ID
<Z72sns9I-zq_KoNr@pks.im>
In-Reply-To
<20250225062824.GA1293961@coredump.intra.peff.net>
On Tue, Feb 25, 2025 at 01:28:24AM -0500, Jeff King wrote:
Show 13 quoted lines
> After unpack_loose_header() returns, it will have inflated not only the
> object header, but possibly some bytes of the object content. When we
> call unpack_loose_rest() to extract the actual content, it finds those
> extra bytes by skipping past the header's terminating NUL in the buffer.
> Like this:
> 
>   int bytes = strlen(buffer) + 1;
>   n = stream->total_out - bytes;
>   ...
>   memcpy(buf, (char *) buffer + bytes, n);
> 
> This won't work with the OBJECT_INFO_ALLOW_UNKNOWN_TYPE flag, as there
> we allow a header of arbitrary size. We put into a strbuf, but feed only
s/into/it &/
> the final 32-byte chunk we read to unpack_loose_rest(). In that case
> stream->total_out may unexpectedly large, and thus our "n" will be
s/may/& be/
Show 7 quoted lines
> large, causing an out-of-bounds read (we do check it against our
> allocated buffer size, which prevents an out-of-bounds write).
> 
> Probably this could be made to work by feeding the strbuf to
> unpack_loose_rest(), along with adjusting some types (e.g., "bytes"
> would need to be a size_t, since it is no longer operating on a 32-byte
> buffer).

I was a bit confused initially as I was thinking in terms of `size_t` and `uint32_t` as I misread 32-byte for 32-bit, which is an immediate shortcut that my brain took because 32 bit is something you read all the time. I don't really have a great idea for how to introduce the byte chunk better though to avoid this.

Show 15 quoted lines
> Signed-off-by: Jeff King <peff@peff.net>
> ---
> I found this because I was tracing the code path after
> unpack_loose_header() returns to verify some assumptions in the other
> patches.
> 
> It really makes me wonder if this "unknown type" stuff has any value
> at all. You can create an object with any type using "hash-object
> --literally -t". And you can ask about its type and size. But you can
> never retrieve the object content! Nor can you pack it or transfer it,
> since packs use a numeric type field.
> 
> This code was added ~2015, but I don't think anybody built more on top
> of it. I wonder if we should just consider it a failed experiment and
> rip out the support.

I certainly do not know and cannot think of any usecase for this. I also expect that a repository with unknown object types is a recipe for weird edge cases in case they are being read somehow.

I guess we'll know a bit more when this patch series lands? In case nobody complains it is another indicator that unknown object types aren't being used out there in the wild.

Show 16 quoted lines
>  object-file.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/object-file.c b/object-file.c
> index 00c3a4b910..45b251ba04 100644
> --- a/object-file.c
> +++ b/object-file.c
> @@ -1580,6 +1580,8 @@ static int loose_object_info(struct repository *r,
>  
>  		if (!oi->contentp)
>  			break;
> +		if (hdrbuf.len)
> +			BUG("unpacking content with unknown types not yet supported");
>  		*oi->contentp = unpack_loose_rest(&stream, hdr, *oi->sizep, oid);
>  		if (*oi->contentp)
>  			goto cleanup;

Okay. I was wondering whether we still need `hdrbuf`, but we of course do in order to continue reading the type and length itself. The only thing we restrict is reading the contents of such objects.

Patrick
Previous: Jeff KingNext: Junio C Hamano
Message 3 of 34 in “some zlib inflating bug fixes”
  1. 0/10 some zlib inflating bug fixesJeff King, Feb 25, 2025
  2. 01/10 loose_object_info(): BUG() on inflating content with unknown typeJeff King, Feb 25, 2025
  3. Patrick SteinhardtFeb 25, 2025
  4. Junio C HamanoFeb 26, 2025
  5. Taylor BlauFeb 28, 2025
  6. Jeff KingMar 4, 2025
  7. Junio C HamanoMar 4, 2025
  8. Taylor BlauFeb 28, 2025
  9. 02/10 unpack_loose_header(): simplify next_out assignmentJeff King, Feb 25, 2025
  10. Taylor BlauFeb 28, 2025
  11. 03/10 unpack_loose_header(): report headers without NUL as "bad"Jeff King, Feb 25, 2025
  12. 04/10 unpack_loose_header(): fix infinite loop on broken zlib inputJeff King, Feb 25, 2025
  13. Patrick SteinhardtFeb 25, 2025
  14. Eric SunshineFeb 25, 2025
  15. Junio C HamanoFeb 26, 2025
  16. Taylor BlauFeb 28, 2025
  17. 05/10 git_inflate(): skip zlib_post_call() sanity check on Z_NEED_DICTJeff King, Feb 25, 2025
  18. Junio C HamanoFeb 26, 2025
  19. Taylor BlauFeb 28, 2025
  20. Jeff KingMar 4, 2025
  21. 06/10 unpack_loose_header(): avoid numeric comparison of zlib statusJeff King, Feb 25, 2025
  22. Taylor BlauFeb 28, 2025
  23. Jeff KingMar 4, 2025
  24. 07/10 unpack_loose_rest(): avoid numeric comparison of zlib statusJeff King, Feb 25, 2025
  25. 08/10 unpack_loose_rest(): never clean up zstreamJeff King, Feb 25, 2025
  26. Junio C HamanoFeb 26, 2025
  27. 09/10 unpack_loose_rest(): simplify error handlingJeff King, Feb 25, 2025
  28. Junio C HamanoFeb 26, 2025
  29. Taylor BlauFeb 28, 2025
  30. 10/10 unpack_loose_rest(): rewrite return handling for clarityJeff King, Feb 25, 2025
  31. Taylor BlauFeb 28, 2025
  32. Jeff KingMar 4, 2025
  33. Taylor BlauMar 4, 2025
  34. Taylor BlauFeb 28, 2025

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.