diff options
author | Junio C Hamano <gitster@pobox.com> | 2016-10-11 14:21:03 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2016-10-11 14:21:03 -0700 |
commit | f7f0a87e0a27a1baaf782af7cec18fd23fdf35de (patch) | |
tree | 7985c724684b4224e762e788fdb8c85752d0e83a | |
parent | Merge branch 'rs/git-gui-use-modern-git-merge-syntax' into maint (diff) | |
parent | unpack_sha1_header(): detect malformed object header (diff) | |
download | tgif-f7f0a87e0a27a1baaf782af7cec18fd23fdf35de.tar.xz |
Merge branch 'jc/verify-loose-object-header' into maint
Codepaths that read from an on-disk loose object were too loose in
validating what they are reading is a proper object file and
sometimes read past the data they read from the disk, which has
been corrected. H/t to Gustavo Grieco for reporting.
* jc/verify-loose-object-header:
unpack_sha1_header(): detect malformed object header
streaming: make sure to notice corrupt object
-rw-r--r-- | sha1_file.c | 26 | ||||
-rw-r--r-- | streaming.c | 12 |
2 files changed, 30 insertions, 8 deletions
diff --git a/sha1_file.c b/sha1_file.c index 3045aeabda..7a4f8f8661 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1572,7 +1572,9 @@ unsigned long unpack_object_header_buffer(const unsigned char *buf, return used; } -int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz) +static int unpack_sha1_short_header(git_zstream *stream, + unsigned char *map, unsigned long mapsize, + void *buffer, unsigned long bufsiz) { /* Get the data stream */ memset(stream, 0, sizeof(*stream)); @@ -1585,13 +1587,31 @@ int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long ma return git_inflate(stream, 0); } +int unpack_sha1_header(git_zstream *stream, + unsigned char *map, unsigned long mapsize, + void *buffer, unsigned long bufsiz) +{ + int status = unpack_sha1_short_header(stream, map, mapsize, + buffer, bufsiz); + + if (status < Z_OK) + return status; + + /* Make sure we have the terminating NUL */ + if (!memchr(buffer, '\0', stream->next_out - (unsigned char *)buffer)) + return -1; + return 0; +} + static int unpack_sha1_header_to_strbuf(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz, struct strbuf *header) { int status; - status = unpack_sha1_header(stream, map, mapsize, buffer, bufsiz); + status = unpack_sha1_short_header(stream, map, mapsize, buffer, bufsiz); + if (status < Z_OK) + return -1; /* * Check if entire header is unpacked in the first iteration. @@ -1682,6 +1702,8 @@ static int parse_sha1_header_extended(const char *hdr, struct object_info *oi, */ for (;;) { char c = *hdr++; + if (!c) + return -1; if (c == ' ') break; type_len++; diff --git a/streaming.c b/streaming.c index 811fcc24d2..90feec9db6 100644 --- a/streaming.c +++ b/streaming.c @@ -337,17 +337,17 @@ static open_method_decl(loose) st->u.loose.mapped = map_sha1_file(sha1, &st->u.loose.mapsize); if (!st->u.loose.mapped) return -1; - if (unpack_sha1_header(&st->z, - st->u.loose.mapped, - st->u.loose.mapsize, - st->u.loose.hdr, - sizeof(st->u.loose.hdr)) < 0) { + if ((unpack_sha1_header(&st->z, + st->u.loose.mapped, + st->u.loose.mapsize, + st->u.loose.hdr, + sizeof(st->u.loose.hdr)) < 0) || + (parse_sha1_header(st->u.loose.hdr, &st->size) < 0)) { git_inflate_end(&st->z); munmap(st->u.loose.mapped, st->u.loose.mapsize); return -1; } - parse_sha1_header(st->u.loose.hdr, &st->size); st->u.loose.hdr_used = strlen(st->u.loose.hdr) + 1; st->u.loose.hdr_avail = st->z.total_out; st->z_state = z_used; |