Skip to content

libFuzzer: Prevent a potential shift overflow - #4435

Merged
ethomson merged 3 commits into
libgit2:masterfrom
lhchavez:ubsan-shift-overflow
Dec 23, 2017
Merged

libFuzzer: Prevent a potential shift overflow#4435
ethomson merged 3 commits into
libgit2:masterfrom
lhchavez:ubsan-shift-overflow

Conversation

@lhchavez

@lhchavez lhchavez commented Dec 8, 2017

Copy link
Copy Markdown
Contributor

The type of |base_offset| in get_delta_base() is git_off_t, which is a
signed long. That means that we need to make sure that the 8 most
significant bits are zero (instead of 7) to avoid an overflow when it is
shifted by 7 bits.

Found using libFuzzer.

The type of |base_offset| in get_delta_base() is `git_off_t`, which is a
signed `long`. That means that we need to make sure that the 8 most
significant bits are zero (instead of 7) to avoid an overflow when it is
shifted by 7 bits.

Found using libFuzzer.
@lhchavez

lhchavez commented Dec 8, 2017

Copy link
Copy Markdown
Contributor Author

PTAL.

This one I'm not 100% sure this is the right fix. The other option being using an unsigned long to store the intermediate computation.

@lhchavez

lhchavez commented Dec 8, 2017

Copy link
Copy Markdown
Contributor Author

ugh, ubsan also complains about the base_offset + 1. will wait for comments, since making the type unsigned would also get rid of that (since signed overflow is defined behavior).

Comment thread src/pack.c
if (left <= used)
return GIT_EBUFS;
base_offset += 1;
if (!base_offset || MSB(base_offset, 7))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, it looks like the author of this code already assumed base_offset being unsigned. Otherwise base_offset += 1; if (!base_offset) /* Overflow */; wouldn't make any sense at all. So I think using size_t instead and then having a check whether its value is greater than the maximum value for git_off_t should be good.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using size_t now.

Comment thread src/pack.c Outdated
if ((size_t)delta_obj_offset <= unsigned_base_offset)
return 0; /* out of bound */
base_offset = delta_obj_offset - unsigned_base_offset;
if (base_offset >= delta_obj_offset)

@pks-t pks-t Dec 15, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can only be true iff unsinged_base_offset equals 0:

base_offset >= delta_obj_offset
<=> delta_obj_offset - unsigned_base_offset >= delta_obj_offset

The above could only be true iff unsinged_base_offset is greater than delta_obj_offset or 0, where the first case was filtered out in line 947 and the second case shouldn't ever happen. So you could just reformulate this condition as unsinged_base_offset == 0.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread src/pack.c
}
base_offset = delta_obj_offset - base_offset;
if (base_offset <= 0 || base_offset >= delta_obj_offset)
if (unsigned_base_offset == 0 || (size_t)delta_obj_offset <= unsigned_base_offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can delta_obj_offset ever be negative?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A cursory glance through the code suggests that the answer to this question is no. But along those lines, should we really return 0 here or should we raise an error in the out-of-bound case?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, 0 is an error, but seems to only be checked occasionally. 😢

@ethomson

Copy link
Copy Markdown
Member

Thanks for doing this - this appears to be an improvement.

@ethomson
ethomson merged commit 30d9176 into libgit2:master Dec 23, 2017
@pks-t pks-t added the backport label Jan 11, 2018
@pks-t pks-t mentioned this pull request Jan 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants