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

Return error if Transaction contains writable executable or ProgramData accounts #19629

Merged

Conversation

CriesofCarrots
Copy link
Contributor

@CriesofCarrots CriesofCarrots commented Sep 3, 2021

Problem

Accounts marked executable can only be written to if being upgraded (ie. if the UpgradeableLoader is present in the transaction). As of #19593, we're demoting top-level program ids incorrectly marked as writable, but we can't detect other executables until the accounts are loaded.
Similarly, ProgramData accounts can only be written if the UpgradeableLoader is present in the transaction, but we can't identify these accounts until they are loaded.

Summary of Changes

Return InvalidAccountIndex error to fail these types of Transactions and release the write lock quickly. Open to creating a new error type, if this seems significant enough.

Needs rebase on #19593
@jackcmay @jstarry , the last 3 commits are ready for review

@jackcmay
Copy link
Contributor

jackcmay commented Sep 3, 2021

Last 3 commits look good so far!

runtime/src/accounts.rs Outdated Show resolved Hide resolved
runtime/src/accounts.rs Outdated Show resolved Hide resolved
@CriesofCarrots CriesofCarrots force-pushed the cpi-writable-program-tx branch 2 times, most recently from bcffe21 to 26184e8 Compare September 4, 2021 01:17
@CriesofCarrots
Copy link
Contributor Author

Ready for final review!

runtime/src/accounts.rs Outdated Show resolved Hide resolved
runtime/src/accounts.rs Outdated Show resolved Hide resolved
runtime/src/accounts.rs Outdated Show resolved Hide resolved
return Err(TransactionError::InvalidProgramForExecution);
// If a ProgramData account is present, it should only be writable
// if the bpf_loader_upgradeable account is also present
if let Ok(UpgradeableLoaderState::ProgramData { .. }) =
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be more efficient to first check the books and then deserialize?

Copy link
Member

Choose a reason for hiding this comment

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

Could we skip the deserialization altogether and disallow writes to any account owned by the upgradeable loader? The only time a program other than the upgradeable loader can write to one of these accounts is if they top up the lamports which doesn't seem useful anyways.

runtime/src/accounts.rs Show resolved Hide resolved
return Err(TransactionError::InvalidProgramForExecution);
// If a ProgramData account is present, it should only be writable
// if the bpf_loader_upgradeable account is also present
if let Ok(UpgradeableLoaderState::ProgramData { .. }) =
Copy link
Member

Choose a reason for hiding this comment

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

Could we skip the deserialization altogether and disallow writes to any account owned by the upgradeable loader? The only time a program other than the upgradeable loader can write to one of these accounts is if they top up the lamports which doesn't seem useful anyways.

@jackcmay
Copy link
Contributor

jackcmay commented Sep 7, 2021

Adding more lamports might be necessary when we add support for realloc...

@jstarry
Copy link
Member

jstarry commented Sep 8, 2021

True, do you think the bpf loader program could be responsible for that?

@jackcmay
Copy link
Contributor

jackcmay commented Sep 8, 2021

I think so, the current plan is continue funding the account via the buffer account, so realloc to larger ProgramData account would require a larger buffer account with a larger associated number of tokens

@CriesofCarrots
Copy link
Contributor Author

I'm not clear, @jackcmay , are you saying the upgradeable-loader program need to be present to do that sort of realloc?
If so, then I think we can skip the deserialization, because any type of UpgradeableLoaderState woudl require the program be present for writes.

@jackcmay
Copy link
Contributor

jackcmay commented Sep 8, 2021

In order for a program to be realloc'd larger, the ProgramData account's balance will have to increase in order to still be rent-exempt. The question was who/how transfers those lamports. The current plan is for the larger buffer account to ferry along those lamports which means the upgradeable loader will always exist for all program reallocs. aka, we can probably skip deserialization as Justin suggested.

…sent; remove is_upgradeable_loader_present exception for all other executables
@CriesofCarrots
Copy link
Contributor Author

CriesofCarrots commented Sep 8, 2021

Okay, the last commit changes the logic to return an error if:

  • A writable account is owned by the upgradeable loader, but the upgradeable loader is not included in the tx
  • OR, a writable account is executable

Look sufficient @jackcmay @jstarry ?

@codecov
Copy link

codecov bot commented Sep 8, 2021

Codecov Report

Merging #19629 (9a5213e) into master (decec3c) will increase coverage by 0.0%.
The diff coverage is 96.0%.

@@           Coverage Diff            @@
##           master   #19629    +/-   ##
========================================
  Coverage    82.5%    82.5%            
========================================
  Files         468      468            
  Lines      131847   132036   +189     
========================================
+ Hits       108774   109036   +262     
+ Misses      23073    23000    -73     

@CriesofCarrots CriesofCarrots merged commit 38bbb77 into solana-labs:master Sep 8, 2021
mergify bot pushed a commit that referenced this pull request Sep 8, 2021
…ta accounts (#19629)

* Return error if Transaction locks an executable as writable

* Return error if a ProgramData account is writable but the upgradable loader isn't present

* Remove unreachable clause

* Fixup bpf tests

* Review comments

* Add new TransactionError

* Disallow writes to any upgradeable-loader account when loader not present; remove is_upgradeable_loader_present exception for all other executables

(cherry picked from commit 38bbb77)

# Conflicts:
#	programs/bpf/tests/programs.rs
#	runtime/src/accounts.rs
#	runtime/src/bank.rs
#	sdk/src/transaction.rs
#	storage-proto/proto/transaction_by_addr.proto
#	storage-proto/src/convert.rs
mergify bot pushed a commit that referenced this pull request Sep 8, 2021
…ta accounts (#19629)

* Return error if Transaction locks an executable as writable

* Return error if a ProgramData account is writable but the upgradable loader isn't present

* Remove unreachable clause

* Fixup bpf tests

* Review comments

* Add new TransactionError

* Disallow writes to any upgradeable-loader account when loader not present; remove is_upgradeable_loader_present exception for all other executables

(cherry picked from commit 38bbb77)

# Conflicts:
#	programs/bpf/tests/programs.rs
#	runtime/src/accounts.rs
#	runtime/src/bank.rs
#	sdk/src/transaction.rs
#	storage-proto/proto/transaction_by_addr.proto
#	storage-proto/src/convert.rs
mergify bot added a commit that referenced this pull request Sep 9, 2021
…ta accounts (backport #19629) (#19729)

* Return error if Transaction contains writable executable or ProgramData accounts (#19629)

* Return error if Transaction locks an executable as writable

* Return error if a ProgramData account is writable but the upgradable loader isn't present

* Remove unreachable clause

* Fixup bpf tests

* Review comments

* Add new TransactionError

* Disallow writes to any upgradeable-loader account when loader not present; remove is_upgradeable_loader_present exception for all other executables

(cherry picked from commit 38bbb77)

# Conflicts:
#	programs/bpf/tests/programs.rs
#	runtime/src/accounts.rs
#	runtime/src/bank.rs
#	sdk/src/transaction.rs
#	storage-proto/proto/transaction_by_addr.proto
#	storage-proto/src/convert.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
mergify bot added a commit that referenced this pull request Sep 9, 2021
…ta accounts (backport #19629) (#19730)

* Return error if Transaction contains writable executable or ProgramData accounts (#19629)

* Return error if Transaction locks an executable as writable

* Return error if a ProgramData account is writable but the upgradable loader isn't present

* Remove unreachable clause

* Fixup bpf tests

* Review comments

* Add new TransactionError

* Disallow writes to any upgradeable-loader account when loader not present; remove is_upgradeable_loader_present exception for all other executables

(cherry picked from commit 38bbb77)

# Conflicts:
#	programs/bpf/tests/programs.rs
#	runtime/src/accounts.rs
#	runtime/src/bank.rs
#	sdk/src/transaction.rs
#	storage-proto/proto/transaction_by_addr.proto
#	storage-proto/src/convert.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
Co-authored-by: Tyera Eulberg <tyera@solana.com>
dankelleher pushed a commit to identity-com/solana that referenced this pull request Nov 24, 2021
…ta accounts (solana-labs#19629)

* Return error if Transaction locks an executable as writable

* Return error if a ProgramData account is writable but the upgradable loader isn't present

* Remove unreachable clause

* Fixup bpf tests

* Review comments

* Add new TransactionError

* Disallow writes to any upgradeable-loader account when loader not present; remove is_upgradeable_loader_present exception for all other executables
frits-metalogix added a commit to identity-com/solana that referenced this pull request Nov 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants