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

[PATCH v3 04/19] fetch-pack: fix out-of-bounds buffer offset in get_ack

From
Jeff King <peff@peff.net>
Date
Feb 20, 2013, 20:00 UTC
Message-ID
<20130220200028.GD25647@sigill.intra.peff.net>
In-Reply-To
<20130220195147.GA25332@sigill.intra.peff.net>
When we read acks from the remote, we expect either:
  ACK <sha1>
or
  ACK <sha1> <multi-ack-flag>

We parse the "ACK <sha1>" bit from the line, and then start looking for the flag strings at "line+45"; if we don't have them, we assume it's of the first type. But if we do have the first type, then line+45 is not necessarily inside our string at all!

It turns out that this works most of the time due to the way we parse the packets. They should come in with a newline, and packet_read puts an extra NUL into the buffer, so we end up with:

  ACK <sha1>\n\0

with the newline at offset 44 and the NUL at offset 45. We then strip the newline, putting a NUL at offset 44. So when we look at "line+45", we are looking past the end of our string; but it's OK, because we hit the terminator from the original string.

This breaks down, however, if the other side does not terminate their packets with a newline. In that case, our packet is one character shorter, and we start looking through uninitialized memory for the flag. No known implementation sends such a packet, so it has never come up in practice.

This patch tightens the check by looking for a short, flagless ACK before trying to parse the flag.

Signed-off-by: Jeff King <peff@peff.net>
---
This is the absolute minimal fix, which just checks for the no-flag case
early; we still treat arbitrary crud in the flag field as just an ACK.
From my understanding of the protocol, a saner parsing scheme would be:
  const char *flag = line + 44; /* we already parsed "ACK <sha1>" */
  if (!*flag)
          return ACK;
  if (!strcmp(flag, " continue"))
          return ACK_continue;
  if (!strcmp(flag, " common"))
          return ACK_continue;
  if (!strcmp(flag, " ready"))
          return ACK_ready;
  die("fetch-pack expected multi-ack flag, got: %s", line);

But that is much tighter, and I wasn't sure if the looseness was there to facilitate future expansion or something (though I'd think we would need a new capability for that).

 fetch-pack.c | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/fetch-pack.c b/fetch-pack.c
index 6d8926a..27a3e80 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -226,6 +226,8 @@ static enum ack_type get_ack(int fd, unsigned char *result_sha1)
 		return NAK;
 	if (!prefixcmp(line, "ACK ")) {
 		if (!get_sha1_hex(line+4, result_sha1)) {
+			if (len < 45)
+				return ACK;
 			if (strstr(line+45, "continue"))
 				return ACK_continue;
 			if (strstr(line+45, "common"))
-- 
1.8.2.rc0.9.g352092c
Previous: Jeff KingNext: Jeff King
Message 5 of 40 in “[PATCHv3 0/19] pkt-line cleanups and fixes”
  1. Jeff KingFeb 20, 2013
  2. 01/19 upload-pack: use get_sha1_hex to parse "shallow" linesJeff King, Feb 20, 2013
  3. 02/19 upload-pack: do not add duplicate objects to shallow listJeff King, Feb 20, 2013
  4. 03/19 upload-pack: remove packet debugging harnessJeff King, Feb 20, 2013
  5. 04/19 fetch-pack: fix out-of-bounds buffer offset in get_ackJeff King, Feb 20, 2013
  6. 05/19 send-pack: prefer prefixcmp over memcmp in receive_statusJeff King, Feb 20, 2013
  7. 06/19 upload-archive: do not copy repo nameJeff King, Feb 20, 2013
  8. 07/19 upload-archive: use argv_array to store client argumentsJeff King, Feb 20, 2013
  9. 08/19 write_or_die: raise SIGPIPE when we get EPIPEJeff King, Feb 20, 2013
  10. Jonathan NiederFeb 20, 2013
  11. Jeff KingFeb 20, 2013
  12. Jonathan NiederFeb 20, 2013
  13. Jeff KingFeb 20, 2013
  14. Jonathan NiederFeb 20, 2013
  15. Jeff KingFeb 20, 2013
  16. Junio C HamanoFeb 20, 2013
  17. [BUG] MSVC: error box when interrupting `gitlog` by quitting lessMarat Radchenko, Mar 28, 2014
  18. Marat RadchenkoMar 28, 2014
  19. Jeff KingMar 28, 2014
  20. Marat RadchenkoMar 28, 2014
  21. Jeff KingMar 28, 2014
  22. Johannes SixtMar 28, 2014
  23. MSVC: link in invalidcontinue.obj for better POSIX compatibilityMarat Radchenko, Mar 28, 2014
  24. Junio C HamanoMar 28, 2014
  25. Marat RadchenkoMar 28, 2014
  26. Junio C HamanoMar 28, 2014
  27. MSVC: link in invalidcontinue.obj for better POSIX compatibilityMarat Radchenko, Mar 28, 2014
  28. Junio C HamanoMar 28, 2014
  29. 09/19 pkt-line: move a misplaced commentJeff King, Feb 20, 2013
  30. 10/19 pkt-line: drop safe_write functionJeff King, Feb 20, 2013
  31. 11/19 pkt-line: provide a generic reading function with optionsJeff King, Feb 20, 2013
  32. 12/19 pkt-line: teach packet_read_line to chomp newlinesJeff King, Feb 20, 2013
  33. 13/19 pkt-line: move LARGE_PACKET_MAX definition from sidebandJeff King, Feb 20, 2013
  34. 14/19 pkt-line: provide a LARGE_PACKET_MAX static bufferJeff King, Feb 20, 2013
  35. 15/19 pkt-line: share buffer/descriptor reading implementationJeff King, Feb 20, 2013
  36. Eric SunshineFeb 22, 2013
  37. 16/19 teach get_remote_heads to read from a memory bufferJeff King, Feb 20, 2013
  38. 17/19 remote-curl: pass buffer straight to get_remote_headsJeff King, Feb 20, 2013
  39. 18/19 remote-curl: move ref-parsing code up in fileJeff King, Feb 20, 2013
  40. 19/19 remote-curl: always parse incoming refsJeff King, Feb 20, 2013

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.