Skip to content

Conversation

gmaxwell
Copy link
Contributor

@gmaxwell gmaxwell commented Feb 6, 2017

We don't normally use ReadVarInt from untrusted inputs, but we might
see this in the case of corruption.

This is exposed in test_bitcoin_fuzzy.

We don't normally use ReadVarInt from untrusted inputs, but we might
 see this in the case of corruption.

This is exposed in test_bitcoin_fuzzy.
@gmaxwell
Copy link
Contributor Author

gmaxwell commented Feb 6, 2017

@sipa might have a suggestion for a cleaner way to do this?

@@ -336,11 +336,18 @@ I ReadVarInt(Stream& is)
I n = 0;
while(true) {
unsigned char chData = ser_readdata8(is);
if (n > (std::numeric_limits<I>::max() >> 7)) {
throw std::ios_base::failure("ReadVarInt(): size too large");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this not be done before chData is read?
It reads currently as though chData being read impacts this in some way

Copy link
Member

Choose a reason for hiding this comment

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

It won't hurt as this branch will never be taken in non-exceptional situation, and at best it may improve ILP.

Copy link
Contributor

Choose a reason for hiding this comment

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

I meant for readability

@sipa
Copy link
Member

sipa commented Feb 6, 2017

Alternative (as this is not used for data read from the network): restrict CVarInt to unsigned types only (the only reason to suggest this is because I'm not sure if there may be a performance impact of this PR as is).

@laanwj
Copy link
Member

laanwj commented Feb 6, 2017

Concept ACK

@pstratem
Copy link
Contributor

pstratem commented Feb 8, 2017

A micro benchmark of this change on my laptop did not show any significant change in runtime.

(This is a pretty bad benchmark though).

@sipa
Copy link
Member

sipa commented Feb 9, 2017

tACK 45f0961

I ran a benchmark: comparing the wall-clock time of the gettxoutsetinfo command's inner loop after commenting out the chainstate hash computation, on a node with 0 connections synced to block 250065. The chainstate was on a tmpfs. Done on i7-6820HQ CPU with frequency pegged to 2.60GHz, with 32 GiB of RAM, and dbcache=8000. Measurements using GetTimeMicros.

Master: 3747773 3747375 3734935 3743421 3723418 3734187 3717763 3732135 3693859 3729604 3731461 3752013 3714361 3703590 3748206 3743741 3733456 3743399 3743514 3750425 3730095 3719208 3735383 3714827 3728027 3712683 3718786

This PR: 3690632 3692104 3686250 3681913 3667378 3661354 3680667 3700359 3687146 3684476 3686028 3679919 3669181 3731960 3671747 3679751 3664658 3691547 3683182 3675638 3682229 3672767 3667536 3669105 3670341 3663954 3664253

If anything, it seems this patch makes UTXO deserialization (likely the most impactful usage of VARINT deserialization) slightly, but measurably, faster by 1-2% at least.

@TheBlueMatt
Copy link
Contributor

utACK 45f0961

@ryanofsky
Copy link
Contributor

It doesn't seem like the varint code supports negative numbers. Should there be a
static_assert(std::is_unsigned<I>::value, "no support for signed varints"); somewhere in here?

@gmaxwell
Copy link
Contributor Author

gmaxwell commented Feb 10, 2017

@ryanofsky would have been good when it was written, unfortunately it's wrong right now-- ccoins uses it on nVersion which is signed, and the result is corrupted data (this is a known issue) fortunately we don't use the nversion for anything. (We should make sure that fact doesn't mean these exceptions can trigger.)

@practicalswift
Copy link
Contributor

practicalswift commented Feb 11, 2017

@gmaxwell Nice find! Do you have a test_bitcoin_fuzzy test case to share that triggers this issue?

I'm doing some bitcoin fuzzing myself and I'm curious to roughly how many CPU months that went into finding this issue and more specifically how many total paths that had been reached before finding this (the number printed at overall results/total paths assuming afl-fuzz)?

From my experience the code paths that can be reached using test_bitcoin_fuzzy seem to be very very robust :-)

BTW, are there any known plans to submit a test_bitcoin_fuzzy based fuzzer to https://github.com/google/oss-fuzz?

I'm really interested in fuzzing bitcoind and I'd love to share corpora. I've done some fuzzing of the Apple Swift compiler using my own fuzzer - see results and @practicalswift for some context.

@jtimon
Copy link
Contributor

jtimon commented Apr 17, 2017

Concept ACK

@sipa sipa merged commit 45f0961 into bitcoin:master Apr 17, 2017
sipa added a commit that referenced this pull request Apr 17, 2017
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell)

Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
laanwj added a commit that referenced this pull request Mar 19, 2018
499d95e Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky)

Pull request description:

  Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128.

  This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior.

  There is some discussion about this issue here: #9693 (comment). I think another good change along these lines would be to make `GetSizeOfVarInt` and `WriteVarInt` throw exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration.

Tree-SHA512: 082c65598cfac6dc1da042bdb47dbc9d5d789fc849fe52921cc238578588f4e5ff976c8b4b2ce42cb75290eb14f3b42ea76e26202c223c5b2aa63ef45c2ea3cc
markblundeberg pushed a commit to markblundeberg/bitcoin-abc that referenced this pull request May 9, 2019
Summary:
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell)

Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0

Backport of Core PR 9693
bitcoin/bitcoin#9693

Test Plan: make check

Reviewers: deadalnix, jasonbcox, Fabien, O1 Bitcoin ABC, #bitcoin_abc

Reviewed By: jasonbcox, O1 Bitcoin ABC, #bitcoin_abc

Differential Revision: https://reviews.bitcoinabc.org/D2950
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request May 10, 2019
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell)

Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request May 15, 2019
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell)

Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request May 20, 2019
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell)

Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request May 21, 2019
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell)

Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
jonspock pushed a commit to devaultcrypto/devault that referenced this pull request Jun 5, 2019
Summary:
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell)

Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0

Backport of Core PR 9693
bitcoin/bitcoin#9693

Test Plan: make check

Reviewers: deadalnix, jasonbcox, Fabien, O1 Bitcoin ABC, #bitcoin_abc

Reviewed By: jasonbcox, O1 Bitcoin ABC, #bitcoin_abc

Differential Revision: https://reviews.bitcoinabc.org/D2950
barrystyle pushed a commit to PACGlobalOfficial/PAC that referenced this pull request Jan 22, 2020
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell)

Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Dec 12, 2020
499d95e Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky)

Pull request description:

  Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128.

  This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior.

  There is some discussion about this issue here: bitcoin#9693 (comment). I think another good change along these lines would be to make `GetSizeOfVarInt` and `WriteVarInt` throw exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration.

Tree-SHA512: 082c65598cfac6dc1da042bdb47dbc9d5d789fc849fe52921cc238578588f4e5ff976c8b4b2ce42cb75290eb14f3b42ea76e26202c223c5b2aa63ef45c2ea3cc
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Dec 12, 2020
499d95e Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky)

Pull request description:

  Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128.

  This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior.

  There is some discussion about this issue here: bitcoin#9693 (comment). I think another good change along these lines would be to make `GetSizeOfVarInt` and `WriteVarInt` throw exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration.

Tree-SHA512: 082c65598cfac6dc1da042bdb47dbc9d5d789fc849fe52921cc238578588f4e5ff976c8b4b2ce42cb75290eb14f3b42ea76e26202c223c5b2aa63ef45c2ea3cc
PastaPastaPasta pushed a commit to PastaPastaPasta/dash that referenced this pull request Dec 16, 2020
499d95e Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky)

Pull request description:

  Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128.

  This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior.

  There is some discussion about this issue here: bitcoin#9693 (comment). I think another good change along these lines would be to make `GetSizeOfVarInt` and `WriteVarInt` throw exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration.

Tree-SHA512: 082c65598cfac6dc1da042bdb47dbc9d5d789fc849fe52921cc238578588f4e5ff976c8b4b2ce42cb75290eb14f3b42ea76e26202c223c5b2aa63ef45c2ea3cc
UdjinM6 pushed a commit to UdjinM6/dash that referenced this pull request Dec 17, 2020
499d95e Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky)

Pull request description:

  Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128.

  This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior.

  There is some discussion about this issue here: bitcoin#9693 (comment). I think another good change along these lines would be to make `GetSizeOfVarInt` and `WriteVarInt` throw exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration.

Tree-SHA512: 082c65598cfac6dc1da042bdb47dbc9d5d789fc849fe52921cc238578588f4e5ff976c8b4b2ce42cb75290eb14f3b42ea76e26202c223c5b2aa63ef45c2ea3cc
UdjinM6 pushed a commit to UdjinM6/dash that referenced this pull request Dec 17, 2020
499d95e Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky)

Pull request description:

  Using VARINT with signed types is dangerous because negative values will appear to serialize correctly, but then deserialize as positive values mod 128.

  This commit changes the VARINT macro to trigger a compile error by default if called with an signed value, and it updates existing broken uses of VARINT to pass a special flag that lets them keep working with no changes in behavior.

  There is some discussion about this issue here: bitcoin#9693 (comment). I think another good change along these lines would be to make `GetSizeOfVarInt` and `WriteVarInt` throw exceptions if they are passed numbers less than 0 to serialize. But unlike this change, that would be a change in runtime behavior, and need more consideration.

Tree-SHA512: 082c65598cfac6dc1da042bdb47dbc9d5d789fc849fe52921cc238578588f4e5ff976c8b4b2ce42cb75290eb14f3b42ea76e26202c223c5b2aa63ef45c2ea3cc
furszy added a commit to PIVX-Project/PIVX that referenced this pull request Apr 8, 2021
172fe15 Add missing locks and locking annotations for CAddrMan (practicalswift)
9271ace Support serialization as another type without casting (Pieter Wuille)
dc37dd9 Remove unnecessary NONNEGATIVE_SIGNED (Russell Yanofsky)
ddd2ab1 Add static_assert to prevent VARINT(<signed value>) (Russell Yanofsky)
539db35 Support deserializing into temporaries (Pieter Wuille)
36db7fd Merge READWRITEMANY into READWRITE (Pieter Wuille)
08ebd5b Remove old pre C++11 functions begin_ptr/end_ptr. (furszy)
9c84665 Prevent integer overflow in ReadVarInt. (Gregory Maxwell)

Pull request description:

  Back ported some pretty concise PRs from upstream over the data serialization area.

  * bitcoin#9305.  --> removal of pre c++11 compatibility functions.
  * bitcoin#9693.  --> prevent integer overflow in `ReadVarInt`.
  * bitcoin#9753.  --> compile error if VARINT is called with a signed value.
  * bitcoin#12683. --> fixing constness violations
  * bitcoin#12731. --> support for `READWRITEAS` macro.

ACKs for top commit:
  random-zebra:
    ACK 172fe15
  Fuzzbawls:
    ACK 172fe15

Tree-SHA512: 1e1e697761b885dcc1aed8a2132bed693b1c76f1f2ed22ae5c074dfb4c353b81d307f71a4c12ed71fc39fd2207c1403881bd699e32b85a167bee57b4f0946130
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants