-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Prevent integer overflow in ReadVarInt. #9693
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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.
@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"); | |||
} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant for readability
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). |
Concept ACK |
A micro benchmark of this change on my laptop did not show any significant change in runtime. (This is a pretty bad benchmark though). |
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. |
utACK 45f0961 |
It doesn't seem like the varint code supports negative numbers. Should there be a |
@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.) |
@gmaxwell Nice find! Do you have a 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 From my experience the code paths that can be reached using BTW, are there any known plans to submit a I'm really interested in fuzzing |
Concept ACK |
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell) Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
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
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
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell) Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell) Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell) Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell) Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
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
45f0961 Prevent integer overflow in ReadVarInt. (Gregory Maxwell) Tree-SHA512: 385ea0efb6b59d44c45a49227e5f6fff236b4775544cbeb236312a3fd87fd75c226ac56f7aa1bca66b853639da75a579610074f7582f92cf2ebd4a74bc40f6f0
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
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
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
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
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
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
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.