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

revive: Bump PolkaVM and add static code validation #5939

Merged
merged 16 commits into from
Oct 7, 2024
Merged

Conversation

athei
Copy link
Member

@athei athei commented Oct 6, 2024

This PR adds static validation that prevents upload of code that:

  1. Contains basic blocks larger than the specified limit (currently 200)
  2. Contains invalid instructions
  3. Uses the sbrk instruction

Doing that statically at upload time (instead of at runtime) allows us to change the basic block limit or add instructions later without worrying about breaking old code. This is well worth the linear scan of the whole blob on deployment in my opinion. Please note that those checks are not applied when existing code is just run (hot path).

Also some drive by fixes:

  • Remove superflous publish = true
  • Abort fixture build on warning and fix existing warnings
  • Re-enable optimizations in fixture builds (should be fixed now in PolkaVM)
  • Disable stripping for fixture builds (maybe we can get some line information on trap via RUST_LOG)

@athei athei added the R0-silent Changes should not be mentioned in any release notes label Oct 6, 2024
@github-actions github-actions bot deleted a comment from athei Oct 6, 2024
@github-actions github-actions bot deleted a comment from athei Oct 6, 2024
@paritytech paritytech deleted a comment from github-actions bot Oct 6, 2024
@paritytech paritytech deleted a comment from github-actions bot Oct 6, 2024
@athei
Copy link
Member Author

athei commented Oct 6, 2024

bot bench substrate-pallet --pallet=pallet_revive

@command-bot
Copy link

command-bot bot commented Oct 6, 2024

@athei https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7517121 was started for your command "$PIPELINE_SCRIPTS_DIR/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --features=riscv --pallet=pallet_revive. Check out https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/pipelines?page=1&scope=all&username=group_605_bot to know what else is being executed currently.

Comment bot cancel 20-fc723e0a-1450-4c19-87d8-351a73728504 to cancel this command or bot cancel to cancel all commands in this pull request.

command-bot added 2 commits October 6, 2024 16:33
@command-bot
Copy link

command-bot bot commented Oct 6, 2024

@athei Command "$PIPELINE_SCRIPTS_DIR/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --features=riscv --pallet=pallet_revive has finished. Result: https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7517121 has finished. If any artifacts were generated, you can download them from https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/7517121/artifacts/download.

Copy link
Member

@xermicus xermicus left a comment

Choose a reason for hiding this comment

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

A malicious program could trigger the compilation of the whole program

Compilation of a whole program should not be a problem regardless of the amount and size of basic blocks it contains. It follows that the compilation is not properly metered, and the charge for compilation of any BB is implied by the maximum BB size and a combination of some other limits. However we can't easily establish a sensible maximum limit, and charging the maximum for each basic block should heavily penalize contracts with many but small BBs.

We can benchmark the compilation of basic blocks and charge the overhead to ref_time then this wouldn't be a problem?

If this is really required, the PolkaVM linker should have a configurable maximum size for basic blocks, such that too large BBs are split up artificially so this is never going to a problem for contracts compiled with some toolchain that is aware. Otherwise we create a bad experience: We fail compilation of Solidity or ink! contracts if we see too large BBs in the final linked blob, and tell people "sorry you need to refactor your code so that it compiles to smaller basic blocks; glhf". This is nothing developers should never need to care about and reminds me of the Solidity StackTooDeep exception.

With tooling support we can at least counter the user experience problems; but the proper solution would be to benchmark and charge for any work done, including lazy compilation overhead, properly?

substrate/frame/revive/src/limits.rs Outdated Show resolved Hide resolved
@athei
Copy link
Member Author

athei commented Oct 7, 2024

It follows that the compilation is not properly metered

AFAIK the compilation is not metered at all. IMHO the proper solution would be that the PolkaVM interpreter charges gas up front when encountering a new basic block. I consider the limit a stop gap solution.

However we can't easily establish a sensible maximum limit, and charging the maximum for each basic block should heavily penalize contracts with many but small BBs.

Story of my life. This is always the problem with benchmarking. Only solution is to meter the compilation itself.

If this is really required, the PolkaVM linker should have a configurable maximum size for basic blocks, such that too large BBs are split up artificially so this is never going to a problem for contracts compiled with some toolchain that is aware.

Yes. I think it should be easy to add this to the linker.

@xermicus
Copy link
Member

xermicus commented Oct 7, 2024

Thanks for the clarification. FWIW I'm fine with this change as a stop-gap given we set the limit to something that makes basic code examples work (like at least 1000 instructions per BB).

@athei
Copy link
Member Author

athei commented Oct 7, 2024

200 is just what made the example fixtures work. I happily increase the number to whatever you think is appropriate. As of right now it is just a basic line of defense against trivial exploits.

@@ -1,6 +1,5 @@
[package]
name = "pallet-revive-fixtures"
publish = true
Copy link
Contributor

@pgherveou pgherveou Oct 7, 2024

Choose a reason for hiding this comment

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

You may need to update the umbrella crate as well to get ci to pass

Copy link
Member Author

Choose a reason for hiding this comment

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

Why? publish = true is a noop and this is why I removed it.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok nvm then, I thought I thought the umbrella python script was filtering crate based on the publish flag

@xermicus
Copy link
Member

xermicus commented Oct 7, 2024

Yeah I see. Well the maximum limit should be what we can set without it causing a DOS vuln. But it's hard to understand what that would be. Since the revive integration tests currently pass with a limit of 584, we have some headroom left with 1000. So I suggest 1000 if it is acceptable security wise.

for inst in program.instructions(ISA) {
num_instructions += 1;
basic_block_size += 1;
max_basic_block_size = max_basic_block_size.max(basic_block_size);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is that better / faster than not doing the max but checking the block size inside the if block, before resetting it to 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.

I moved it into the block.

substrate/frame/revive/fixtures/contracts/basic_block.rs Outdated Show resolved Hide resolved
@athei athei enabled auto-merge October 7, 2024 14:59
@athei athei added this pull request to the merge queue Oct 7, 2024
Merged via the queue into master with commit 5f55185 Oct 7, 2024
205 of 208 checks passed
@athei athei deleted the at/bump-polkavm branch October 7, 2024 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
R0-silent Changes should not be mentioned in any release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants