diff options
author | Patrick Steinhardt <ps@pks.im> | 2018-08-09 11:01:00 +0200 |
---|---|---|
committer | Patrick Steinhardt <ps@pks.im> | 2018-10-03 16:09:02 +0200 |
commit | a9f1ca09178af0640963e069a2142d5ced53f0b4 (patch) | |
tree | 113ea5c507dac921f35d6e329d356ce5c2b954f5 | |
parent | bc349045b1be8fb3af2b02d8554483869e54d5b8 (diff) | |
download | libgit2-a9f1ca09178af0640963e069a2142d5ced53f0b4.tar.gz |
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)
-rw-r--r-- | src/transports/smart_pkt.c | 21 | ||||
-rw-r--r-- | tests/transports/smart/packet.c | 11 |
2 files changed, 16 insertions, 16 deletions
diff --git a/src/transports/smart_pkt.c b/src/transports/smart_pkt.c index 91a709e38..1066bc3e1 100644 --- a/src/transports/smart_pkt.c +++ b/src/transports/smart_pkt.c @@ -262,21 +262,19 @@ out_err: static int ok_pkt(git_pkt **out, const char *line, size_t len) { git_pkt_ok *pkt; - const char *ptr; size_t alloc_len; pkt = git__malloc(sizeof(*pkt)); GITERR_CHECK_ALLOC(pkt); - pkt->type = GIT_PKT_OK; - line += 3; /* skip "ok " */ - if (!(ptr = strchr(line, '\n'))) { - giterr_set(GITERR_NET, "invalid packet line"); - git__free(pkt); - return -1; - } - len = ptr - line; + if (git__prefixncmp(line, len, "ok ")) + goto out_err; + line += 3; + len -= 3; + + if (line[len - 1] == '\n') + --len; GITERR_CHECK_ALLOC_ADD(&alloc_len, len, 1); pkt->ref = git__malloc(alloc_len); @@ -287,6 +285,11 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len) *out = (git_pkt *)pkt; return 0; + +out_err: + giterr_set(GITERR_NET, "error parsing OK pkt-line"); + git__free(pkt); + return -1; } static int ng_pkt(git_pkt **out, const char *line, size_t len) diff --git a/tests/transports/smart/packet.c b/tests/transports/smart/packet.c index 8bbb0bbcf..f887563f3 100644 --- a/tests/transports/smart/packet.c +++ b/tests/transports/smart/packet.c @@ -280,18 +280,15 @@ void test_transports_smart_packet__comment_pkt(void) void test_transports_smart_packet__ok_pkt(void) { - /* - * TODO: the trailing slash is currently mandatory. Check - * if we should really enforce this. As this test is part - * of a security release, I feel uneasy to change - * behaviour right now and leave it for a later point. - */ assert_pkt_fails("0007ok\n"); + assert_ok_parses("0007ok ", ""); assert_ok_parses("0008ok \n", ""); + assert_ok_parses("0008ok x", "x"); assert_ok_parses("0009ok x\n", "x"); + assert_pkt_fails("001OK ref/foo/bar"); + assert_ok_parses("0012ok ref/foo/bar", "ref/foo/bar"); assert_pkt_fails("0013OK ref/foo/bar\n"); assert_ok_parses("0013ok ref/foo/bar\n", "ref/foo/bar"); - assert_ok_parses("0012ok ref/foo/bar\n", "ref/foo/bar"); } void test_transports_smart_packet__ng_pkt(void) |