summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlhchavez <lhchavez@lhchavez.com>2022-04-05 13:10:33 -0700
committerEdward Thomson <ethomson@edwardthomson.com>2022-04-12 14:17:24 -0400
commitc93609120a76dcd25369dca4be69dbca7dfdaff7 (patch)
treebf845d3c6a93be76f6d0db5d544d5ed5b84d1aa8
parent99336fe3dd3cefc16085955d617cc31dcd5a112b (diff)
downloadlibgit2-c93609120a76dcd25369dca4be69dbca7dfdaff7.tar.gz
[midx] Fix an undefined behavior (left-shift signed overflow)
There was a missing check to ensure that the `off64_t` (which is a signed value) didn't overflow when parsing it from the midx file. This shouldn't have huge repercusions since the parsed value is immediately validated afterwards, but then again, there is no such thing as "benign" undefined behavior. This change makes all the bitwise arithmetic happen with unsigned types and is only casted to `off64_t` until the very end. Thanks to Taotao Gu for finding and reporting this!
-rw-r--r--fuzzers/corpora/midx/666a779eed16847c6930a71c0547a34e52db409ebin0 -> 62 bytes
-rw-r--r--src/midx.c11
2 files changed, 8 insertions, 3 deletions
diff --git a/fuzzers/corpora/midx/666a779eed16847c6930a71c0547a34e52db409e b/fuzzers/corpora/midx/666a779eed16847c6930a71c0547a34e52db409e
new file mode 100644
index 000000000..ed9e0d07a
--- /dev/null
+++ b/fuzzers/corpora/midx/666a779eed16847c6930a71c0547a34e52db409e
Binary files differ
diff --git a/src/midx.c b/src/midx.c
index eb99e7373..0092601f6 100644
--- a/src/midx.c
+++ b/src/midx.c
@@ -225,8 +225,13 @@ int git_midx_parse(
chunk_hdr = data + sizeof(struct git_midx_header);
last_chunk = NULL;
for (i = 0; i < hdr->chunks; ++i, chunk_hdr += 12) {
- chunk_offset = ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) << 32 |
- ((off64_t)ntohl(*((uint32_t *)(chunk_hdr + 8))));
+ uint32_t chunk_id = ntohl(*((uint32_t *)(chunk_hdr + 0)));
+ uint64_t high_offset = ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 4)))) & 0xffffffffu;
+ uint64_t low_offset = ((uint64_t)ntohl(*((uint32_t *)(chunk_hdr + 8)))) & 0xffffffffu;
+
+ if (high_offset >= INT32_MAX)
+ return midx_error("chunk offset out of range");
+ chunk_offset = (off64_t)(high_offset << 32 | low_offset);
if (chunk_offset < last_chunk_offset)
return midx_error("chunks are non-monotonic");
if (chunk_offset >= trailer_offset)
@@ -235,7 +240,7 @@ int git_midx_parse(
last_chunk->length = (size_t)(chunk_offset - last_chunk_offset);
last_chunk_offset = chunk_offset;
- switch (ntohl(*((uint32_t *)(chunk_hdr + 0)))) {
+ switch (chunk_id) {
case MIDX_PACKFILE_NAMES_ID:
chunk_packfile_names.offset = last_chunk_offset;
last_chunk = &chunk_packfile_names;