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

Re: [PATCH v2 1/7] v0 protocol: fix infinite loop when parsing multi-valued capabilities

From
Jeff King <peff@peff.net>
Date
Apr 12, 2023, 07:26 UTC
Message-ID
<20230412072622.GA1695073@coredump.intra.peff.net>
In-Reply-To
<20230412072510.GA1694877@coredump.intra.peff.net>
On Wed, Apr 12, 2023 at 03:25:10AM -0400, Jeff King wrote:
Show 8 quoted lines
> So I think it's worth fixing, and even worth beefing up the test to
> include this case, but sadly there's no specific case to check for. So I
> just rolled it into the fix in patch 1.
> 
> Here's that patch (and I'll send a range-diff in a second). The rest are
> the same, modulo a small textual conflict in patch 7 that touches a
> nearby line, but I'll refrain from re-sending the rest of them until
> I've gotten more review.
And here's the range-diff.
1:  c379efdcc0 ! 1:  3958a89100 v0 protocol: fix infinite loop when parsing multi-valued capabilities
    @@ Commit message
         feature_list only inside our function, and not the caller, that
         increment is lost next time the function is called.
     
    -    The simplest solution is to account for those skipped bytes by
    -    incrementing *offset, rather than assigning to it. (The other possible
    -    solution is to add an extra level of pointer indirection to feature_list
    -    so that the caller knows we moved it forward, but that seems more
    -    complicated).
    +    One solution would be to account for those skipped bytes by incrementing
    +    *offset, rather than assigning to it. But wait, there's more!
    +
    +    We also increment feature_list if we have a near-miss. Say we are
    +    looking for "symref" and find "almost-symref". In that case we'll point
    +    feature_list to the "y" in "almost-symref" and restart our search. But
    +    that again means our offset won't be correct, as it won't account for
    +    the bytes between the start of the string and that "y".
    +
    +    So instead, let's just record the beginning of the feature_list string
    +    in a separate pointer that we never touch. That offset we take in and
    +    return is meant to be using that point as a base, and now we'll do so
    +    consistently.
     
         Since the bug can't be reproduced using the current version of
         git-upload-pack, we'll instead hard-code an input which triggers the
    @@ Commit message
         Signed-off-by: Jeff King <peff@peff.net>
     
      ## connect.c ##
    +@@ connect.c: struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
    + 
    + const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset)
    + {
    ++	const char *orig_start = feature_list;
    + 	int len;
    + 
    + 	if (!feature_list)
     @@ connect.c: const char *parse_feature_value(const char *feature_list, const char *feature, i
      				if (lenp)
      					*lenp = 0;
      				if (offset)
     -					*offset = found + len - feature_list;
    -+					*offset += found + len - feature_list;
    ++					*offset = found + len - orig_start;
      				return value;
      			}
      			/* feature with a value (e.g., "agent=git/1.2.3") */
    @@ connect.c: const char *parse_feature_value(const char *feature_list, const char
      					*lenp = end;
      				if (offset)
     -					*offset = value + end - feature_list;
    -+					*offset += value + end - feature_list;
    ++					*offset = value + end - orig_start;
      				return value;
      			}
      			/*
    @@ t/t5512-ls-remote.sh: test_expect_success 'ls-remote prefixes work with all prot
     +	symrefs="symref=refs/remotes/origin/HEAD:refs/remotes/origin/main" &&
     +	symrefs="$symrefs symref=HEAD:refs/heads/main" &&
     +
    ++	# Likewise we want to make sure our parser is not fooled by the string
    ++	# "symref" appearing as part of an earlier cap. But there is no way to
    ++	# do that via upload-pack, as arbitrary strings can appear only in a
    ++	# "symref" value itself (where we skip past the values as a whole)
    ++	# and "agent" (which always appears after "symref", so putting our
    ++	# parser in a confused state is less interesting).
    ++	caps="some other caps including a-fake-symref-cap" &&
    ++
     +	test-tool pkt-line pack >input.q <<-EOF &&
    -+	$oid HEADQ$symrefs
    ++	$oid HEADQ$caps $symrefs
     +	$oid refs/heads/main
     +	$oid refs/remotes/origin/HEAD
     +	$oid refs/remotes/origin/main
2:  2a8e6943e5 = 2:  4cb0739770 t5512: stop referring to "v1" protocol
3:  7e411ed56b = 3:  4fe3be0476 t5512: stop using jgit for capabilities^{} test
4:  65387a02bf = 4:  77875ff7f6 t5512: add v2 support for "ls-remote --symref" test
5:  3409bd94b0 = 5:  642608ac2d t5512: allow any protocol version for filtered symref test
6:  c42a25ceca = 6:  20c78c9e41 t5512: test "ls-remote --heads --symref" filtering with v0 and v2
7:  86067753cb ! 7:  48a46fc6fc v0 protocol: use size_t for capability length/offset
    @@ connect.c: struct ref **get_remote_refs(int fd_out, struct packet_reader *reader
     -const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset)
     +const char *parse_feature_value(const char *feature_list, const char *feature, size_t *lenp, size_t *offset)
      {
    + 	const char *orig_start = feature_list;
     -	int len;
     +	size_t len;
      
Previous: Jeff KingNext: Jeff King
Message 14 of 30 in “Infinite loop + memory leak in annotate_refs_with_symref_info”
  1. Jonas HaagApr 11, 2023
  2. Taylor BlauApr 11, 2023
  3. Taylor BlauApr 11, 2023
  4. brian m. carlsonApr 12, 2023
  5. Jeff KingApr 11, 2023
  6. Jeff KingApr 11, 2023
  7. Taylor BlauApr 11, 2023
  8. Jeff KingApr 11, 2023
  9. Junio C HamanoApr 11, 2023
  10. 0/7 v0 multiple-symref infinite loop fix and test cleanupJeff King, Apr 12, 2023
  11. 1/7 v0 protocol: fix infinite loop when parsing multi-valued capabilitiesJeff King, Apr 12, 2023
  12. Jeff KingApr 12, 2023
  13. 1/7 v0 protocol: fix infinite loop when parsing multi-valued capabilitiesJeff King, Apr 12, 2023
  14. Jeff KingApr 12, 2023
  15. 2/7 t5512: stop referring to "v1" protocolJeff King, Apr 12, 2023
  16. 3/7 t5512: stop using jgit for capabilities^{} testJeff King, Apr 12, 2023
  17. Jeff KingApr 12, 2023
  18. 0/7 v0 multiple-symref infinite loop fix and test cleanupJeff King, Apr 14, 2023
  19. 1/7 v0 protocol: fix infinite loop when parsing multi-valued capabilitiesJeff King, Apr 14, 2023
  20. 2/7 t5512: stop referring to "v1" protocolJeff King, Apr 14, 2023
  21. 3/7 v0 protocol: fix sha1/sha256 confusion for capabilities^{}Jeff King, Apr 14, 2023
  22. 5/7 t5512: allow any protocol version for filtered symref testJeff King, Apr 14, 2023
  23. 4/7 t5512: add v2 support for "ls-remote --symref" testJeff King, Apr 14, 2023
  24. 6/7 t5512: test "ls-remote --heads --symref" filtering with v0 and v2Jeff King, Apr 14, 2023
  25. 7/7 v0 protocol: use size_t for capability length/offsetJeff King, Apr 14, 2023
  26. Junio C HamanoApr 17, 2023
  27. 4/7 t5512: add v2 support for "ls-remote --symref" testJeff King, Apr 12, 2023
  28. 5/7 t5512: allow any protocol version for filtered symref testJeff King, Apr 12, 2023
  29. 6/7 t5512: test "ls-remote --heads --symref" filtering with v0 and v2Jeff King, Apr 12, 2023
  30. 7/7 v0 protocol: use size_t for capability length/offsetJeff King, Apr 12, 2023

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.