summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff King <peff@peff.net>2013-02-20 15:00:28 -0500
committerJunio C Hamano <gitster@pobox.com>2013-02-20 13:42:21 -0800
commit030e9dd64f931c0ccfb6ad4be88775f8272f02eb (patch)
treecab44ffa6e1162b6d00c3dfd1eea5b3a3fc6b76e
parent97a83fa839d818130bfeca060279c4c355036785 (diff)
downloadgit-030e9dd64f931c0ccfb6ad4be88775f8272f02eb.tar.gz
fetch-pack: fix out-of-bounds buffer offset in get_ack
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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--fetch-pack.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/fetch-pack.c b/fetch-pack.c
index 6d8926a550..27a3e80364 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"))