Skip to content
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

Reject TXs when there is a mismatch #6236

Merged
merged 5 commits into from
Oct 18, 2019

Conversation

ryoqun
Copy link
Member

@ryoqun ryoqun commented Oct 4, 2019

Hi, this is my second small PR.

Problem

See #3568.

Summary of Changes

  • Made sigverify fail when there is a mismatch between tx.signatures.len() and tx.message().num_required_signatures.
    • Specifically, made get_packets_offset return 0 as sig_len to propagate such a rejection into the ultimate result of sigverify. This changes the runtime semantics of sigverify for the case of with sig_len being 0. So be careful when reviewing!
    • I believe this is the best way under the various constraints to localize the needed changes, considering both the CPU implementation and the GPU one.
  • (Additionally to the A malicious slot leader can drop signatures #3568), I fixed a bug in deserializing logic in get_packets_offset. (Should I create a separete pull request?)

@mvines mvines added the CI Pull Request is ready to enter CI label Oct 4, 2019
@solana-grimes solana-grimes removed the CI Pull Request is ready to enter CI label Oct 4, 2019
@garious
Copy link
Contributor

garious commented Oct 4, 2019

@sakridge @CriesofCarrots, fyi. Not sure if the issue referenced is still an issue after the credit-only rewrite. Can you take a peek at #3568?

@ryoqun
Copy link
Member Author

ryoqun commented Oct 5, 2019

@sakridge @CriesofCarrots, fyi. Not sure if the issue referenced is still an issue after the credit-only rewrite. Can you take a peek at #3568?

Thanks for checking this. I'll also try to understand how this relates to the credit-only rewrite.

@CriesofCarrots
Copy link
Contributor

@sakridge @CriesofCarrots, fyi. Not sure if the issue referenced is still an issue after the credit-only rewrite. Can you take a peek at #3568?

Yep, this does appear to still be an issue, as sigverify trusts the signature vec length per this line here:

let (sig_len, sig_size) = decode_len(&packet.data);

@ryoqun
Copy link
Member Author

ryoqun commented Oct 9, 2019

@CriesofCarrots Thanks for checking this out! I'll work on to finish this up tomorrow's work-time in JST. :)

@ryoqun ryoqun changed the title [WIP] Reject TXs when there is a mismatch Reject TXs when there is a mismatch Oct 10, 2019
@ryoqun ryoqun marked this pull request as ready for review October 10, 2019 18:55
@@ -51,6 +51,10 @@ fn verify_packet(packet: &Packet) -> u8 {
let mut pubkey_start = pubkey_start as usize;
let msg_start = msg_start as usize;

if sig_len == 0 {
Copy link
Member Author

Choose a reason for hiding this comment

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

As mentioned in the pull request description, this part changes the runtime semantics. I'm assuming there will be no transaction with zero signature...

for _ in 0..sig_len {
signature_offsets.push(sig_offset);
sig_offset += size_of::<Signature>() as u32;
if sig_len > 0 {
Copy link
Member Author

Choose a reason for hiding this comment

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

As mentioned in the pull request description, this part changes the runtime semantics. I'm assuming there will be no transaction with zero signature...

@@ -127,6 +127,7 @@ fn get_program_ids(instructions: &[Instruction]) -> Vec<Pubkey> {
pub struct MessageHeader {
/// The number of signatures required for this message to be considered valid. The
/// signatures must match the first `num_required_signatures` of `account_keys`.
/// NOTE: Serialization-related changes must be paired with the direct read at sigverify.
Copy link
Member Author

Choose a reason for hiding this comment

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

As bonuses, I added precautionary comments to prevent this bug from reoccurring in the future...

Copy link
Member

@sakridge sakridge Oct 14, 2019

Choose a reason for hiding this comment

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

Can you also add a test that fails if the serialization changes in a way to affect that?

Copy link
Member Author

Choose a reason for hiding this comment

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

Well, I could do that of course, however I think that will be out of scope for this PR, assuming you're meaning to write some robust set of unit tests for each plausible outcome of get_packet_offsets. This PR getting relatively large as one from an outside contributor already.

I've already wrote units tests, directly spotting the changed behavior: 1, 2 and 3.

I understand those yet-to-be-written unit tests will be invaluable, considering sigverify will directly be faced to the outside world (= the public Internet for the permission-less DLT like solana). But the concern already are covered by the issues like #5414 and #6339.

Anyway, if there are some thoughts I'm missing or better unit test scenario, please tell me!

Copy link
Member

Choose a reason for hiding this comment

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

Ok, no problem, we can take on writing that test.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for consideration! Hopefully, writing it will be me if I find some free time!


let (_pubkey_len, pubkey_size) = decode_len(&packet.data[msg_start_offset..]);
Copy link
Member Author

Choose a reason for hiding this comment

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

Sadly, this was a blatant wrongdoing of reading a packet...

In short, this old code incorrectly reads bytes serialized from MessageHeader (three of u8s) as the length (ShortU16) of short_vec. (Moderate pun intended... :).

So, if MessageHeader.required_num_sigs are above 0x7f (according to the comment of Short16), pubkey_size will be 2 and subsequent offset calculation gets bogus, resulting in false negative results of sigverify. This have been working because most of time MessageHeader.required_num_sigs is very small compared to the 0x7f.

To make sure, I traced this back to the origin of introduction of this bug. Let me know if it's needed!

(By the way, this is the first bug I've ever found in the production code of solana, I think I've finally managed to make tangible contribution... yay!)

Copy link
Member Author

Choose a reason for hiding this comment

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

Also, accompanying unit test is test_large_sigs

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a nice catch. That was my oversight; thanks!

Copy link
Member Author

Choose a reason for hiding this comment

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

FYI, this is split into #6388.

@ryoqun
Copy link
Member Author

ryoqun commented Oct 10, 2019

@CriesofCarrots @garious Sorry for not being able to deliver the promised blush-up in time... But I've finally managed to finish it! Could you review this pull request and run the CI?

@CriesofCarrots CriesofCarrots added the CI Pull Request is ready to enter CI label Oct 10, 2019
@solana-grimes solana-grimes removed the CI Pull Request is ready to enter CI label Oct 10, 2019
@codecov
Copy link

codecov bot commented Oct 10, 2019

Codecov Report

Merging #6236 into master will increase coverage by 1.2%.
The diff coverage is 74.5%.

@@           Coverage Diff            @@
##           master   #6236     +/-   ##
========================================
+ Coverage    77.4%   78.6%   +1.2%     
========================================
  Files         216     219      +3     
  Lines       42592   41922    -670     
========================================
+ Hits        32969   32985     +16     
+ Misses       9623    8937    -686

Copy link
Contributor

@CriesofCarrots CriesofCarrots left a comment

Choose a reason for hiding this comment

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

This approach looks okay to me. Just a couple small suggestions.
But I'd love for @sakridge to take a look; adding as reviewer.

core/src/sigverify.rs Outdated Show resolved Hide resolved
core/src/sigverify.rs Outdated Show resolved Hide resolved
core/src/sigverify.rs Outdated Show resolved Hide resolved
core/src/sigverify.rs Outdated Show resolved Hide resolved
core/src/sigverify.rs Outdated Show resolved Hide resolved
@sakridge
Copy link
Member

This looks pretty good, but I would like to see a test that puts the malicious transaction into the verify path to show the issue in the original code and then that it's fixed with the updated offsets logic.

@sakridge
Copy link
Member

I actually would like to see this split into the fix for the issue #3568 and the deserialization fix.

@ryoqun
Copy link
Member Author

ryoqun commented Oct 15, 2019

Thanks for various comments! Now that #6251 is almost finished, I'll work on this tomorrow!

@ryoqun
Copy link
Member Author

ryoqun commented Oct 16, 2019

@sakridge

I actually would like to see this split into the fix for the issue #3568 and the deserialization fix.

I created one! Please take a look at #6388. Currently, both are based on the same parent git commit. And semantically, this PR are based on #6388, expecting that hotfix-like PR will get merged first. After the merge this PR will look like this: https://github.com/ryoqun/solana/compare/unaligned-pubkey-read..mismatched-sig-len.

This looks pretty good, but I would like to see a test that puts the malicious transaction into the verify path to show the issue in the original code and then that it's fixed with the updated offsets logic.

I think this newly-added test case covers that scenario. If anything is missing, please tell me!

@mvines mvines added the CI Pull Request is ready to enter CI label Oct 16, 2019
@solana-grimes solana-grimes removed the CI Pull Request is ready to enter CI label Oct 16, 2019
@CriesofCarrots
Copy link
Contributor

@ryoqun , can you rebase on master, now that #6388 is merged? Thank you!

@ryoqun
Copy link
Member Author

ryoqun commented Oct 16, 2019

Oops, I created a merge commit to preserve old review comments. Is the rebase way preferred? I'm fine to do that!

@mvines
Copy link
Member

mvines commented Oct 16, 2019

Oops, I created a merge commit to preserve old review comments. Is the rebase way preferred? I'm fine to do that!

Rebase please. No need to preserve the old review comments

Reject transactions when there is a mismatch between tx.signatures.len() and
tx.message().num_required_signatures.

Fixes solana-labs#3568
@ryoqun ryoqun force-pushed the mismatched-sig-len branch from 2de7267 to 3079bdb Compare October 16, 2019 20:29
@ryoqun
Copy link
Member Author

ryoqun commented Oct 16, 2019

@mvines done!

Oops, I created a merge commit to preserve old review comments. Is the rebase way preferred? I'm fine to do that!

Rebase please. No need to preserve the old review comments

Ok! Rebased!

core/src/sigverify.rs Outdated Show resolved Hide resolved
core/src/sigverify.rs Outdated Show resolved Hide resolved
core/src/sigverify.rs Outdated Show resolved Hide resolved
@ryoqun
Copy link
Member Author

ryoqun commented Oct 16, 2019

@CriesofCarrots @sakridge Thanks for quick reviews! I'm relieved the introduction of PacketOffsets isn't off too much, so I finished it up fixing all nits!

@ryoqun
Copy link
Member Author

ryoqun commented Oct 16, 2019

(Wow, it seems CI starts without bothering you to attach the CI label anymore... I'm very happy! Thank you very much!)

@mvines
Copy link
Member

mvines commented Oct 16, 2019

(Wow, it seems CI starts without bothering you to attach the CI label anymore... I'm very happy! Thank you very much!)

Yep, I fixed that for you :)

CriesofCarrots
CriesofCarrots previously approved these changes Oct 17, 2019
core/src/sigverify.rs Outdated Show resolved Hide resolved
@ryoqun ryoqun requested a review from sakridge October 18, 2019 01:28
@mergify mergify bot dismissed CriesofCarrots’s stale review October 18, 2019 01:29

Pull request has been modified.

@ryoqun
Copy link
Member Author

ryoqun commented Oct 18, 2019

Oops, github created a merge commit.... I'll force push...

@ryoqun ryoqun force-pushed the mismatched-sig-len branch 2 times, most recently from 1cd32f6 to b7f518d Compare October 18, 2019 01:32
core/src/sigverify.rs Outdated Show resolved Hide resolved
core/src/sigverify.rs Outdated Show resolved Hide resolved
core/src/sigverify.rs Outdated Show resolved Hide resolved
@ryoqun
Copy link
Member Author

ryoqun commented Oct 18, 2019

@CriesofCarrots Thanks for reviewing again! I addressed them!

@CriesofCarrots CriesofCarrots added the automerge Merge this Pull Request automatically once CI passes label Oct 18, 2019
@solana-grimes solana-grimes merged commit 193c9a0 into solana-labs:master Oct 18, 2019
@CriesofCarrots
Copy link
Contributor

Thanks, @ryoqun !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge Merge this Pull Request automatically once CI passes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants