Skip to content

Conversation

theStack
Copy link
Contributor

The BIP37 bloom filter class CBloomFilter contains two flags isEmpty/isFull together with an update method with the purpose to, according to the comments, "avoid wasting cpu", i.e. the mechanism should serve as an optimization for the trivial cases of empty (all bits zero) or full (all bits one) filters.
However, the real reason of adding those flags (introduced with commit 37c6389 by gmaxwell) was a covert fix of CVE-2013-5700, a vulnerability that allowed a divide-by-zero remote node crash.
According to gmaxwell himself (#9060 (comment)):

the IsEmpty/IsFull optimizations were largely a pretextual optimization intended to make unexploitable a remote crash vulnerability (integer division by zero) that existed in the original bloom filtering code without disclosing it. I'm doubtful that they are all that useful. :)

For more information on how to trigger this crash, see PR #18515 which contains a detailled description and a regression test. It has also been discussed on a recent PR club meeting on fuzzing.

The covert fix code already led to issues and PR based on the wrong assumption that the flags are there for optimization reasons (see #16886 and #16922). This PR gets rid of the flags and the update method and just focuses on the CVE fix itself, i.e. it can be seen as a revert of the covert fix commit modulo the actual fix.

@laanwj
Copy link
Member

laanwj commented Apr 29, 2020

Concept and code review ACK 1ad8ea2
Simpler code is better here, and absolutely, the "pretend" reasoning has caused a few people to do unnecessary work here.

@maflcko
Copy link
Member

maflcko commented Apr 29, 2020

ACK 1ad8ea2

@practicalswift
Copy link
Contributor

practicalswift commented Apr 29, 2020

Concept ACK but please don't invalidate the existing seed corpus :)

@jnewbery
Copy link
Contributor

jnewbery commented May 1, 2020

We'll cover this in review club next Wednesday: https://bitcoincore.reviews/18806.html

@meshcollider
Copy link
Contributor

utACK 1ad8ea2

@fjahr
Copy link
Contributor

fjahr commented May 5, 2020

Code review ACK 1ad8ea2

Thanks for clarifying this code!

@jkczyz
Copy link
Contributor

jkczyz commented May 6, 2020

ACK 1ad8ea2

Reviewed and verified tests pass (including p2p_filter functional test which exercises this behavior).

@fanquake fanquake merged commit 551dc7f into bitcoin:master May 6, 2020
@rajarshimaitra
Copy link
Contributor

Unit tests and functional tests passing (including p2p_filter).
Code Review ACK.

Question:
It seems this PR reverts almost all the changes of PR 2914 to fix the bug. Why the bug fix was done using is{Empty,Full} flags if it could have been fixed with a simple vData.empty() check in the insert and contains functions?

@fjahr
Copy link
Contributor

fjahr commented May 6, 2020

It seems this PR reverts almost all the changes of PR 2914 to fix the bug. Why the bug fix was done using is{Empty,Full} flags if it could have been fixed with a simple vData.empty() check in the insert and contains functions?

That is the covert part of the fix (together with a misleading commit message and merge process). It made it harder to understand that there was a vulnerability so that attackers don't find it and use it before most of the network has updated to a version that includes the fix. Once that is the case the vulnerability is made public. This post about a more recent vulnerability should give you more insight into the process: https://bitcoincore.org/en/2019/11/08/CVE-2017-18350/

@vasild
Copy link
Contributor

vasild commented May 6, 2020

utACK 1ad8ea2

@eriknylund
Copy link
Contributor

eriknylund commented May 6, 2020

ACK 1ad8ea2 reviewed changes, built and ran tests.

Ran functional test p2p_filter which includes test for CVE-2013-5700 fix:

$ test/functional/p2p_filter.py 
2020-05-06T16:50:58.370000Z TestFramework (INFO): Initializing test directory /var/folders/tx/4h1x765x05xd4mkbqgj507dw0000gn/T/bitcoin_func_test_922swrck
2020-05-06T16:51:00.727000Z TestFramework (INFO): Check that too large filter is rejected
2020-05-06T16:51:00.838000Z TestFramework (INFO): Check that too large data element to add to the filter is rejected
2020-05-06T16:51:00.889000Z TestFramework (INFO): Add filtered P2P connection to the node
2020-05-06T16:51:00.942000Z TestFramework (INFO): Check that we receive merkleblock and tx if the filter matches a tx in a block
2020-05-06T16:51:01.002000Z TestFramework (INFO): Check that we only receive a merkleblock if the filter does not match a tx in a block
2020-05-06T16:51:01.150000Z TestFramework (INFO): Check that we not receive a tx if the filter does not match a mempool tx
2020-05-06T16:51:01.451000Z TestFramework (INFO): Check that we receive a tx in reply to a mempool msg if the filter matches a mempool tx
2020-05-06T16:51:01.656000Z TestFramework (INFO): Check that after deleting filter all txs get relayed again
2020-05-06T16:51:03.128000Z TestFramework (INFO): Check that request for filtered blocks is ignored if no filter is set
2020-05-06T16:51:03.326000Z TestFramework (INFO): Check that sending "filteradd" if no filter is set is treated as misbehavior
2020-05-06T16:51:03.379000Z TestFramework (INFO): Check that division-by-zero remote crash bug [CVE-2013-5700] is fixed
2020-05-06T16:51:03.543000Z TestFramework (INFO): Stopping nodes
2020-05-06T16:51:03.910000Z TestFramework (INFO): Cleaning up /var/folders/tx/4h1x765x05xd4mkbqgj507dw0000gn/T/bitcoin_func_test_922swrck on exit
2020-05-06T16:51:03.910000Z TestFramework (INFO): Tests successful

Copy link
Contributor

@eriknylund eriknylund left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feedback from nehan and others during the PR review club was to consider adding an assert() in the Hash() method to make sure any caller is informed that a vData.empty() check has been done to make sure vData.size() is not 0.

@vasild
Copy link
Contributor

vasild commented May 6, 2020

@eriknylund an assertion failure is not much different than division by zero - both would terminate the program.

@practicalswift
Copy link
Contributor

@vasild Division by zero is not guaranteed to terminate the program :)

@jnewbery
Copy link
Contributor

jnewbery commented May 6, 2020

utACK 1ad8ea2

Concept ACK adding the assert, to document the expectations.

@theStack
Copy link
Contributor Author

theStack commented May 7, 2020

I'm neutral on the idea of adding an assert to Hash() -- on one hand it documents expectations, on the other hand there is no point in ever calling the hash function outside of the two operations insert and contains in a bloom filter. Also the performance could decrease a bit if on every single hash calculated (up to 50 per insert/contains operation) an additional assertion condition has to be checked.

@eriknylund
Copy link
Contributor

I'm neutral on the idea of adding an assert to Hash() -- on one hand it documents expectations, on the other hand there is no point in ever calling the hash function outside of the two operations insert and contains in a bloom filter. Also the performance could decrease a bit if on every single hash calculated (up to 50 per insert/contains operation) an additional assertion condition has to be checked.

I see. Would a simple comment be better suited in this case?

@sipa
Copy link
Member

sipa commented May 7, 2020

Just a comment/assertion on Hash is arguably insufficient. The code vData[nIndex >> 3] is always invalid when vData is empty, for any value of nIndex - which happens to exactly match the conditions in which Hash is allowed to be called.

@ThomasBucaioni
Copy link

All three test suites passed here.

sidhujag pushed a commit to syscoin/syscoin that referenced this pull request May 12, 2020
…er, clarify CVE fix

1ad8ea2 net: remove is{Empty,Full} flags from CBloomFilter, clarify CVE fix (Sebastian Falbesoner)

Pull request description:

  The BIP37 bloom filter class `CBloomFilter` contains two flags `isEmpty`/`isFull` together with an update method with the purpose to, according to the comments, "avoid wasting cpu", i.e. the mechanism should serve as an optimization for the trivial cases of empty (all bits zero) or full (all bits one) filters.
  However, the real reason of adding those flags (introduced with commit bitcoin@37c6389 by gmaxwell) was a _covert fix_ of [CVE-2013-5700](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-5700), a vulnerability that allowed a divide-by-zero remote node crash.
  According to gmaxwell himself (bitcoin#9060 (comment)):
  > the IsEmpty/IsFull optimizations were largely a pretextual optimization intended to make unexploitable a remote crash vulnerability (integer division by zero) that existed in the original bloom filtering code without disclosing it. I'm doubtful that they are all that useful. :)

  For more information on how to trigger this crash, see PR bitcoin#18515 which contains a detailled description and a regression test. It has also been discussed on a [recent PR club meeting on fuzzing](https://bitcoincore.reviews/18521.html).

  The covert fix code already led to issues and PR based on the wrong assumption that the flags are there for optimization reasons (see bitcoin#16886 and bitcoin#16922). This PR gets rid of the flags and the update method and just focuses on the CVE fix itself, i.e. it can be seen as a revert of the covert fix commit modulo the actual fix.

ACKs for top commit:
  meshcollider:
    utACK 1ad8ea2
  laanwj:
    Concept and code review ACK 1ad8ea2
  jkczyz:
    ACK 1ad8ea2
  MarcoFalke:
    ACK 1ad8ea2
  fjahr:
    Code review ACK 1ad8ea2

Tree-SHA512: 29f7ff9faece0285e11e16c024851f5bcb772dec64118ccc3f9067ec256267ec8e1b1e3105c7de2a72fd122c3b085e8fc840ab8f4e49813f1cc7a444df1867f7
@theStack theStack deleted the 20200428-net-clarify-divide-by-zero-fix branch December 1, 2020 09:55
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Jan 26, 2021
Summary:
```
The BIP37 bloom filter class CBloomFilter contains two flags
isEmpty/isFull together with an update method with the purpose to,
according to the comments, "avoid wasting cpu", i.e. the mechanism
should serve as an optimization for the trivial cases of empty (all bits
zero) or full (all bits one) filters.
However, the real reason of adding those flags (introduced with commit
37c6389 by gmaxwell) was a covert fix of CVE-2013-5700, a vulnerability
that allowed a divide-by-zero remote node crash.
According to gmaxwell himself (#9060 (comment)):

    the IsEmpty/IsFull optimizations were largely a pretextual
optimization intended to make unexploitable a remote crash vulnerability
(integer division by zero) that existed in the original bloom filtering
code without disclosing it. I'm doubtful that they are all that useful.
:)

For more information on how to trigger this crash, see PR #18515 which
contains a detailled description and a regression test. It has also been
discussed on a recent PR club meeting on fuzzing.

The covert fix code already led to issues and PR based on the wrong
assumption that the flags are there for optimization reasons (see #16886
and #16922). This PR gets rid of the flags and the update method and
just focuses on the CVE fix itself, i.e. it can be seen as a revert of
the covert fix commit modulo the actual fix.
```

Backport of core [[bitcoin/bitcoin#18806 | PR18806]].

Test Plan:
  ninja all check-all
  ninja bitcoin-fuzzers
  ./src/test/fuzz/bloom_filter <path_to_corpus>

Reviewers: #bitcoin_abc, PiRK

Reviewed By: #bitcoin_abc, PiRK

Differential Revision: https://reviews.bitcoinabc.org/D9051
zkbot added a commit to zcash/zcash that referenced this pull request Mar 5, 2021
Backport bloom filter improvements

Cherry-picked from the following upstream PRs:

- bitcoin/bitcoin#7113
- bitcoin/bitcoin#7818
  - Only the second commit (to resolve conflicts).
- bitcoin/bitcoin#7934
- bitcoin/bitcoin#8655
  - Partial backport to help resolve conflicts.
- bitcoin/bitcoin#9060
- bitcoin/bitcoin#9223
- bitcoin/bitcoin#9644
  - Partial backport to help resolve conflicts.
- bitcoin/bitcoin#9916
- bitcoin/bitcoin#9750
- bitcoin/bitcoin#13176
- bitcoin/bitcoin#13948
- bitcoin/bitcoin#16073
- bitcoin/bitcoin#18670
- bitcoin/bitcoin#18806
  - Reveals upstream's covert fix for CVE-2013-5700.
- bitcoin/bitcoin#19968
zkbot added a commit to zcash/zcash that referenced this pull request Apr 15, 2021
Backport bloom filter improvements

Cherry-picked from the following upstream PRs:

- bitcoin/bitcoin#7113
- bitcoin/bitcoin#7818
  - Only the second commit (to resolve conflicts).
- bitcoin/bitcoin#7934
- bitcoin/bitcoin#8655
  - Partial backport to help resolve conflicts.
- bitcoin/bitcoin#9060
- bitcoin/bitcoin#9223
- bitcoin/bitcoin#9644
  - Partial backport to help resolve conflicts.
- bitcoin/bitcoin#9916
- bitcoin/bitcoin#9750
- bitcoin/bitcoin#13176
- bitcoin/bitcoin#13948
- bitcoin/bitcoin#16073
- bitcoin/bitcoin#18670
- bitcoin/bitcoin#18806
  - Reveals upstream's covert fix for CVE-2013-5700.
- bitcoin/bitcoin#19968
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.