-
Notifications
You must be signed in to change notification settings - Fork 37.7k
refactor: Avoid integer overflow in ApplyStats when activating snapshot #23411
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
Conversation
31ce7b3
to
fac215e
Compare
fac215e
to
fa5bdc9
Compare
How does activating a snapshot trigger an integer overflow in this code in the first place? That seems far more concerning, and this PR just patches it up. |
@sipa Added three more sentences to OP to explain this refactor. |
Hm, I'm kind of confused - is the concern here that a user could be fed a bad snapshot that causes an overflow? Because if that's the case, the hash of the UTXO set won't match the one hardcoded in chainparams' If it's not a bad snapshot you're worried about, then as far as I can tell the same wraparound issue would exist with a normal |
Correct. If we don't care about integer overflows when activating invalid snapshots, then this pull can be closed. |
Would it make sense to instead compute the total amount as an |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsNo conflicts as of last run. |
fa5bdc9
to
fa12d4f
Compare
Switched to |
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.
Concept ACK
This PR allows preventing integer overflow of coin_stats.total_amount while activating the snapshot.
The following points explain the PR in greater detail:
- The function
AdditionOverflow
has been moved from src/test/fuzz/util.h to a new file src/util/overflow.h. The dependencies of other files are updated accordingly. - Unit tests are added for this function, which tests on various edge cases in the case of both signed and unsigned elements.
- The
AdditionOverflow
function is used in thecoinstats::ApplyStats
function to prevent the risk of an overflow of CAmount. In case if there might be an integer overflow, thetotal_amount
var is set tonullopt
.
Though I have not rigorously tested this PR yet, I think the code is logically coherent.
I have just one doubt I would like to point out.
In src/test/util_tests.cpp file:
From the line BOOST_CHECK(TestAddMatrix<signed>());
I inferred that this function was made to be used with signed integers. If I am correct, then there is one logical error:
assert(TestAdd(mini, mini));
This might not always be true.
For example:
- mini = 2; mini + mini = 4 > 2 (in range) TestAdd result == true
- mini = -2; mini + mini = -4 < -2 (out of range) TestAdd result == false
fa29302
to
faff961
Compare
MINI is a compile time constant (just force pushed to rename it from mini). It allows for the test checking for underflow to be less verbose. Checking for underflow is only needed when adding signed integers. Adding two unsigned integers can only overflow. |
faff961
to
fa13888
Compare
Seems like the number is useful for human verification. We should probably log it or tell advanced users somewhere. Maybe instead, abort activation of snapshots that exceed |
The amounts are already covered by the hash, which is obviously trusted and verified. Thus, it will abort activation. Starting to check random consensus rules on the snapshot is going to be an open ended issue (why not check that there are no unspendable scriptPubKeys in the snapshot, ...) that doesn't give any benefit. |
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.
Checking for underflow is only needed when adding signed integers. Adding two unsigned integers can only overflow.
Makes sense to me now. Since TestAddMatrix()
is being used only for signed integer. The minimum possible value ( = MINI) must be < 0. In that case the assertion condition assert(TestAdd(MINI, MINI));
will never fail.
crACK fa13888
fa13888
to
fa4a86e
Compare
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.
reACK fa4a86e
Changes since my last review:
- Added a new function CheckedAdd (in overflow.h), which returns nullopt if there is an addition overflow (or underflow) and otherwise returns the sum.
- TestAdd function (in util_tests.cpp) has been removed, and its usage is replaced with CheckedAdd.
- Finally, CheckedAdd is used to simplify added code in the coinstats.cpp file.
fa4a86e
to
fa72733
Compare
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.
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.
Concept ACK fa72733
fa72733
to
fa996c5
Compare
Addressed test nits in force push. Should be trivial to re-ACK with:
|
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.
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.
ACK fa996c5
…hen activating snapshot fa996c5 refactor: Avoid integer overflow in ApplyStats when activating snapshot (MarcoFalke) fac0188 Move AdditionOverflow to util, Add CheckedAdd with unit tests (MarcoFalke) fa526d8 Add dev doc to CCoinsStats::m_hash_type and make it const (MarcoFalke) faff051 style: Remove unused whitespace (MarcoFalke) Pull request description: A snapshot contains the utxo set, including the out value. To activate the snapshot, the hash needs to be calculated. As a side-effect, the total amount in the snapshot is calculated (as the sum of all out values), but never used. Instead of running into an integer overflow in an unused result, don't calculate the result in the first place. Other code paths (using the active utxo set) can not run into an integer overflow, since the active utxo set is valid. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=39716 ACKs for top commit: shaavan: reACK fa996c5 vasild: ACK fa996c5 Tree-SHA512: 4f207f634841f6f634fd02ae1e5907e343fd767524fd0e8149aa99fa9a1834fe50167d14874834d45236e9c325d567925f28129bacb7d80be29cf22277a16a14
A snapshot contains the utxo set, including the out value. To activate the snapshot, the hash needs to be calculated. As a side-effect, the total amount in the snapshot is calculated (as the sum of all out values), but never used. Instead of running into an integer overflow in an unused result, don't calculate the result in the first place.
Other code paths (using the active utxo set) can not run into an integer overflow, since the active utxo set is valid.
Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=39716