Skip to content

Commit bc34904

Browse files
committed
smart_pkt: fix buffer overflow when parsing "ACK" packets
We are being quite lenient when parsing "ACK" packets. First, we didn't correctly verify that we're not overrunning the provided buffer length, which we fix here by using `git__prefixncmp` instead of `git__prefixcmp`. Second, we do not verify that the actual contents make any sense at all, as we simply ignore errors when parsing the ACKs OID and any unknown status strings. This may result in a parsed packet structure with invalid contents, which is being silently passed to the caller. This is being fixed by performing proper input validation and checking of return codes.
1 parent 5edcf5d commit bc34904

File tree

2 files changed

+34
-30
lines changed

2 files changed

+34
-30
lines changed

src/transports/smart_pkt.c

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,34 +43,43 @@ static int flush_pkt(git_pkt **out)
4343
static int ack_pkt(git_pkt **out, const char *line, size_t len)
4444
{
4545
git_pkt_ack *pkt;
46-
GIT_UNUSED(line);
47-
GIT_UNUSED(len);
4846

4947
pkt = git__calloc(1, sizeof(git_pkt_ack));
5048
GITERR_CHECK_ALLOC(pkt);
51-
5249
pkt->type = GIT_PKT_ACK;
53-
line += 3;
54-
len -= 3;
5550

56-
if (len >= GIT_OID_HEXSZ) {
57-
git_oid_fromstr(&pkt->oid, line + 1);
58-
line += GIT_OID_HEXSZ + 1;
59-
len -= GIT_OID_HEXSZ + 1;
60-
}
51+
if (git__prefixncmp(line, len, "ACK "))
52+
goto out_err;
53+
line += 4;
54+
len -= 4;
6155

62-
if (len >= 7) {
63-
if (!git__prefixcmp(line + 1, "continue"))
56+
if (len < GIT_OID_HEXSZ || git_oid_fromstr(&pkt->oid, line) < 0)
57+
goto out_err;
58+
line += GIT_OID_HEXSZ;
59+
len -= GIT_OID_HEXSZ;
60+
61+
if (len && line[0] == ' ') {
62+
line++;
63+
len--;
64+
65+
if (!git__prefixncmp(line, len, "continue"))
6466
pkt->status = GIT_ACK_CONTINUE;
65-
if (!git__prefixcmp(line + 1, "common"))
67+
else if (!git__prefixncmp(line, len, "common"))
6668
pkt->status = GIT_ACK_COMMON;
67-
if (!git__prefixcmp(line + 1, "ready"))
69+
else if (!git__prefixncmp(line, len, "ready"))
6870
pkt->status = GIT_ACK_READY;
71+
else
72+
goto out_err;
6973
}
7074

7175
*out = (git_pkt *) pkt;
7276

7377
return 0;
78+
79+
out_err:
80+
giterr_set(GITERR_NET, "error parsing ACK pkt-line");
81+
git__free(pkt);
82+
return -1;
7483
}
7584

7685
static int nak_pkt(git_pkt **out)

tests/transports/smart/packet.c

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -236,25 +236,20 @@ void test_transports_smart_packet__ack_pkt(void)
236236
"0000000000000000000000000000000000000000",
237237
GIT_ACK_READY);
238238

239-
/* TODO: these should fail as they don't have OIDs */
240-
assert_ack_parses("0007ACK", "0000000000000000000000000000000000000000", 0);
241-
assert_ack_parses("0008ACK ", "0000000000000000000000000000000000000000", 0);
239+
/* these should fail as they don't have OIDs */
240+
assert_pkt_fails("0007ACK");
241+
assert_pkt_fails("0008ACK ");
242242

243-
/* TODO: this one is missing a space and should thus fail */
244-
assert_ack_parses("0036ACK00000000000000000x0000000000000000000000 ready",
245-
"0000000000000000000000000000000000000000", 0);
243+
/* this one is missing a space and should thus fail */
244+
assert_pkt_fails("0036ACK00000000000000000x0000000000000000000000 ready");
246245

247-
/* TODO: the following ones have invalid OIDs and should thus fail */
248-
assert_ack_parses("0037ACK 00000000000000000x0000000000000000000000 ready",
249-
"0000000000000000000000000000000000000000", GIT_ACK_READY);
250-
assert_ack_parses("0036ACK 000000000000000000000000000000000000000 ready",
251-
"0000000000000000000000000000000000000000", 0);
252-
assert_ack_parses("0036ACK 00000000000000000x0000000000000000000000ready",
253-
"0000000000000000000000000000000000000000", 0);
246+
/* the following ones have invalid OIDs and should thus fail */
247+
assert_pkt_fails("0037ACK 00000000000000000x0000000000000000000000 ready");
248+
assert_pkt_fails("0036ACK 000000000000000000000000000000000000000 ready");
249+
assert_pkt_fails("0036ACK 00000000000000000x0000000000000000000000ready");
254250

255-
/* TODO: this one has an invalid status and should thus fail */
256-
assert_ack_parses("0036ACK 0000000000000000000000000000000000000000 read",
257-
"0000000000000000000000000000000000000000", 0);
251+
/* this one has an invalid status and should thus fail */
252+
assert_pkt_fails("0036ACK 0000000000000000000000000000000000000000 read");
258253
}
259254

260255
void test_transports_smart_packet__nak_pkt(void)

0 commit comments

Comments
 (0)