Skip to content

Commit a9f1ca0

Browse files
committed
smart_pkt: fix buffer overflow when parsing "ok" packets
There are two different buffer overflows present when parsing "ok" packets. First, we never verify whether the line already ends after "ok", but directly go ahead and also try to skip the expected space after "ok". Second, we then go ahead and use `strchr` to scan for the terminating newline character. But in case where the line isn't terminated correctly, this can overflow the line buffer. Fix the issues by using `git__prefixncmp` to check for the "ok " prefix and only checking for a trailing '\n' instead of using `memchr`. This also fixes the issue of us always requiring a trailing '\n'. Reported by oss-fuzz, issue 9749: Crash Type: Heap-buffer-overflow READ {*} Crash Address: 0x6310000389c0 Crash State: ok_pkt git_pkt_parse_line git_smart__store_refs Sanitizer: address (ASAN)
1 parent bc34904 commit a9f1ca0

File tree

2 files changed

+16
-16
lines changed

2 files changed

+16
-16
lines changed

src/transports/smart_pkt.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -262,21 +262,19 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len)
262262
static int ok_pkt(git_pkt **out, const char *line, size_t len)
263263
{
264264
git_pkt_ok *pkt;
265-
const char *ptr;
266265
size_t alloc_len;
267266

268267
pkt = git__malloc(sizeof(*pkt));
269268
GITERR_CHECK_ALLOC(pkt);
270-
271269
pkt->type = GIT_PKT_OK;
272270

273-
line += 3; /* skip "ok " */
274-
if (!(ptr = strchr(line, '\n'))) {
275-
giterr_set(GITERR_NET, "invalid packet line");
276-
git__free(pkt);
277-
return -1;
278-
}
279-
len = ptr - line;
271+
if (git__prefixncmp(line, len, "ok "))
272+
goto out_err;
273+
line += 3;
274+
len -= 3;
275+
276+
if (line[len - 1] == '\n')
277+
--len;
280278

281279
GITERR_CHECK_ALLOC_ADD(&alloc_len, len, 1);
282280
pkt->ref = git__malloc(alloc_len);
@@ -287,6 +285,11 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len)
287285

288286
*out = (git_pkt *)pkt;
289287
return 0;
288+
289+
out_err:
290+
giterr_set(GITERR_NET, "error parsing OK pkt-line");
291+
git__free(pkt);
292+
return -1;
290293
}
291294

292295
static int ng_pkt(git_pkt **out, const char *line, size_t len)

tests/transports/smart/packet.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -280,18 +280,15 @@ void test_transports_smart_packet__comment_pkt(void)
280280

281281
void test_transports_smart_packet__ok_pkt(void)
282282
{
283-
/*
284-
* TODO: the trailing slash is currently mandatory. Check
285-
* if we should really enforce this. As this test is part
286-
* of a security release, I feel uneasy to change
287-
* behaviour right now and leave it for a later point.
288-
*/
289283
assert_pkt_fails("0007ok\n");
284+
assert_ok_parses("0007ok ", "");
290285
assert_ok_parses("0008ok \n", "");
286+
assert_ok_parses("0008ok x", "x");
291287
assert_ok_parses("0009ok x\n", "x");
288+
assert_pkt_fails("001OK ref/foo/bar");
289+
assert_ok_parses("0012ok ref/foo/bar", "ref/foo/bar");
292290
assert_pkt_fails("0013OK ref/foo/bar\n");
293291
assert_ok_parses("0013ok ref/foo/bar\n", "ref/foo/bar");
294-
assert_ok_parses("0012ok ref/foo/bar\n", "ref/foo/bar");
295292
}
296293

297294
void test_transports_smart_packet__ng_pkt(void)

0 commit comments

Comments
 (0)