Skip to content
This repository has been archived by the owner on Jan 22, 2025. It is now read-only.

Programs were not spawned by SystemProgram #1533

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions programs/native/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,21 +189,13 @@ pub extern "C" fn process(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8]) -
.userdata
.splice(0..s.len(), s.iter().cloned());
}

LoaderInstruction::Finalize => {
keyed_accounts[0].account.executable = true;
keyed_accounts[0].account.loader_program_id = keyed_accounts[0].account.program_id;
keyed_accounts[0].account.program_id = *keyed_accounts[0].key;
trace!(
"BPFLoader::Finalize prog: {:?} loader {:?}",
keyed_accounts[0].account.program_id,
keyed_accounts[0].account.loader_program_id
);
trace!("BPfLoader::Finalize prog: {:?}", keyed_accounts[0].key);
}
}
} else {
warn!("Invalid program transaction: {:?}", tx_data);
return false;
}
true
}
8 changes: 1 addition & 7 deletions programs/native/lua_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,7 @@ pub extern "C" fn process(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8]) -

LoaderInstruction::Finalize => {
keyed_accounts[0].account.executable = true;
keyed_accounts[0].account.loader_program_id = keyed_accounts[0].account.program_id;
keyed_accounts[0].account.program_id = *keyed_accounts[0].key;
trace!(
"LuaLoader::Finalize prog: {:?} loader {:?}",
keyed_accounts[0].account.program_id,
keyed_accounts[0].account.loader_program_id
);
trace!("LuaLoader::Finalize prog: {:?}", keyed_accounts[0].key);
}
}
} else {
Expand Down
11 changes: 4 additions & 7 deletions src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,13 +486,10 @@ impl Bank {
account: &Account,
) -> Result<()> {
// Verify the transaction
// make sure that program_id is still the same or this was just assigned by the system call contract
if !((*pre_program_id == account.program_id)
|| (SystemProgram::check_id(&tx_program_id)
&& SystemProgram::check_id(&pre_program_id)))
{
//TODO, this maybe redundant bpf should be able to guarantee this property
// return Err(BankError::ModifiedContractId(instruction_index as u8));

// Make sure that program_id is still the same or this was just assigned by the system call contract
if *pre_program_id != account.program_id && !SystemProgram::check_id(&tx_program_id) {
return Err(BankError::ModifiedContractId(instruction_index as u8));
}
// For accounts unassigned to the contract, the individual balance of each accounts cannot decrease.
if *tx_program_id != account.program_id && pre_tokens > account.tokens {
Expand Down
39 changes: 14 additions & 25 deletions src/native_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,18 @@ pub fn process_transaction(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8])
}
};
trace!("Call native {:?}", name);
{
// create native program
let path = create_path(&name);
// TODO linux tls bug can cause crash on dlclose(), workaround by never unloading
let library = Library::open(Some(path), libc::RTLD_NODELETE | libc::RTLD_NOW).unwrap();
unsafe {
let entrypoint: Symbol<Entrypoint> = match library.get(ENTRYPOINT.as_bytes()) {
Ok(s) => s,
Err(e) => {
warn!("{:?}: Unable to find {:?} in program", e, ENTRYPOINT);
return false;
}
};
return entrypoint(&mut keyed_accounts[1..], tx_data);
}
let path = create_path(&name);
// TODO linux tls bug can cause crash on dlclose(), workaround by never unloading
let library = Library::open(Some(path), libc::RTLD_NODELETE | libc::RTLD_NOW).unwrap();
unsafe {
let entrypoint: Symbol<Entrypoint> = match library.get(ENTRYPOINT.as_bytes()) {
Ok(s) => s,
Err(e) => {
warn!("{:?}: Unable to find {:?} in program", e, ENTRYPOINT);
return false;
}
};
return entrypoint(&mut keyed_accounts[1..], tx_data);
}
} else if let Ok(instruction) = deserialize(tx_data) {
match instruction {
Expand All @@ -96,23 +93,15 @@ pub fn process_transaction(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8])
}
// native loader takes a name and we assume it all comes in at once
keyed_accounts[0].account.userdata = bytes;
return true;
}

LoaderInstruction::Finalize => {
keyed_accounts[0].account.executable = true;
keyed_accounts[0].account.loader_program_id = id();
keyed_accounts[0].account.program_id = *keyed_accounts[0].key;
trace!(
"NativeLoader::Finalize prog: {:?} loader {:?}",
keyed_accounts[0].account.program_id,
keyed_accounts[0].account.loader_program_id
);
return true;
trace!("NativeLoader::Finalize prog: {:?}", keyed_accounts[0].key);
}
}
} else {
warn!("Invalid program transaction: {:?}", tx_data);
}
false
true
}
20 changes: 17 additions & 3 deletions src/system_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use transaction::Transaction;
#[derive(Debug)]
pub enum Error {
InvalidArgument,
AssignOfUnownedAccount,
AccountNotFinalized,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
Expand Down Expand Up @@ -39,6 +41,9 @@ pub enum SystemProgram {
/// * Transaction::keys[0] - source
/// * Transaction::keys[1] - destination
Move { tokens: i64 },

/// Spawn a new program from an account
Spawn,
}

pub const SYSTEM_PROGRAM_ID: [u8; 32] = [0u8; 32];
Expand Down Expand Up @@ -85,7 +90,7 @@ impl SystemProgram {
}
SystemProgram::Assign { program_id } => {
if !Self::check_id(&accounts[0].program_id) {
Err(Error::InvalidArgument)?;
Err(Error::AssignOfUnownedAccount)?;
mvines marked this conversation as resolved.
Show resolved Hide resolved
}
accounts[0].program_id = program_id;
}
Expand All @@ -94,6 +99,14 @@ impl SystemProgram {
accounts[0].tokens -= tokens;
accounts[1].tokens += tokens;
}
SystemProgram::Spawn => {
if !accounts[0].executable || accounts[0].loader_program_id != Pubkey::default()
{
Err(Error::AccountNotFinalized)?;
}
accounts[0].loader_program_id = accounts[0].program_id;
accounts[0].program_id = tx.account_keys[0];
}
}
Ok(())
} else {
Expand Down Expand Up @@ -141,15 +154,16 @@ mod test {
}

#[test]
#[ignore]
fn test_create_spend_wrong_source() {
let from = Keypair::new();
let to = Keypair::new();
let mut accounts = vec![Account::default(), Account::default()];
accounts[0].tokens = 1;
accounts[0].program_id = from.pubkey();
let tx = Transaction::system_new(&from, to.pubkey(), 1, Hash::default());
process_transaction(&tx, &mut accounts).unwrap();
if let Ok(()) = process_transaction(&tx, &mut accounts) {
panic!("Account not owned by SystemProgram");
}
assert_eq!(accounts[0].tokens, 1);
assert_eq!(accounts[1].tokens, 0);
}
Expand Down
17 changes: 16 additions & 1 deletion src/system_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ pub trait SystemTransaction {
last_id: Hash,
fee: i64,
) -> Self;

fn system_spawn(from_keypair: &Keypair, last_id: Hash, fee: i64) -> Self;
}

impl SystemTransaction for Transaction {
Expand Down Expand Up @@ -100,7 +102,7 @@ impl SystemTransaction for Transaction {
fee,
)
}

/// Create and sign new SystemProgram::Move transaction to many destinations
fn system_move_many(from: &Keypair, moves: &[(Pubkey, i64)], last_id: Hash, fee: i64) -> Self {
let instructions: Vec<_> = moves
.iter()
Expand All @@ -124,6 +126,19 @@ impl SystemTransaction for Transaction {
instructions,
)
}
/// Create and sign new SystemProgram::Spawn transaction
fn system_spawn(from_keypair: &Keypair, last_id: Hash, fee: i64) -> Self {
let spawn = SystemProgram::Spawn;
let userdata = serialize(&spawn).unwrap();
Transaction::new(
from_keypair,
&[],
SystemProgram::id(),
userdata,
last_id,
fee,
)
}
}

pub fn test_tx() -> Transaction {
Expand Down
15 changes: 15 additions & 0 deletions tests/programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ fn test_transaction_load_native() {
let tx = Transaction::finalize(&program, native_loader::id(), mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

let tx = Transaction::system_spawn(&program, mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

// Call user program

let tx = Transaction::new(
Expand Down Expand Up @@ -114,6 +117,9 @@ fn test_transaction_load_lua() {
let tx = Transaction::finalize(&loader, native_loader::id(), mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

let tx = Transaction::system_spawn(&loader, mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

// allocate, populate, and finalize user program

let bytes = r#"
Expand Down Expand Up @@ -141,6 +147,9 @@ fn test_transaction_load_lua() {
let tx = Transaction::finalize(&program, loader.pubkey(), mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

let tx = Transaction::system_spawn(&program, mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

// Call user program with two accounts

let tx = Transaction::system_create(
Expand Down Expand Up @@ -211,6 +220,9 @@ fn test_transaction_load_bpf() {
let tx = Transaction::finalize(&loader, native_loader::id(), mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

let tx = Transaction::system_spawn(&loader, mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

// allocate, populate, and finalize user program

let tx = Transaction::system_create(
Expand Down Expand Up @@ -238,6 +250,9 @@ fn test_transaction_load_bpf() {
let tx = Transaction::finalize(&program, loader.pubkey(), mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

let tx = Transaction::system_spawn(&program, mint.last_id(), 0);
check_tx_results(&bank, &tx, bank.process_transactions(&vec![tx.clone()]));

// Call user program

let tx = Transaction::new(
Expand Down