Skip to content

Commit

Permalink
delta: fix out-of-bounds read of delta
Browse files Browse the repository at this point in the history
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 <[email protected]>
Test-provided-by: Riccardo Schirone <[email protected]>
  • Loading branch information
pks-t committed Jun 29, 2018
1 parent 7db2587 commit 2459781
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 8 deletions.
18 changes: 10 additions & 8 deletions src/delta.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,15 +568,17 @@ int git_delta_apply(
/* cmd is a copy instruction; copy from the base. */
size_t off = 0, len = 0;

if (cmd & 0x01) off = *delta++;
if (cmd & 0x02) off |= *delta++ << 8UL;
if (cmd & 0x04) off |= *delta++ << 16UL;
if (cmd & 0x08) off |= ((unsigned) *delta++ << 24UL);

if (cmd & 0x10) len = *delta++;
if (cmd & 0x20) len |= *delta++ << 8UL;
if (cmd & 0x40) len |= *delta++ << 16UL;
#define ADD_DELTA(o, shift) { if (delta < delta_end) (o) |= ((unsigned) *delta++ << shift); else goto fail; }
if (cmd & 0x01) ADD_DELTA(off, 0UL);
if (cmd & 0x02) ADD_DELTA(off, 8UL);
if (cmd & 0x04) ADD_DELTA(off, 16UL);
if (cmd & 0x08) ADD_DELTA(off, 24UL);

if (cmd & 0x10) ADD_DELTA(len, 0UL);
if (cmd & 0x20) ADD_DELTA(len, 8UL);
if (cmd & 0x40) ADD_DELTA(len, 16UL);
if (!len) len = 0x10000;
#undef ADD_DELTA

if (base_len < off + len || res_sz < len)
goto fail;
Expand Down
9 changes: 9 additions & 0 deletions tests/delta/apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}

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)));
}

0 comments on commit 2459781

Please sign in to comment.