-
Notifications
You must be signed in to change notification settings - Fork 278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extra checking to prevent loop counter from wrapping around #1766
Extra checking to prevent loop counter from wrapping around #1766
Conversation
blockIndex--; | ||
blockSize = (long)p_->blocksMap_[blockIndex].getSize(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, this code doesn't seem to be covered by any of our tests. But I am pretty sure that if this loop doesn't terminate early then, on the final iteration of the loop, this array access will attempt to access blocksMap_[-1]
. Since all this code is doing is preloading blockSize
for the next iteration, it is better to just load it at the beginning of the loop.
for (int i = 0; i < pos->count(); ++i) { | ||
for (long i = 0; i < pos->count(); ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (unsigned i = 0; i < value.length(); ++i) { | ||
for (size_t i = 0; i < value.length(); ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value
is a std::string
, so size_t
is a better choice for the type of i
.
const uint32_t component_size = ciffComponent.size(); | ||
enforce(component_size % 2 == 0, kerCorruptedMetadata); | ||
enforce(component_size/2 <= static_cast<uint32_t>(std::numeric_limits<uint16_t>::max()), kerCorruptedMetadata); | ||
const uint16_t num_components = static_cast<uint16_t>(component_size/2); | ||
uint16_t c = 1; | ||
while (uint32_t(c)*2 < ciffComponent.size()) { | ||
while (c < num_components) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the fix for GHSA-hqjh-hpv8-8r9p
The value of ciffComponent.size()
is bounds-checked before the start of the loop and the correct number of iterations is precomputed.
if (ifdId == canonCsId && c == 23 && ciffComponent.size() > 50) n = 3; | ||
if (ifdId == canonCsId && c == 23 && component_size >= 52) n = 3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The number 50 looks wrong to me. If c == 23
and n == 3
then the read
below will read the 6 bytes starting at offset 46. Therefore the size needs to be at least 52.
for (unsigned int i = 0; i < input.length(); ++i) { | ||
for (size_t i = 0; i < input.length(); ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
input
is a std::string
, so size_t
is a better type for i
.
if (input.length() - 4 > i) { | ||
if (input.length() >= 4 && input.length() - 4 > i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure that input.length() - 4
cannot overflow.
src/iptc.cpp
Outdated
uint32_t i = 0; | ||
while (i < bytes.size() - 3 && bytes.at(i) != 0x1c) | ||
size_t i = 0; | ||
while (i + 3 < bytes.size() && bytes.at(i) != 0x1c) | ||
i++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The subtraction bytes.size() - 3
could overflow. i + 3
cannot, because i
is initially 0 and only incremented by 1 on each loop iteration.
src/iptc.cpp
Outdated
while (i < bytes.size() - 3) { | ||
while (i + 3 < bytes.size()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. I just realized that my logic that i + 3
cannot overflow doesn't work here because i
is incremented with a +=
in this loop. I'll add another commit to fix it.
for (uint16_t i = 0; i < value.count(); i++ ) { // for each element in value array | ||
long count = value.count(); | ||
enforce(0 <= count && count <= std::numeric_limits<uint16_t>::max(), kerCorruptedMetadata); | ||
for (uint16_t i = 0; i < count; i++ ) { // for each element in value array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure that value.count()
doesn't exceed the range of a uint16_t
.
for (unsigned int i = 0; i < stringValue.length(); ++i) { | ||
for (size_t i = 0; i < stringValue.length(); ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stringValue
is a std::string
, so size_t
is a better choice for i
.
for ( int16_t k = 0 ; k < records[i].size ; k++ ) s << " " << ints.at(nStart++); | ||
for ( uint16_t k = 0 ; k < records[i].size ; k++ ) s << " " << ints.at(nStart++); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type of records[i].size
is uint16_t
, so uint16_t
is a better choice for k
.
size_t i = 0; | ||
while (i < bytes.size() - 3 && bytes.at(i) != 0x1c) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type of bytes.size()
is size_t
, so size_t
is a better choice for i
.
if (bytes.size() < 3) { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent integer overflow in bytes.size() - 3
below.
I used two CodeQL queries to find loop conditions similar to the original bug. Both queries have quite a few false positives, so I ignored some of the results. The first query looks for loop conditions of the form
The second query looks for loop conditions that do arithmetic in the comparison. For example:
|
Extra checking to prevent loop counter from wrapping around (backport #1766)
Fixes: GHSA-hqjh-hpv8-8r9p
The bug is this loop condition in
CrwMap::decodeArray
. The loop counter,c
, is auint16_t
, so if the component size is greater than2 * 0xffff
thenc
will wrap around and the loop won't terminate.There are 3 commits:
So the 3rd commit is optional. I'll add comments to the code review explaining those changes.