-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Fix signed integer oveflow #25561
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
Fix signed integer oveflow #25561
Conversation
Signed-off-by: Anthony Fieroni <[email protected]>
|
Mind adding steps to reproduce? |
Increase |
|
Sorry, I don't follow. Are you saying this is something that an end user of a Bitcoin Core release can run into or does it require local modifications or external scripts? Our functional tests run with the integer sanitizer, so are you saying this happens only outside of tests? I am happy to try to reproduce this, but it would make it a lot easier for me if there were exact and easy steps to reproduce. Ideally ones that can be copy-pasted into a terminal. |
|
If this is security relevant (or you are unsure about it), kindly follow the security policy: |
|
It could compromise block / tx index and/or coins db which could lead to possible fork and compromise the network as worst case scenario. |
|
@bvbfan, I don't think this is possible under any realistic circumstance. Writing the entire UTXO set in a single batch still wouldn't come close to triggering an overflow. |
|
@chjj correct, it groups batches when it's called concurrently, but it does it even one batch is present, notice one batch it uses the allocated one and will overflow as well. Issue is pretty serious. |
|
@bvbfan, the append loop won't ever be entered with just a single writer: std::deque<Writer*>::iterator iter = writers_.begin();
++iter; // Advance past "first"
for (; iter != writers_.end(); ++iter) {
...
}
I'm still having trouble understanding how there would be billions of updates in a single write. |
Easy, bitcoin core uses a cache over the backed, so when cache is increased it will produce a big batch, as i wrote before via |
I don't think that's true. When the cache is flushed, core splits the updates into smaller batches. These batches are processed sequentially, and aren't grouped together by LevelDB. |
There is nothing to "think", just read the code |
|
While an overflow may technically be UB, in practice AFAIK it is always the same deterministic result (for the same platform) on all supported platforms. So unless the value going negative is a problem (which is not trivial to see looking at the code), I don't see how this is exploitable or can lead to de facto issues. But if going negative is a problem, I don't see why simply making it uint32 would fix it... it would just move the overflow from 2^31 to 2^32. That being said, since it's UB, we should probably still fix it anyway. But this currently goes through upstream or at least https://github.com/bitcoin-core/leveldb-subtree |
Keep in mind that If the issue purely exists for unrelated third-party API users of the google leveldb, the issue should be fixed in google/leveldb. |
It will be true if there is unsigned int in the calculation chain, but there isn't. It's stored as unsigned but after calculation. The lucky scenario is 0 + (- signed) will not trigger actual calculation then it's fine.
Unsigned int overflow is well defined and expected, unless that - true.
So wrong logic, even if it's well defined, as i wrote only by luck, it could lead to possible fork in the future, depend of some new implementation. There is no blind here. |
I don't think this leads to signed integer overflow.
Note that this size is not the number of entries being updated, but the overall serialized size of the batch (which is internally represented as std::string). The number of entries ref'd by SetCount or Count is the actual number of entries being updated via put/delete. The count will always lag behind the byte size of the batch since each entry being modified at least has a key that is stored in the internal std::string. Since the |
Correct, it's internal counter of Put/Delete records, it could overflow as well, note here So depending of configuration it's vulnerable. I did not expect to defence a patch which address a clear CVE. |
|
A few comments:
|
Untrue, https://github.com/bitcoin/bitcoin/blob/master/src/txdb.cpp#L118 it's configurable. It's not affected only coinds db, block index as well.
Sure, i could open PR there.
Sure, it's open PR upstream, i still think it's higher priority to Bitcoin
Sure, i did not request, but it's clear a CVE, i was supposed to do it, but rather i think it's better to be fixed here. |
|
It's accepted upstream. |
|
Not as far as I can see...? |
|
It's approved google/leveldb#1040 |
That some random GitHub account marks your PR with a checkmark on GItHub doesn't mean that the PR is accepted into upstream. Everyone can add this checkmark on any PR. |
It's Common Vulnerable and Exposure mirror google/leveldb#1040
Ledger by default is safe, but if node is running by
-dbcache=2148or more it will misbehave.