Skip to content

Conversation

maflcko
Copy link
Member

@maflcko maflcko commented Jul 19, 2021

Otherwise CAddrMan::_Check() will complain.

An alternative would be to remove the check from CAddrMan::_Check().

@maflcko maflcko marked this pull request as draft July 19, 2021 13:45
@maflcko
Copy link
Member Author

maflcko commented Jul 19, 2021

Converted to draft to avoid merge conflicts for now

@maflcko maflcko added this to the Future milestone Jul 19, 2021
@vasild
Copy link
Contributor

vasild commented Jul 19, 2021

nKey is a random integer. Why treat 0 specially? It is a possible valid value and no less or more likely to be set in nKey = FastRandomContext::rand256(); than any other value, e.g. 0xFFFF... or 0x5555....

@maflcko
Copy link
Member Author

maflcko commented Jul 19, 2021

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:

An alternative would be to remove the check from CAddrMan::_Check().

Are you saying I should remove the check from _Check?

@DrahtBot DrahtBot added the P2P label Jul 19, 2021
Copy link
Contributor

@vasild vasild left a 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.

@sipa
Copy link
Member

sipa commented Jul 19, 2021

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.

@vasild
Copy link
Contributor

vasild commented Jul 19, 2021

to make it explicit

... to the reader that 0 is treated specially, it would be more of a documentation than avoiding a 1/2^256 chance.

@maflcko
Copy link
Member Author

maflcko commented Jul 19, 2021

Needs rebase.

Not if it is merged after the pull that it conflicts with ;)

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.

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.

@sipa
Copy link
Member

sipa commented Jul 19, 2021

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.

@maflcko
Copy link
Member Author

maflcko commented Jul 19, 2021

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?

@sipa
Copy link
Member

sipa commented Jul 19, 2021

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.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jul 19, 2021

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

No conflicts as of last run.

@maflcko maflcko force-pushed the 2107-addrmanKeyZero branch from fa52c7e to fa64288 Compare July 20, 2021 06:00
@maflcko
Copy link
Member Author

maflcko commented Jul 20, 2021

Ok, I am not removing the m_key.SetNull() in this pull. It seems unrelated anyway. Also, I took this out of draft and force pushed to fixup the tests in the first commit, which I forgot initially.

@maflcko maflcko marked this pull request as ready for review July 20, 2021 06:01
@maflcko maflcko removed this from the Future milestone Jul 20, 2021
@maflcko maflcko marked this pull request as draft July 20, 2021 06:31
@vasild
Copy link
Contributor

vasild commented Jul 20, 2021

addrman_tests/remove_invalid and addrman_tests/addrman_serialization are failing due to the new check: "Corrupt CAddrMan serialization, m_key is all zeros"

Copy link
Contributor

@lsilva01 lsilva01 left a 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

@practicalswift
Copy link
Contributor

Concept ACK

@jnewbery
Copy link
Contributor

Concept ACK

@maflcko maflcko changed the title Check that CAddrMan::m_key is not null after deserialize Check that CAddrMan::nKey is not null after deserialize Aug 17, 2021
Otherwise CAddrMan::_Check() will complain.
@maflcko
Copy link
Member Author

maflcko commented Aug 18, 2021

See #22734

@maflcko maflcko closed this Aug 18, 2021
@maflcko maflcko deleted the 2107-addrmanKeyZero branch August 18, 2021 07:24
maflcko pushed a commit to maflcko/bitcoin-core that referenced this pull request Sep 21, 2021
…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
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Sep 21, 2021
…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
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants