-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Check that CAddrMan::nKey is not null after deserialize #22498
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
Converted to draft to avoid merge conflicts for now |
|
Zero is a special value because it is used to clear the memory before destructing addrman. Though, I see your point, which is why I mentioned the alternative in OP:
Are you saying I should remove the check from |
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 fa52c7e
Needs rebase.
Are you saying I should remove the check from _Check?
I don't have strong opinion and this is so minor that it will work either way. Personally I would remove it from Check()
and remove the SetNull()
from addrman destructor. Nowadays there are better ways to detect use-after-free than setting select members to magic values in the destructor.
Or add a comment to m_key
to explain the magic value or make the magic value a static member constant or:
- nKey = insecure_rand.rand256();
+ do {
+ nKey = insecure_rand.rand256();
+ } while (nKey.IsNull());
to make it explicit.
There is no need for that. It's a 256-bit value. If we're worried about the chance that it can randomly be 0, we should first be worried about hash collisions in blocks, and randomly guessing private keys. |
... to the reader that 0 is treated specially, it would be more of a documentation than avoiding a |
Not if it is merged after the pull that it conflicts with ;)
Makes sense. Will do, because addrman is only destructed on shutdown, at which point is seems unlikely that someone successfully pulls an attack after exploiting a use-after-free on m_key. |
The reason for wiping the key is to avoid keeping secret key material longer in memory than needed, by the way. The fact that it allows use-after-free detection is a side effect. |
The secret is written to disk in plain text and thus kept in the cache in memory. With that in mind, is it important to still set it to zero on shutdown? |
I'd still say so, yes. This is no different from wallet private keys in an unencrypted wallet. Leaving it in memory means it risks ending up in uninitialized memory that's allocated, where it may leak in case of other bugs. The addrman key is of course not nearly as sensitive as wallet keys, and the fact that it remains in use almost the entire lifetime of the process makes it less of an issue further, but I think it's good practice in general to wipe key material that is unused. We could go further and allocate it using the locked pool, actually. |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsNo conflicts as of last run. |
fa52c7e
to
fa64288
Compare
Ok, I am not removing the |
|
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 same errors occurred.
fatal error: in "addrman_tests/addrman_serialization": std::ios_base::failure[abi:cxx11]: Corrupt CAddrMan serialization, m_key is all zeros.: iostream error
fatal error: in "addrman_tests/remove_invalid": std::ios_base::failure[abi:cxx11]: Corrupt CAddrMan serialization, m_key is all zeros.: iostream error
Concept ACK |
fa64288
to
0b8e34c
Compare
Concept ACK |
Otherwise CAddrMan::_Check() will complain.
0b8e34c
to
fa5ee2f
Compare
See #22734 |
…k after deserialize fa3669f fuzz: Move all addrman fuzz targets to one file (MarcoFalke) fa7a883 addrman: Replace assert with throw on corrupt data (MarcoFalke) fa29897 Refactor: Turn the internal addrman check helper into a forced check (MarcoFalke) fae5c63 move-only: Move CAddrMan::Check to cpp file (MarcoFalke) Pull request description: Assert should only be used for program internal logic errors, not to sanitize external user input. The assert was introduced via the debug-only runtime option `-checkaddrman` in commit 803ef70, thus won't need a backport. Also, it doesn't really make sense to continue when the deserialized addrman doesn't pass the sanity check. For example, if `nLastSuccess` is negative, it would later result in integer overflows. Thus, this patch fixes bitcoin#22931. Also, Fixes bitcoin#22503 Fixes bitcoin#22504 Fixes bitcoin#22519 Closes bitcoin#22498 Steps to test: ``` mkdir -p /tmp/test_235/regtest/ echo 'H4sIAAAAAAAAA/u1f+stZmUGYgELgwPRakfBKBgFo2AUjIJRMApGwSgYBaNgFIyCUTBswdyGpFnLjUKjP9e0bvjYusl6b+L2e7Vs2dd6N//Pua0/xQUALJAn93IQAAA=' | base64 --decode | zcat > /tmp/test_235/regtest/peers.dat ./src/qt/bitcoin-qt -regtest -datadir=/tmp/test_235/ -checkaddrman=1 -printtoconsole | grep -A2 'Loading P2P addresses' ``` Output before: ``` 2021-09-10T11:28:37Z init message: Loading P2P addresses… 2021-09-10T11:28:37Z ADDRMAN CONSISTENCY CHECK FAILED!!! err=-16 bitcoin-qt: addrman.cpp:765: void CAddrMan::Check() const: Assertion `false' failed. (program crashes) ``` Output after: ``` 2021-09-10T11:26:00Z init message: Loading P2P addresses… 2021-09-10T11:26:00Z Error: Invalid or corrupt peers.dat (Corrupt data. Consistency check failed with code -16: iostream error). If you believe this is a bug, please report it to https://github.com/bitcoin/bitcoin/issues. As a workaround, you can move the file ("/tmp/test_235/regtest/peers.dat") out of the way (rename, move, or delete) to have a new one created on the next start. (program exits) ``` ACKs for top commit: naumenkogs: ACK fa3669f jnewbery: Code review ACK fa3669f vasild: ACK fa3669f Tree-SHA512: 687e4a4765bbc66495152fa7a49d28ee84b405dc5370ba87b4016b5593e45f54c4ce5cae579e4d433e0e082d20fc263969fa602679c911accef0adb2d6213bd6
…k after deserialize fa3669f fuzz: Move all addrman fuzz targets to one file (MarcoFalke) fa7a883 addrman: Replace assert with throw on corrupt data (MarcoFalke) fa29897 Refactor: Turn the internal addrman check helper into a forced check (MarcoFalke) fae5c63 move-only: Move CAddrMan::Check to cpp file (MarcoFalke) Pull request description: Assert should only be used for program internal logic errors, not to sanitize external user input. The assert was introduced via the debug-only runtime option `-checkaddrman` in commit 803ef70, thus won't need a backport. Also, it doesn't really make sense to continue when the deserialized addrman doesn't pass the sanity check. For example, if `nLastSuccess` is negative, it would later result in integer overflows. Thus, this patch fixes bitcoin#22931. Also, Fixes bitcoin#22503 Fixes bitcoin#22504 Fixes bitcoin#22519 Closes bitcoin#22498 Steps to test: ``` mkdir -p /tmp/test_235/regtest/ echo 'H4sIAAAAAAAAA/u1f+stZmUGYgELgwPRakfBKBgFo2AUjIJRMApGwSgYBaNgFIyCUTBswdyGpFnLjUKjP9e0bvjYusl6b+L2e7Vs2dd6N//Pua0/xQUALJAn93IQAAA=' | base64 --decode | zcat > /tmp/test_235/regtest/peers.dat ./src/qt/bitcoin-qt -regtest -datadir=/tmp/test_235/ -checkaddrman=1 -printtoconsole | grep -A2 'Loading P2P addresses' ``` Output before: ``` 2021-09-10T11:28:37Z init message: Loading P2P addresses… 2021-09-10T11:28:37Z ADDRMAN CONSISTENCY CHECK FAILED!!! err=-16 bitcoin-qt: addrman.cpp:765: void CAddrMan::Check() const: Assertion `false' failed. (program crashes) ``` Output after: ``` 2021-09-10T11:26:00Z init message: Loading P2P addresses… 2021-09-10T11:26:00Z Error: Invalid or corrupt peers.dat (Corrupt data. Consistency check failed with code -16: iostream error). If you believe this is a bug, please report it to https://github.com/bitcoin/bitcoin/issues. As a workaround, you can move the file ("/tmp/test_235/regtest/peers.dat") out of the way (rename, move, or delete) to have a new one created on the next start. (program exits) ``` ACKs for top commit: naumenkogs: ACK fa3669f jnewbery: Code review ACK fa3669f vasild: ACK fa3669f Tree-SHA512: 687e4a4765bbc66495152fa7a49d28ee84b405dc5370ba87b4016b5593e45f54c4ce5cae579e4d433e0e082d20fc263969fa602679c911accef0adb2d6213bd6
Otherwise
CAddrMan::_Check()
will complain.An alternative would be to remove the check from
CAddrMan::_Check()
.