Skip to content

Commit

Permalink
Disallow deployment of deprecated _sol_alloc_free syscall (#24986)
Browse files Browse the repository at this point in the history
* Disallow deployment of deprecated _sol_alloc_free syscall

* remove cli argument
  • Loading branch information
jackcmay authored May 11, 2022
1 parent 4c7a030 commit 8f1d4c1
Show file tree
Hide file tree
Showing 19 changed files with 223 additions and 43 deletions.
2 changes: 1 addition & 1 deletion cli/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2044,7 +2044,7 @@ fn read_and_verify_elf(program_location: &str) -> Result<Vec<u8>, Box<dyn std::e
reject_broken_elfs: true,
..Config::default()
},
register_syscalls(&mut invoke_context).unwrap(),
register_syscalls(&mut invoke_context, true).unwrap(),
)
.map_err(|err| format!("ELF error: {}", err))?;

Expand Down
6 changes: 3 additions & 3 deletions programs/bpf/benches/bpf_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ fn bench_program_alu(bencher: &mut Bencher) {
&elf,
None,
Config::default(),
register_syscalls(invoke_context).unwrap(),
register_syscalls(invoke_context, true).unwrap(),
)
.unwrap();
Executable::<BpfError, ThisInstructionMeter>::jit_compile(&mut executable).unwrap();
Expand Down Expand Up @@ -228,7 +228,7 @@ fn bench_create_vm(bencher: &mut Bencher) {
&elf,
None,
Config::default(),
register_syscalls(invoke_context).unwrap(),
register_syscalls(invoke_context, true).unwrap(),
)
.unwrap();

Expand Down Expand Up @@ -263,7 +263,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
&elf,
None,
Config::default(),
register_syscalls(invoke_context).unwrap(),
register_syscalls(invoke_context, true).unwrap(),
)
.unwrap();
let compute_meter = invoke_context.get_compute_meter();
Expand Down
31 changes: 26 additions & 5 deletions programs/bpf/c/src/alloc/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ extern uint64_t entrypoint(const uint8_t *input) {
// Confirm large allocation fails
void *ptr = sol_calloc(1, UINT64_MAX);
if (ptr != NULL) {
sol_log("Error: Alloc of very larger buffer should fail");
sol_log("Error: Alloc of very large type should fail");
sol_panic();
}
}
Expand All @@ -18,7 +18,7 @@ extern uint64_t entrypoint(const uint8_t *input) {
// Confirm large allocation fails
void *ptr = sol_calloc(UINT64_MAX, 1);
if (ptr != NULL) {
sol_log("Error: Alloc of very larger buffer should fail");
sol_log("Error: Alloc of very large number of items should fail");
sol_panic();
}
}
Expand All @@ -42,16 +42,37 @@ extern uint64_t entrypoint(const uint8_t *input) {
sol_log("Error: Alloc failed");
sol_panic();
}
for (int i = 0; i < iters; i++) {
for (uint64_t i = 0; i < iters; i++) {
*(ptr + i) = i;
}
for (int i = 0; i < iters; i++) {
for (uint64_t i = 0; i < iters; i++) {
sol_assert(*(ptr + i) == i);
}
sol_log_64(0x3, 0, 0, 0, *(ptr + 42));
sol_assert(*(ptr + 42) == 42);
sol_free(ptr);
}

// Alloc to exhaustion

for (uint64_t i = 0; i < 31; i++) {
uint8_t *ptr = sol_calloc(1024, 1);
if (ptr == NULL) {
sol_log("large alloc failed");
sol_panic();
}
}
for (uint64_t i = 0; i < 760; i++) {
uint8_t *ptr = sol_calloc(1, 1);
if (ptr == NULL) {
sol_log("small alloc failed");
sol_panic();
}
}
uint8_t *ptr = sol_calloc(1, 1);
if (ptr != NULL) {
sol_log("final alloc did not fail");
sol_panic();
}

return SUCCESS;
}
3 changes: 2 additions & 1 deletion programs/bpf/rust/128bit/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Example Rust-based BPF program tests loop iteration
extern crate solana_program;
use solana_program::{custom_panic_default, entrypoint::SUCCESS};
use solana_program::{custom_heap_default, custom_panic_default, entrypoint::SUCCESS};

#[no_mangle]
pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
Expand Down Expand Up @@ -50,6 +50,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
SUCCESS
}

custom_heap_default!();
custom_panic_default!();

#[cfg(test)]
Expand Down
5 changes: 4 additions & 1 deletion programs/bpf/rust/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
#[macro_use]
extern crate alloc;
use {
solana_program::{custom_panic_default, entrypoint::SUCCESS, log::sol_log_64, msg},
solana_program::{
custom_heap_default, custom_panic_default, entrypoint::SUCCESS, log::sol_log_64, msg,
},
std::{alloc::Layout, mem},
};

Expand Down Expand Up @@ -83,6 +85,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
SUCCESS
}

custom_heap_default!();
custom_panic_default!();

#[cfg(test)]
Expand Down
5 changes: 4 additions & 1 deletion programs/bpf/rust/call_depth/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Example Rust-based BPF program that tests call depth and stack usage
use solana_program::{custom_panic_default, entrypoint::SUCCESS, log::sol_log_64, msg};
use solana_program::{
custom_heap_default, custom_panic_default, entrypoint::SUCCESS, log::sol_log_64, msg,
};

#[inline(never)]
pub fn recurse(data: &mut [u8]) {
Expand All @@ -26,4 +28,5 @@ pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
SUCCESS
}

custom_heap_default!();
custom_panic_default!();
5 changes: 4 additions & 1 deletion programs/bpf/rust/iter/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! Example Rust-based BPF program tests loop iteration
extern crate solana_program;
use solana_program::{custom_panic_default, entrypoint::SUCCESS, log::sol_log_64};
use solana_program::{
custom_heap_default, custom_panic_default, entrypoint::SUCCESS, log::sol_log_64,
};

#[no_mangle]
pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
Expand All @@ -18,6 +20,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
SUCCESS
}

custom_heap_default!();
custom_panic_default!();

#[cfg(test)]
Expand Down
3 changes: 2 additions & 1 deletion programs/bpf/rust/many_args/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
mod helper;
extern crate solana_program;
use solana_program::{custom_panic_default, entrypoint::SUCCESS, msg};
use solana_program::{custom_heap_default, custom_panic_default, entrypoint::SUCCESS, msg};

#[no_mangle]
pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
Expand All @@ -26,6 +26,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
SUCCESS
}

custom_heap_default!();
custom_panic_default!();

#[cfg(test)]
Expand Down
3 changes: 2 additions & 1 deletion programs/bpf/rust/membuiltins/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
extern crate compiler_builtins;
use {
solana_bpf_rust_mem::{run_mem_tests, MemOps},
solana_program::{custom_panic_default, entrypoint::SUCCESS},
solana_program::{custom_heap_default, custom_panic_default, entrypoint::SUCCESS},
};

#[no_mangle]
Expand Down Expand Up @@ -38,4 +38,5 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
SUCCESS
}

custom_heap_default!();
custom_panic_default!();
5 changes: 4 additions & 1 deletion programs/bpf/rust/param_passing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
extern crate solana_program;
use {
solana_bpf_rust_param_passing_dep::{Data, TestDep},
solana_program::{custom_panic_default, entrypoint::SUCCESS, log::sol_log_64},
solana_program::{
custom_heap_default, custom_panic_default, entrypoint::SUCCESS, log::sol_log_64,
},
};

#[no_mangle]
Expand All @@ -25,6 +27,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
SUCCESS
}

custom_heap_default!();
custom_panic_default!();

#[cfg(test)]
Expand Down
3 changes: 2 additions & 1 deletion programs/bpf/rust/secp256k1_recover/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Secp256k1Recover Syscall test
extern crate solana_program;
use solana_program::{custom_panic_default, msg};
use solana_program::{custom_heap_default, custom_panic_default, msg};

fn test_secp256k1_recover() {
use solana_program::secp256k1_recover::secp256k1_recover;
Expand Down Expand Up @@ -41,4 +41,5 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
0
}

custom_heap_default!();
custom_panic_default!();
3 changes: 2 additions & 1 deletion programs/bpf/rust/sha/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! SHA Syscall test
extern crate solana_program;
use solana_program::{custom_panic_default, msg};
use solana_program::{custom_heap_default, custom_panic_default, msg};

fn test_sha256_hasher() {
use solana_program::hash::{hashv, Hasher};
Expand Down Expand Up @@ -39,6 +39,7 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
0
}

custom_heap_default!();
custom_panic_default!();

#[cfg(test)]
Expand Down
3 changes: 2 additions & 1 deletion programs/bpf/rust/zk_token_elgamal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
extern crate solana_program;
use {
solana_program::{custom_panic_default, msg},
solana_program::{custom_heap_default, custom_panic_default, msg},
solana_zk_token_sdk::zk_token_elgamal::{
ops,
pod::{ElGamalCiphertext, Zeroable},
Expand Down Expand Up @@ -50,4 +50,5 @@ pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
0
}

custom_heap_default!();
custom_panic_default!();
90 changes: 86 additions & 4 deletions programs/bpf/tests/programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use {
},
},
solana_sdk::{
account::{AccountSharedData, ReadableAccount},
account::{AccountSharedData, ReadableAccount, WritableAccount},
account_utils::StateMut,
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
client::SyncClient,
Expand Down Expand Up @@ -226,7 +226,7 @@ fn run_program(name: &str) -> u64 {
&data,
None,
config,
register_syscalls(invoke_context).unwrap(),
register_syscalls(invoke_context, false /* no sol_alloc_free */).unwrap(),
)
.unwrap();
Executable::<BpfError, ThisInstructionMeter>::jit_compile(&mut executable).unwrap();
Expand Down Expand Up @@ -563,6 +563,10 @@ fn test_program_bpf_loader_deprecated() {
.accounts
.remove(&solana_sdk::feature_set::disable_deprecated_loader::id())
.unwrap();
genesis_config
.accounts
.remove(&solana_sdk::feature_set::disable_deploy_of_alloc_free_syscall::id())
.unwrap();
let mut bank = Bank::new_for_tests(&genesis_config);
let (name, id, entrypoint) = solana_bpf_loader_deprecated_program!();
bank.add_builtin(&name, &id, entrypoint);
Expand All @@ -581,6 +585,84 @@ fn test_program_bpf_loader_deprecated() {
}
}

#[test]
fn test_sol_alloc_free_no_longer_deployable() {
solana_logger::setup();

let program_keypair = Keypair::new();
let program_address = program_keypair.pubkey();
let loader_address = bpf_loader_deprecated::id();

let GenesisConfigInfo {
genesis_config,
mint_keypair,
..
} = create_genesis_config(50);
let mut bank = Bank::new_for_tests(&genesis_config);

bank.deactivate_feature(&solana_sdk::feature_set::disable_deprecated_loader::id());
let (name, id, entrypoint) = solana_bpf_loader_deprecated_program!();
bank.add_builtin(&name, &id, entrypoint);

// Populate loader account with elf that depends on _sol_alloc_free syscall
let elf = read_bpf_program("solana_bpf_rust_deprecated_loader");
let mut program_account = AccountSharedData::new(1, elf.len(), &loader_address);
program_account
.data_as_mut_slice()
.get_mut(..)
.unwrap()
.copy_from_slice(&elf);
bank.store_account(&program_address, &program_account);

let finalize_tx = Transaction::new(
&[&mint_keypair, &program_keypair],
Message::new(
&[loader_instruction::finalize(
&program_keypair.pubkey(),
&loader_address,
)],
Some(&mint_keypair.pubkey()),
),
bank.last_blockhash(),
);

let invoke_tx = Transaction::new(
&[&mint_keypair],
Message::new(
&[Instruction::new_with_bytes(
program_address,
&[1],
vec![AccountMeta::new(mint_keypair.pubkey(), true)],
)],
Some(&mint_keypair.pubkey()),
),
bank.last_blockhash(),
);

// Try and deploy a program that depends on _sol_alloc_free
assert_eq!(
bank.process_transaction(&finalize_tx).unwrap_err(),
TransactionError::InstructionError(0, InstructionError::InvalidAccountData)
);

// Enable _sol_alloc_free syscall
bank.deactivate_feature(&solana_sdk::feature_set::disable_deploy_of_alloc_free_syscall::id());
bank.clear_signatures();

// Try and finalize the program now that sol_alloc_free is re-enabled
assert!(bank.process_transaction(&finalize_tx).is_ok());

// invoke the program
assert!(bank.process_transaction(&invoke_tx).is_ok());

// disable _sol_alloc_free
bank.deactivate_feature(&solana_sdk::feature_set::disable_deploy_of_alloc_free_syscall::id());
bank.clear_signatures();

// invoke should still succeed on execute because the program is already deployed
assert!(bank.process_transaction(&invoke_tx).is_ok());
}

#[test]
fn test_program_bpf_duplicate_accounts() {
solana_logger::setup();
Expand Down Expand Up @@ -1437,7 +1519,7 @@ fn assert_instruction_count() {
{
programs.extend_from_slice(&[
("solana_bpf_rust_128bit", 584),
("solana_bpf_rust_alloc", 4459),
("solana_bpf_rust_alloc", 4581),
("solana_bpf_rust_custom_heap", 469),
("solana_bpf_rust_dep_crate", 2),
("solana_bpf_rust_external_spend", 338),
Expand All @@ -1450,7 +1532,7 @@ fn assert_instruction_count() {
("solana_bpf_rust_rand", 429),
("solana_bpf_rust_sanity", 52290),
("solana_bpf_rust_secp256k1_recover", 25707),
("solana_bpf_rust_sha", 25251),
("solana_bpf_rust_sha", 25265),
]);
}

Expand Down
Loading

0 comments on commit 8f1d4c1

Please sign in to comment.