Skip to content

Conversation

@mjdietzx
Copy link
Contributor

@mjdietzx mjdietzx commented Aug 13, 2021

This PR is on top of #22867 which adds test coverage relevant to this PR, and motivates it by highlighting some of the behavior this improves upon.

It aims to resolve issue #22209 as well as CVE-2021-31876

Bitcoin Core 0.12.0 through 0.21.1 does not properly implement the replacement policy specified in BIP125, which makes it easier for attackers to trigger a loss of funds, or a denial of service attack against downstream projects such as Lightning network nodes.


@mjdietzx mjdietzx force-pushed the fix_bip125_inherited_signaling branch 2 times, most recently from e09c0b7 to 1d95210 Compare August 13, 2021 15:05
@luke-jr
Copy link
Member

luke-jr commented Aug 13, 2021

This is not a security issue in Bitcoin Core, and there is nothing Bitcoin Core can do to fix it.

Fixing this bug is fine, but please don't misrepresent it.

@mjdietzx
Copy link
Contributor Author

@luke-jr

This is not a security issue in Bitcoin Core, and there is nothing Bitcoin Core can do to fix it.
Fixing this bug is fine, but please don't misrepresent it.

I don't think its a security issue in Bitcoin Core. Did I imply that somehow? I basically view this as minor bug fixes, and making bitcoin core adhere to BIP 125 plus getting rid of some inconsistencies

@luke-jr
Copy link
Member

luke-jr commented Aug 13, 2021

Specifically, "It fixes bug CVE-2021-31876" is incorrect. The CVE does not affect Bitcoin Core, and cannot be fixed by changing Core's default policies.

@mjdietzx
Copy link
Contributor Author

Specifically, "It fixes bug CVE-2021-31876" is incorrect. The CVE does not affect Bitcoin Core, and cannot be fixed by changing Core's default policies.

Any suggestions on how I should better word this? I'll edit

@luke-jr
Copy link
Member

luke-jr commented Aug 13, 2021

Just don't mention the CVE at all?

@ghost
Copy link

ghost commented Aug 13, 2021

Any suggestions on how I should better word this? I'll edit

-It fixes bug CVE-2021-31876
+re: CVE-2021-31876
-Fix CVE-2021-31876 RBF inherited signaling and fixes getmempoolentry returned bip125-replaceable status 
+Implement RBF inherited signaling and fix getmempoolentry returned bip125-replaceable status 

Also Bitcoin Core's RBF implementation related docs were updated in #21946

@mjdietzx mjdietzx changed the title Fix CVE-2021-31876 RBF inherited signaling and fixes getmempoolentry returned bip125-replaceable status Implement RBF inherited signaling and fix getmempoolentry returned bip125-replaceable status Aug 13, 2021
@mjdietzx mjdietzx force-pushed the fix_bip125_inherited_signaling branch from 1d95210 to 0d48c3b Compare August 13, 2021 16:24
@mjdietzx mjdietzx marked this pull request as draft August 13, 2021 18:35
@mjdietzx
Copy link
Contributor Author

mjdietzx commented Aug 13, 2021

I made this PR a draft for now. Seeing a performance degradation in functional test mempool_updatefromblock.py: Create an acyclic tournament (a type of directed graph) of transactions and use it for testing.

This is along the lines of what @ariard said in #21946

IMO, main motivation to not fix it is avoiding increasing the DoS surface of the mempool

I'm gonna dig into this and see if there's anything that can be done here. Also open to ideas

@luke-jr
Copy link
Member

luke-jr commented Aug 13, 2021

+re: CVE-2021-31876

But it isn't related to the CVE at all. The security issue is that some software assumes the network has a consistent and firm policy as if it were a consensus rule. That's an issue regardless of what policy Bitcoin Core implements.

@DrahtBot
Copy link
Contributor

DrahtBot commented Aug 14, 2021

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

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #23319 (rpc: Return fee and prevout (utxos) to getrawtransaction by dougEfresh)
  • #23121 ([policy] check ancestor feerate in RBF, remove BIP125 Rule2 by glozow)
  • #22689 (rpc: deprecate top-level fee fields in getmempool RPCs by josibake)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@mjdietzx mjdietzx force-pushed the fix_bip125_inherited_signaling branch 3 times, most recently from d2479d0 to b7f9983 Compare August 14, 2021 05:12
@mjdietzx mjdietzx force-pushed the fix_bip125_inherited_signaling branch 5 times, most recently from 4cdec25 to 832696a Compare August 15, 2021 15:14
@mjdietzx mjdietzx marked this pull request as ready for review August 15, 2021 16:17
In the event of a reorg, the assumption that a newly added tx has no
in-mempool children is false. If the children opted-out of rbf they
would show \`RBFTransactionState::FINAL\` prior to the reorg.
Upon their rbf opt-in parent being accepted back into the mempool, they
would show \`RBFTransactionState::REPLACEABLE_BIP125\`.
Highlight that transactions may signal they are replaceable even
though they are not due to BIP125 RBF (Rule bitcoin#5).
The number of original transactions to be replaced and their
descendant transactions must not exceed `MAX_BIP125_REPLACEMENT_CANDIDATES`.
This is according to BIP125 RBF (Rule 5). Without an entry in the mempool
(whether it's because we don't have a local mempool or we don't have `tx` in
our mempool) this check can't be done, and therefore the bip125-replaceable
status will be unknown regardless of how `tx` itself signals.
Now RBF signaling adheres to BIP125 RBF (Rule 5) which states that the number
of original transactions to be replaced and their descendant transactions
must not exceed `MAX_BIP125_REPLACEMENT_CANDIDATES`. Prior to this commit,
the bip125-replaceable status of a given transaction indicated whether the
transaction or _any_ of its unconfirmed ancestors opted-in to RBF, with no
consideration of this limitation.

Note: the bip125-replaceable status that `getmempoolentry` returns is still
inconsistent with what the mempool will treat as replaceable, as the mempool
does not (yet) allow inherited signaling.
Resolves issue bitcoin#22209.

The bip125-replaceable status that `getmempoolentry` returns is now
consistent with what the mempool will treat as replaceable. Transactions signal
"correctly" w.r.t. inherited signaling, and the mempool will accept a
replacement of any transaction signaling replaceability via RBF.
Previously when enforcing BIP125 Rule 5, the number of actual descendants of a set
of conflicts will be counted multiple times in some cases (ie if multiple conflicts
share a descendant). This was done to be conservative and avoid doing too much work.
However, it seems preferable to be accurate as there is no major cost or performance
bottleneck/tradeoff to do this exactly, and the code is simplified.
@mjdietzx mjdietzx force-pushed the fix_bip125_inherited_signaling branch from 42cd4ab to 2ac1d33 Compare December 1, 2021 18:09
@mjdietzx
Copy link
Contributor Author

mjdietzx commented Dec 1, 2021

Rebased on top of #22867 after #23437 and #22677 were merged

@ghost
Copy link

ghost commented Dec 2, 2021

I also re-worked the PR description as things have changed a lot (this is just simpler than before)

Can you share the things that have changed a lot? Sorry it's difficult to keep a track of everything related to mempool, rbf etc.

Also is there any pull request open in LN implementation repos to fix this CVE which affects LN implementations?

Copy link
Member

@glozow glozow left a comment

Choose a reason for hiding this comment

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

Thanks for updating! First pass through - I appreciate that you've used functional tests to dig into this code and they're really good, but a lot are out of scope for this PR. I'd recommend adding unit tests for SignalsOptInRBF() instead.

Comment on lines -51 to -70
Copy link
Member

Choose a reason for hiding this comment

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

commit "validation: MemPoolAccept::PreChecks count evictions accurately" and "test: replacement tx rejected bc conflicts may be double counted" are interesting but out of the scope of this PR. I'd suggest removing them.

Comment on lines +108 to +118
Copy link
Member

Choose a reason for hiding this comment

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

in 2ac1d33:

I don't think increased confidence needs to be an RPC release note, especially since there is no change to the returned result.

Copy link
Member

Choose a reason for hiding this comment

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

for commit "test: incorrect rbf status when max replacement limit exceeded"

While it's true that bip125-replaceable is only checking for Rule#1, and actual replacement is restricted by other requirements as well, I don't think it's necessary to add a test specifically to illustrate this.

Instead, you could probably clarify the result in the RPC help string.

Comment on lines +57 to +61
Mempool policy changed such that now RBF inherited signaling is supported (transactions
that don't explicitly signal replaceability are replaceable for as long as any one
of their ancestors signals replaceability and remains unconfirmed). Previously
the mempool only accepted replacements for transactions that themselves opted-in
to RBF. See `getmempoolentry` in the "Updated RPCs" section below for more details. (#22698)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Mempool policy changed such that now RBF inherited signaling is supported (transactions
that don't explicitly signal replaceability are replaceable for as long as any one
of their ancestors signals replaceability and remains unconfirmed). Previously
the mempool only accepted replacements for transactions that themselves opted-in
to RBF. See `getmempoolentry` in the "Updated RPCs" section below for more details. (#22698)
Mempool transactions now inherit RBF signaling from ancestors, addressing CVE-2021-31876. (#22698)

"-acceptnonstdtxn=1",
"-maxorphantx=1000",
"-limitancestorcount=50",
f"-limitancestorcount={MAX_REPLACEMENT_LIMIT + 3}", # enough room to test BIP125 Rule #5
Copy link
Member

Choose a reason for hiding this comment

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

Side note: It's not very clean to change a policy in order to test another, tightly related policy. If the test requires more than 100 replaced transactions, you should create multiple conflicting transactions rather than increasing the ancestor limit.

@mjdietzx
Copy link
Contributor Author

mjdietzx commented Dec 2, 2021

@glozow thanks for the review! To clarify, this PR is on top of #22867 which should be reviewed independently. I agree that not all the functional tests are relevant, but I think once you consider the PRs separately it will make more sense.

I will look at adding some unit tests, I agree it's necessary. I will go through your comments in more detail shortly

@mjdietzx
Copy link
Contributor Author

mjdietzx commented Dec 2, 2021

Can you share the things that have changed a lot? Sorry it's difficult to keep a track of everything related to mempool, rbf etc.

@prayank23 The PR description and the commit messages (which are pretty detailed) should provide a good overview.

I know you looked at this PR way back when I first opened it, when it was very rough. It was marked as a draft for a while, and the main things I changed when I re-opened it were:

  • broke a lot of the additional functional test coverage into a separate PR test: Extend test coverage of BIP125 and document confusing/inconsistent behavior #22867
  • did not do any performance optimizations to IsRBFOptIn (instead I believe that should be a followup, if we think it's worthwhile)
  • rebased on top of a lot of related work which allowed me to simplify and have more minimal changes to code (so the code-diff of this PR is much smaller than previously)

Also is there any pull request open in LN implementation repos to fix this CVE which affects LN implementations?

Great idea, I will look into this and follow up. Honestly I have not looked at other implementations much. IIRC mempool policy of other implementations differs from bitcoin core, but I'll take a look in detail

@ghost
Copy link

ghost commented Dec 2, 2021

@mjdietzx Thanks for sharing the details.

Great idea, I will look into this and follow up. Honestly I have not looked at other implementations much. IIRC mempool policy of other implementations differs from bitcoin core, but I'll take a look in detail.

There are 7 LN implementations based on this list. Some of them might be using BTCD which has inherited signaling. However, 99% of Bitcoin nodes use Bitcoin Core as Bitcoin full node. Please share the link to issue/PR if you create one in any LN implementation (would follow the discussion) because RBF is just a mempool policy and cannot be enforced, so nothing would prevent nodes (or even miners) from using a different policy if that helps in exploiting vulnerable LN projects.

@glozow
Copy link
Member

glozow commented Dec 3, 2021

To clarify, this PR is on top of #22867 which should be reviewed independently. I agree that not all the functional tests are relevant, but I think once you consider the PRs separately it will make more sense.

Thanks for clarifying. The "validation: MemPoolAccept::PreChecks count evictions accurately" commit is not contained in #22867, and not related to inherited signaling. Note that it increases the number of potential mempool entries visited from 100 to unlimited.

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

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

Concept NACK

I don't think any changes are required in Bitcoin Core's mempool policy. Documentation could have been improved and it was done in #21946. Documentation can always be improved further.

Even if changed it won't fix CVE that affects vulnerable LN projects

More context: #22698 (comment)

@mjdietzx
Copy link
Contributor Author

mjdietzx commented Dec 4, 2021

The "validation: MemPoolAccept::PreChecks count evictions accurately" commit is not contained in #22867, and not related to inherited signaling. Note that it increases the number of potential mempool entries visited from 100 to unlimited.

I was on the fence about including 658a0f3 in this PR. I tend to agree it is not necessary for it to be in this PR, and I'd be open to removing it for now. But my thought process was:

  • it is related to inherited signaling because there are cases where a transaction should be replaceable due to inherited signaling, but is not due to eviction double counting. And in these cases the bip125-replaceable status that getmempoolentry returns will be different than what the mempool will treat as replaceable. Which is something I wanted to be totally consistent after this PR
  • Note that it increases the number of potential mempool entries visited from 100 to unlimited. This is a great point, and I want this to be front-and-center in this PR. It is not just the case in MemPoolAccept::PreChecks, but also the case in IsRBFOptIn 831ecb0. Instead we rely on the local mempool's policy to put a hard bound on the work we do to determine inherited signaling:
default mempool limits are much stricter than BIP125 Rule 5's MAX_BIP125_REPLACEMENT_CANDIDATES{100},
because DEFAULT_DESCENDANT_LIMIT == 25

In my testing/implementation I found this was a safe assumption (I discuss this more in the PR description). But this is the risk of this PR and we need to be sure we don't introduce a DOS vector here. Which I don't believe we do, but the reviewers who know much better than me will need to confirm this.

@glozow
Copy link
Member

glozow commented Dec 7, 2021

Note that it increases the number of potential mempool entries visited from 100 to unlimited. This is a great point, and I want this to be front-and-center in this PR. It is not just the case in MemPoolAccept::PreChecks, but also the case in IsRBFOptIn 831ecb0.

Right, I hadn't noticed that it was the case in both. Limiting to 100 direct conflicts and default ancestor limits means up to 2500 entry lookups. But both IsRBFOptIn and GetItersForConflicting are worse because the number of direct conflicts hasn't been restricted at all. It can contain much more than 100 - the limit is the number of inputs you can cram into a 100KvB transaction. The two functions combined can cause you to search all of the ancestors and all of the descendants, and the inputs don't even need valid signatures because you haven't done script checks yet. It can probably cover your entire mempool.

I think as long as you fail faster, you can still get decent bounds (based on the anc/desc limit). Have you also considered an alternative approach for signaling checks - instead of searching ancestor sets of all conflicts every time, caching a signaling bool in mempool entries? It's an extra bit for every transaction, but perhaps we can pack it somewhere in CTxMemPoolEntry. We would also need to update entries on removal (limited to limitdescendantcount). I haven't really dug into it - it's possible that the alternative approach is worse - but maybe worth thinking about?

@DrahtBot
Copy link
Contributor

DrahtBot commented Dec 7, 2021

🐙 This pull request conflicts with the target branch and needs rebase.

Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a "draft".

@DrahtBot
Copy link
Contributor

There hasn't been much activity lately and the patch still needs rebase. What is the status here?
  • Is it still relevant? ➡️ Please solve the conflicts to make it ready for review and to ensure the CI passes.
  • Is it no longer relevant? ➡️ Please close.
  • Did the author lose interest or time to work on this? ➡️ Please close it and mark it 'Up for grabs' with the label, so that it can be picked up in the future.

@fanquake
Copy link
Member

I'm going to close this for now. It can be re-opened and rebased if/when #22867 is merged.

@fanquake fanquake closed this Mar 22, 2022
maflcko pushed a commit that referenced this pull request Jul 8, 2022
4c9666b Mention `mempoolfullrbf` in policy/mempool-replacements.md (Antoine Riard)
aae66ab Update getmempoolinfo RPC with `mempoolfullrbf` (Antoine Riard)
3e27e31 Introduce `mempoolfullrbf` node setting. (Antoine Riard)

Pull request description:

  This is ready for review.

  Recent discussions among LN devs have brought back on the surface concerns about the security of multi-party funded transactions against pinnings attacks and other mempool-based nuisances. The lack of full-rbf transaction-relay topology connected to miners open the way to cheap and naive DoS against multi-party funded transactions (e.g coinjoins, dual-funded channels, on-chain DLCs, ...) without solutions introducing an overhead cost or centralization vectors afaik . For more details, see [0].

  This PR implements a simple `fullrbf` setting, where the node always allows transaction replacement, ignoring BIP125 opt-in flag. The default value of the setting stays **false**, therefore opt-in replacement is still the default Bitcoin Core replacement policy. Contrary to a previous proposal of mine and listening to feedbacks collected since then [1], I think this new setting simply offers more flexibility in a node transaction-relay policy suiting one's application requirements, without arguing a change of the default behavior.

  I [posted](https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-June/020557.html) on the ML to invite operators with a bitcoin application sensitive to full-rbf (e.g dual-funded LN channels service providers) or mempool researchers to join a bootstrapped full-rbf activated peers network for experimentation and learning. If people have strong opinions against the existence of such full-rbf transaction-relay network, I'm proposing to express them on the future thread.

  [0] https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-May/003033.html
  [1] https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-June/019074.html

  Follow-up suggestions :
  - soft-enable opt-in RBF in the wallet : #25353 (comment)
  - p2p discovery and additional outbound connection to full-rbf peers : #25353 (comment)
  - match the code between RPC, wallet and mempool about disregard of inherited signaling : #22698

ACKs for top commit:
  instagibbs:
    reACK 4c9666b
  glozow:
    ACK 4c9666b, a few nits which are non-blocking.
  w0xlt:
    ACK 4c9666b

Tree-SHA512: 9e288bf22e06a9808804e58178444ef1830c3fdd42fd8a7cd7ffb101f8f586e08b000679be407d63ca76a56f7216227b368ff630c81f3fac3243db1a1202ab1c
@bitcoin bitcoin locked and limited conversation to collaborators Mar 22, 2023
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.

7 participants