Skip to content

Conversation

maflcko
Copy link
Member

@maflcko maflcko commented Nov 2, 2021

Signed integer overflow is UB in theory, but not in practice. Still,
it would be nice to avoid this UB to allow Bitcoin Core to be
compiled with sanitizers such as -ftrapv or ubsan.

It is impossible to predict when and if an overflow occurs, since
the overflow caused by a prioritisetransaction RPC might only be
later hit when descendant txs are added to the mempool.
Since it is impossible to predict reliably, leave it up to the user
to use the RPC endpoint responsibly, considering their mempool
limits and usage patterns.

Fixes: #20626
Fixes: #20383
Fixes: #19278
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=34146 / https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=47132

Steps to reproduce

Build the code without the changes in this pull.

Make sure to pass the sanitizer flag:

./autogen.sh && ./configure --with-sanitizers=signed-integer-overflow && make clean && make -j $(nproc)

Reproduce on RPC

./src/bitcoind -chain=regtest -noprinttoconsole &
./src/bitcoin-cli -chain=regtest prioritisetransaction 00000000deadbeef00000000deadbeef00000000deadbeef00000000deadbeef 0 9123456789123456789
./src/bitcoin-cli -chain=regtest prioritisetransaction 00000000deadbeef00000000deadbeef00000000deadbeef00000000deadbeef 0 9123456789123456789
|> txmempool.cpp:920:15: runtime error: signed integer overflow: 9123456789123456789 + 9123456789123456789 cannot be represented in type 'long int'

./src/bitcoin-cli -chain=regtest stop

By fuzzing

wget https://github.com/bitcoin/bitcoin/files/8921302/clusterfuzz-testcase-minimized-validation_load_mempool-5599531390074880.bin.txt
FUZZ=validation_load_mempool ./src/test/fuzz/fuzz ./clusterfuzz-testcase-minimized-validation_load_mempool-5599531390074880.bin.txt 
|> txmempool.cpp:920:15: runtime error: signed integer overflow: 7214801925397553184 + 2314885530818453536 cannot be represented in type 'long int'
|> validation_load_mempool: succeeded against 1 files in 0s.

@DrahtBot
Copy link
Contributor

DrahtBot commented Nov 3, 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:

  • #17786 (refactor: Nuke policy/fees->mempool circular dependencies by hebasto)

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.

Copy link
Contributor

@PastaPastaPasta PastaPastaPasta left a comment

Choose a reason for hiding this comment

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

See https://godbolt.org/z/aWTKcM6db, I have a couple of suggestions:

  1. make TestAdd, TestAddMatrixOverflow, TestAddMatrix and AdditionOverflow constexpr b/c why not
  2. Consider replacing MaybeAdd with my implementation of MaybeAddRet, which returns a value instead of mutating a mutable reference, which enables MaybeAddRet to be constexpr. (they appear virtually equally efficient, especially when we take into account we'll be using trivial types with this) (I also think this just makes more sense for a function called "MaybeAdd" as opposed to "MaybeAddEquals" or smth else)
  3. Consider adding a static_assert(std::is_trivial<T>::value); to ensure we only are using trivial types

(also, I see that you weren't really asking for a review, but I just saw the PR and started poking around :D )

@PastaPastaPasta
Copy link
Contributor

See https://godbolt.org/z/aWTKcM6db, I have a couple of suggestions:

  1. make TestAdd, TestAddMatrixOverflow, TestAddMatrix and AdditionOverflow constexpr b/c why not
  2. Consider replacing MaybeAdd with my implementation of MaybeAddRet, which returns a value instead of mutating a mutable reference, which enables MaybeAddRet to be constexpr. (they appear virtually equally efficient, especially when we take into account we'll be using trivial types with this) (I also think this just makes more sense for a function called "MaybeAdd" as opposed to "MaybeAddEquals" or smth else)
  3. Consider adding a static_assert(std::is_trivial<T>::value); to ensure we only are using trivial types

(also, I see that you weren't really asking for a review, but I just saw the PR and started poking around :D )

@MarcoFalke do you have an opinion about these suggestions?

@maflcko maflcko marked this pull request as draft February 7, 2022 13:26
@maflcko
Copy link
Member Author

maflcko commented Feb 7, 2022

Yeah, MaybeAdd will be removed, in which case the suggestions won't apply.

maflcko pushed a commit to bitcoin-core/gui that referenced this pull request Feb 21, 2022
faa7d8a util: Add SaturatingAdd helper (MarcoFalke)

Pull request description:

  Seems good to have this in the repo, as it might be needed to write cleaner code. For example:

  * bitcoin/bitcoin#24090 (comment)
  * bitcoin/bitcoin#23418 (comment)
  * ...

ACKs for top commit:
  MarcoFalke:
    Added a test. Should be trivial to re-ACK with `git range-diff bitcoin-core/master fa90189cbf faa7d8a`
  klementtan:
    reACK faa7d8a
  vasild:
    ACK faa7d8a

Tree-SHA512: d0e6efdba7dfcbdd16ab4539a7f5e45a97d17792e42586c3c52caaae3fc70612dc9e364359658de5de5718fb8c2a765a59ceb2230098355394fa067a9732bc2a
@maflcko maflcko marked this pull request as ready for review February 22, 2022 10:00
@maflcko maflcko force-pushed the 2111-txPoolPrioOverflow branch from fa108c3 to faa69b3 Compare February 22, 2022 10:04
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.

concept ACK faa69b3

Very nice to get rid of a sanitizer suppression, and the fee delta for modified fees should be a CAmount anyway. I have a small suggestion which is not really within scope of this PR, so feel freee to ignore.

@maflcko maflcko force-pushed the 2111-txPoolPrioOverflow branch from faa69b3 to fa28736 Compare March 25, 2022 10:20
@maflcko maflcko closed this Mar 25, 2022
@maflcko maflcko reopened this Mar 25, 2022
@maflcko maflcko force-pushed the 2111-txPoolPrioOverflow branch from fa28736 to fa46eec Compare March 25, 2022 10:39
@maflcko maflcko force-pushed the 2111-txPoolPrioOverflow branch 4 times, most recently from fa131d5 to fa59aef Compare March 29, 2022 12:32
@maflcko
Copy link
Member Author

maflcko commented Mar 29, 2022

Rebased and replied to all comments. Also changed the name of the update function.

@maflcko maflcko force-pushed the 2111-txPoolPrioOverflow branch 2 times, most recently from fa3d182 to fac053d Compare March 31, 2022 08:38
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 fac053d

Consider #23418 (comment)

@maflcko maflcko force-pushed the 2111-txPoolPrioOverflow branch from fac053d to fa471a7 Compare March 31, 2022 13:48
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 fa471a7

@maflcko maflcko added this to the 24.0 milestone Apr 27, 2022
Copy link
Contributor

@LarryRuane LarryRuane left a comment

Choose a reason for hiding this comment

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

Rebased onto latest master (7377ed7), was able to reproduce the bug both using RPC and fuzzing, and the bug is fixed using the PR (both ways).

You could make a couple of small fixes in the description: dot before /autogen.sh, and add -chain=regtest to the bitcoin-cli command lines.

In the first commit message, s/tacked/tracked/.

lockPoints{lp},
nSizeWithDescendants{GetTxSize()},
nModFeesWithDescendants{nFee},
nSizeWithAncestors{GetTxSize()},
nModFeesWithAncestors{nFee},
nSigOpCostWithAncestors{sigOpCost} {}

void CTxMemPoolEntry::UpdateFeeDelta(CAmount newFeeDelta)
void CTxMemPoolEntry::UpdateModifiedFee(CAmount fee_diff)
Copy link
Contributor

Choose a reason for hiding this comment

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

Would a better name be IncrementModifiedFee? The verb "update" isn't wrong, but it could mean simply setting a variable to a value (as in a simple assignment statement). The verb "increment" makes it clear that a variable, or, in this case, 3 variables, are being incremented by the argument. It's true that the previous name used the verb "update", so maybe it would be best to preserve that. But I just thought I'd mention it for consideration.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree, but maybe this can be done as a follow up to also rename the Update*State functions, which do the same thing, but are not touched in this pull request.

@@ -921,7 +925,7 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeD
delta += nFeeDelta;
Copy link
Contributor

Choose a reason for hiding this comment

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

delta is now unused

Copy link
Member Author

Choose a reason for hiding this comment

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

delta is a mutable reference, so while the symbol itself isn't used after this line, the line can not be removed.

MarcoFalke added 2 commits June 22, 2022 09:32
* feeDelta tracked the delta (to be applied on top of the actual fee)
* m_modified_fee tracks the actual fee with the delta included
* Instead of passing in the new total delta to the Updater, pass in by
  how much the total delta should be modified.

This is needed for the next commit, but makes sense on its own because
the same is done by UpdateDescendantState and UpdateAncestorState.
@maflcko maflcko force-pushed the 2111-txPoolPrioOverflow branch from fa471a7 to fa07f84 Compare June 22, 2022 07:34
@maflcko
Copy link
Member Author

maflcko commented Jun 22, 2022

In the first commit message, s/tacked/tracked/.

Thx, done. Also rebased to make testing easier. Should be trivial to re-ACK with git range-diff.

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 fa07f84

Copy link
Contributor

@dunxen dunxen left a comment

Choose a reason for hiding this comment

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

ACK fa07f84

@michaelfolkson
Copy link

michaelfolkson commented Jun 22, 2022

Concept ACK, Approach ACK.

The saturating approach (as discussed in today's PR review club) makes sense over alternative approaches. Reviewed code changes, didn't test unfortunately.

Copy link
Contributor

@LarryRuane LarryRuane left a comment

Choose a reason for hiding this comment

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

ACK fa07f84
I reproduced the bug on master both using RPC and fuzzing, and the bug is fixed using the PR (both ways)/

@maflcko maflcko merged commit dde7205 into bitcoin:master Jun 27, 2022
@maflcko maflcko deleted the 2111-txPoolPrioOverflow branch June 27, 2022 06:37
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Jun 27, 2022
…tion RPC

fa07f84 Fix signed integer overflow in prioritisetransaction RPC (MarcoFalke)
fa52cf8 refactor: Replace feeDelta by m_modified_fee (MarcoFalke)

Pull request description:

  Signed integer overflow is UB in theory, but not in practice. Still,
  it would be nice to avoid this UB to allow Bitcoin Core to be
  compiled with sanitizers such as `-ftrapv` or ubsan.

  It is impossible to predict when and if an overflow occurs, since
  the overflow caused by a prioritisetransaction RPC might only be
  later hit when descendant txs are added to the mempool.
  Since it is impossible to predict reliably, leave it up to the user
  to use the RPC endpoint responsibly, considering their mempool
  limits and usage patterns.

  Fixes: bitcoin#20626
  Fixes: bitcoin#20383
  Fixes: bitcoin#19278
  Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=34146 / https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=47132

  ## Steps to reproduce

  Build the code without the changes in this pull.

  Make sure to pass the sanitizer flag:

  ```
  ./autogen.sh && ./configure --with-sanitizers=signed-integer-overflow && make clean && make -j $(nproc)
  ```

  ### Reproduce on RPC

  ```
  ./src/bitcoind -chain=regtest -noprinttoconsole &
  ./src/bitcoin-cli -chain=regtest prioritisetransaction 00000000deadbeef00000000deadbeef00000000deadbeef00000000deadbeef 0 9123456789123456789
  ./src/bitcoin-cli -chain=regtest prioritisetransaction 00000000deadbeef00000000deadbeef00000000deadbeef00000000deadbeef 0 9123456789123456789
  |> txmempool.cpp:920:15: runtime error: signed integer overflow: 9123456789123456789 + 9123456789123456789 cannot be represented in type 'long int'

  ./src/bitcoin-cli -chain=regtest stop
  ```

  ### By fuzzing

  ```
  wget https://github.com/bitcoin/bitcoin/files/8921302/clusterfuzz-testcase-minimized-validation_load_mempool-5599531390074880.bin.txt
  FUZZ=validation_load_mempool ./src/test/fuzz/fuzz ./clusterfuzz-testcase-minimized-validation_load_mempool-5599531390074880.bin.txt
  |> txmempool.cpp:920:15: runtime error: signed integer overflow: 7214801925397553184 + 2314885530818453536 cannot be represented in type 'long int'
  |> validation_load_mempool: succeeded against 1 files in 0s.

ACKs for top commit:
  vasild:
    ACK fa07f84
  dunxen:
    ACK fa07f84
  LarryRuane:
    ACK fa07f84

Tree-SHA512: 4a357950af55a49c9113da0a50c2e743c5b752f0514dd8d16cd92bfde2f77dd0ef56aa98452626df6f7f7a5b51d1227021f6bc94091201a179f0d488ee32a0df
@bitcoin bitcoin locked and limited conversation to collaborators Jun 27, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
9 participants