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

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

From
Jeff King <peff@peff.net>
Date
Apr 12, 2023, 06:46 UTC
Message-ID
<20230412064651.GA1681676@coredump.intra.peff.net>
In-Reply-To
<20230412062924.GA1681312@coredump.intra.peff.net>
On Wed, Apr 12, 2023 at 02:29:24AM -0400, Jeff King wrote:
Show 13 quoted lines
> But on the second call, now *offset is set to that larger index, which
> lets us skip past the first "symref" capability. However, we do so by
> incrementing feature_list. That means our pointer difference is now too
> small; it is counting from where we resumed parsing, not from the start
> of the original feature_list pointer. And because we incremented
> 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).

Hmph. So after convincing myself that was the end of it, now I'm not so sure. We also increment feature_list if we find a false positive in the middle of another entry. I.e., the code even after this patch looks like:

          while (*feature_list) {
                  const char *found = strstr(feature_list, feature);
                  if (!found)
                          return NULL;
                  if (feature_list == found || isspace(found[-1])) {
                          const char *value = found + len;
                          /* feature with no value (e.g., "thin-pack") */
                          if (!*value || isspace(*value)) {
                                  if (lenp)
                                          *lenp = 0;
                                  if (offset)
                                          *offset += found + len - feature_list;
                                  return value;
                          }
                          /* feature with a value (e.g., "agent=git/1.2.3") */
                          else if (*value == '=') {
                                  size_t end;
  
                                  value++;
                                  end = strcspn(value, " \t\n");
                                  if (lenp)
                                          *lenp = end;
                                  if (offset)
                                          *offset += value + end - feature_list;
                                  return value;
                          }
                          /*
                           * otherwise we matched a substring of another feature;
                           * keep looking
                           */
                  }
                  feature_list = found + 1;
          }
          return NULL;
So if we have something like:
   agent=i-like-symrefs symref=HEAD:refs/heads/foo

then we'd find the "symref" value in the agent line, increment feature_list, and then find the real one. But our pointer difference will again be too short! And incrementing "offset" rather than assigning it won't help, because those skipped bytes are not accounted for in the existing value of "offset".

So what we probably want is a third possibility I didn't allow for: keep the original value of feature_list intact, and use a separate pointer to increment. And then assigning "*offset = value + end - feature_list" will always be correct, because the offset will always be from the original, true beginning of the string.

The fix is easy, but let me see if I can come up with a test.
-Peff
Previous: Jeff KingNext: Jeff King
Message 12 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.