Commit 9844d38b by Patrick Steinhardt

delta: fix out-of-bounds read of delta

When computing the offset and length of the delta base, we repeatedly
increment the `delta` pointer without checking whether we have advanced
past its end already, which can thus result in an out-of-bounds read.
Fix this by repeatedly checking whether we have reached the end. Add a
test which would cause Valgrind to produce an error.

Reported-by: Riccardo Schirone <rschiron@redhat.com>
Test-provided-by: Riccardo Schirone <rschiron@redhat.com>
parent 3f461902
...@@ -568,15 +568,17 @@ int git_delta_apply( ...@@ -568,15 +568,17 @@ int git_delta_apply(
/* cmd is a copy instruction; copy from the base. */ /* cmd is a copy instruction; copy from the base. */
size_t off = 0, len = 0; size_t off = 0, len = 0;
if (cmd & 0x01) off = *delta++; #define ADD_DELTA(o, shift) { if (delta < delta_end) (o) |= ((unsigned) *delta++ << shift); else goto fail; }
if (cmd & 0x02) off |= *delta++ << 8UL; if (cmd & 0x01) ADD_DELTA(off, 0UL);
if (cmd & 0x04) off |= *delta++ << 16UL; if (cmd & 0x02) ADD_DELTA(off, 8UL);
if (cmd & 0x08) off |= ((unsigned) *delta++ << 24UL); if (cmd & 0x04) ADD_DELTA(off, 16UL);
if (cmd & 0x08) ADD_DELTA(off, 24UL);
if (cmd & 0x10) len = *delta++;
if (cmd & 0x20) len |= *delta++ << 8UL; if (cmd & 0x10) ADD_DELTA(len, 0UL);
if (cmd & 0x40) len |= *delta++ << 16UL; if (cmd & 0x20) ADD_DELTA(len, 8UL);
if (cmd & 0x40) ADD_DELTA(len, 16UL);
if (!len) len = 0x10000; if (!len) len = 0x10000;
#undef ADD_DELTA
if (base_len < off + len || res_sz < len) if (base_len < off + len || res_sz < len)
goto fail; goto fail;
......
...@@ -10,3 +10,12 @@ void test_delta_apply__read_at_off(void) ...@@ -10,3 +10,12 @@ void test_delta_apply__read_at_off(void)
cl_git_fail(git_delta_apply(&out, &outlen, base, sizeof(base), delta, sizeof(delta))); cl_git_fail(git_delta_apply(&out, &outlen, base, sizeof(base), delta, sizeof(delta)));
} }
void test_delta_apply__read_after_limit(void)
{
unsigned char base[16] = { 0 }, delta[] = { 0x10, 0x70, 0xff };
void *out;
size_t outlen;
cl_git_fail(git_delta_apply(&out, &outlen, base, sizeof(base), delta, sizeof(delta)));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment