From 9f6496d38ad3ea6b034777af60a414ebd10f2dd0 Mon Sep 17 00:00:00 2001 From: Jack May Date: Mon, 10 Jun 2019 11:00:15 -0700 Subject: [PATCH] Panic filename (#4625) automerge --- programs/bpf/build.rs | 2 +- programs/bpf/rust/alloc/Xargo.toml | 2 - programs/bpf/rust/alloc/src/lib.rs | 3 +- programs/bpf/rust/iter/Xargo.toml | 2 - programs/bpf/rust/iter/src/lib.rs | 2 +- programs/bpf/rust/noop/Xargo.toml | 2 - programs/bpf/rust/panic/.gitignore | 3 ++ programs/bpf/rust/panic/Cargo.toml | 22 ++++++++++ programs/bpf/rust/panic/Xargo.toml | 6 +++ programs/bpf/rust/panic/src/lib.rs | 10 +++++ programs/bpf/tests/programs.rs | 46 +++++++++++---------- programs/bpf_loader/src/lib.rs | 66 +++++++++++++++++++----------- sdk/bpf/rust-utils/src/panic.rs | 38 ++++++++--------- 13 files changed, 129 insertions(+), 75 deletions(-) create mode 100644 programs/bpf/rust/panic/.gitignore create mode 100644 programs/bpf/rust/panic/Cargo.toml create mode 100644 programs/bpf/rust/panic/Xargo.toml create mode 100644 programs/bpf/rust/panic/src/lib.rs diff --git a/programs/bpf/build.rs b/programs/bpf/build.rs index d08337cf9c..ce5b2ea4fb 100644 --- a/programs/bpf/build.rs +++ b/programs/bpf/build.rs @@ -67,7 +67,7 @@ fn main() { .expect("Unable to create BPF install directory") .success()); - let rust_programs = ["alloc", "iter", "noop"]; + let rust_programs = ["alloc", "iter", "noop", "panic"]; for program in rust_programs.iter() { println!( "cargo:warning=(not a warning) Building Rust-based BPF programs: solana_bpf_rust_{}", diff --git a/programs/bpf/rust/alloc/Xargo.toml b/programs/bpf/rust/alloc/Xargo.toml index c2898d9b0d..480d86ea29 100644 --- a/programs/bpf/rust/alloc/Xargo.toml +++ b/programs/bpf/rust/alloc/Xargo.toml @@ -1,5 +1,3 @@ - - [dependencies.compiler_builtins] path = "../../../../sdk/bpf/rust-bpf-sysroot/src/compiler-builtins" features = ["c", "mem"] diff --git a/programs/bpf/rust/alloc/src/lib.rs b/programs/bpf/rust/alloc/src/lib.rs index b7ad7f8c25..6ff692c6f9 100644 --- a/programs/bpf/rust/alloc/src/lib.rs +++ b/programs/bpf/rust/alloc/src/lib.rs @@ -1,5 +1,4 @@ -//! @brief Example Rust-based BPF program that prints out the parameters passed to it - +//! @brief Example Rust-based BPF program that test dynamic memory allocation #![no_std] #[macro_use] diff --git a/programs/bpf/rust/iter/Xargo.toml b/programs/bpf/rust/iter/Xargo.toml index c2898d9b0d..480d86ea29 100644 --- a/programs/bpf/rust/iter/Xargo.toml +++ b/programs/bpf/rust/iter/Xargo.toml @@ -1,5 +1,3 @@ - - [dependencies.compiler_builtins] path = "../../../../sdk/bpf/rust-bpf-sysroot/src/compiler-builtins" features = ["c", "mem"] diff --git a/programs/bpf/rust/iter/src/lib.rs b/programs/bpf/rust/iter/src/lib.rs index 86aa918911..478d403128 100644 --- a/programs/bpf/rust/iter/src/lib.rs +++ b/programs/bpf/rust/iter/src/lib.rs @@ -1,4 +1,4 @@ -//! @brief Example Rust-based BPF program that prints out the parameters passed to it +//! @brief Example Rust-based BPF program tests loop iteration #![no_std] diff --git a/programs/bpf/rust/noop/Xargo.toml b/programs/bpf/rust/noop/Xargo.toml index c2898d9b0d..480d86ea29 100644 --- a/programs/bpf/rust/noop/Xargo.toml +++ b/programs/bpf/rust/noop/Xargo.toml @@ -1,5 +1,3 @@ - - [dependencies.compiler_builtins] path = "../../../../sdk/bpf/rust-bpf-sysroot/src/compiler-builtins" features = ["c", "mem"] diff --git a/programs/bpf/rust/panic/.gitignore b/programs/bpf/rust/panic/.gitignore new file mode 100644 index 0000000000..e13de17f65 --- /dev/null +++ b/programs/bpf/rust/panic/.gitignore @@ -0,0 +1,3 @@ +/target/ + +Cargo.lock diff --git a/programs/bpf/rust/panic/Cargo.toml b/programs/bpf/rust/panic/Cargo.toml new file mode 100644 index 0000000000..bfc2ddb9bc --- /dev/null +++ b/programs/bpf/rust/panic/Cargo.toml @@ -0,0 +1,22 @@ + +# Note: This crate must be built using build.sh + +[package] +name = "solana-bpf-rust-panic" +version = "0.15.0" +description = "Solana BPF iter program written in Rust" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +license = "Apache-2.0" +homepage = "https://solana.com/" +edition = "2018" + +[dependencies] +solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust-utils", version = "0.16.0" } + +[workspace] +members = [] + +[lib] +name = "solana_bpf_rust_panic" +crate-type = ["cdylib"] diff --git a/programs/bpf/rust/panic/Xargo.toml b/programs/bpf/rust/panic/Xargo.toml new file mode 100644 index 0000000000..480d86ea29 --- /dev/null +++ b/programs/bpf/rust/panic/Xargo.toml @@ -0,0 +1,6 @@ +[dependencies.compiler_builtins] +path = "../../../../sdk/bpf/rust-bpf-sysroot/src/compiler-builtins" +features = ["c", "mem"] + +[target.bpfel-unknown-unknown.dependencies] +alloc = { path = "../../../../sdk/bpf/rust-bpf-sysroot/src/liballoc" } \ No newline at end of file diff --git a/programs/bpf/rust/panic/src/lib.rs b/programs/bpf/rust/panic/src/lib.rs new file mode 100644 index 0000000000..2c7af75dbb --- /dev/null +++ b/programs/bpf/rust/panic/src/lib.rs @@ -0,0 +1,10 @@ +//! @brief Example Rust-based BPF program that panics + +#![no_std] + +extern crate solana_sdk_bpf_utils; + +#[no_mangle] +pub extern "C" fn entrypoint(_input: *mut u8) -> bool { + panic!(); +} diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 788091c957..1a45a6132e 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -41,15 +41,15 @@ mod bpf { let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); - let (genesis_block, alice_keypair) = create_genesis_block(50); + let (genesis_block, mint_keypair) = create_genesis_block(50); let bank = Bank::new(&genesis_block); let bank_client = BankClient::new(bank); // Call user program - let program_id = load_program(&bank_client, &alice_keypair, &bpf_loader::id(), elf); - let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8); + let program_id = load_program(&bank_client, &mint_keypair, &bpf_loader::id(), elf); + let instruction = create_invoke_instruction(mint_keypair.pubkey(), program_id, &1u8); bank_client - .send_instruction(&alice_keypair, instruction) + .send_instruction(&mint_keypair, instruction) .unwrap(); } @@ -72,23 +72,23 @@ mod bpf { let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); - let (genesis_block, alice_keypair) = create_genesis_block(50); + let (genesis_block, mint_keypair) = create_genesis_block(50); let bank = Bank::new(&genesis_block); let bank_client = BankClient::new(bank); let loader_pubkey = load_program( &bank_client, - &alice_keypair, + &mint_keypair, &native_loader::id(), "solana_bpf_loader".as_bytes().to_vec(), ); // Call user program - let program_id = load_program(&bank_client, &alice_keypair, &loader_pubkey, elf); + let program_id = load_program(&bank_client, &mint_keypair, &loader_pubkey, elf); let instruction = - create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8); + create_invoke_instruction(mint_keypair.pubkey(), program_id, &1u8); bank_client - .send_instruction(&alice_keypair, instruction) + .send_instruction(&mint_keypair, instruction) .unwrap(); } } @@ -107,38 +107,42 @@ mod bpf { solana_logger::setup(); let programs = [ - "solana_bpf_rust_alloc", - "solana_bpf_rust_iter", - "solana_bpf_rust_noop", + ("solana_bpf_rust_alloc", true), + ("solana_bpf_rust_iter", true), + ("solana_bpf_rust_noop", true), + ("solana_bpf_rust_panic", false), ]; for program in programs.iter() { - let filename = create_bpf_path(program); - println!("Test program: {:?} from {:?}", program, filename); + let filename = create_bpf_path(program.0); + println!("Test program: {:?} from {:?}", program.0, filename); let mut file = File::open(filename).unwrap(); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); - let (genesis_block, alice_keypair) = create_genesis_block(50); + let (genesis_block, mint_keypair) = create_genesis_block(50); let bank = Bank::new(&genesis_block); let bank_client = BankClient::new(bank); let loader_pubkey = load_program( &bank_client, - &alice_keypair, + &mint_keypair, &native_loader::id(), "solana_bpf_loader".as_bytes().to_vec(), ); // Call user program - let program_id = load_program(&bank_client, &alice_keypair, &loader_pubkey, elf); + let program_id = load_program(&bank_client, &mint_keypair, &loader_pubkey, elf); let account_metas = vec![ - AccountMeta::new(alice_keypair.pubkey(), true), + AccountMeta::new(mint_keypair.pubkey(), true), AccountMeta::new(Keypair::new().pubkey(), false), ]; let instruction = Instruction::new(program_id, &1u8, account_metas); - bank_client - .send_instruction(&alice_keypair, instruction) - .unwrap(); + let result = bank_client.send_instruction(&mint_keypair, instruction); + if program.1 { + assert!(result.is_ok()); + } else { + assert!(result.is_err()); + } } } } diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 47ad938cf5..763bea64a1 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -37,7 +37,31 @@ use allocator_bump::BPFAllocator; /// are expected to enforce this const DEFAULT_HEAP_SIZE: usize = 32 * 1024; +/// Verifies a string passed out of the program +fn verify_string(addr: u64, ro_regions: &[MemoryRegion]) -> Result<(()), Error> { + for region in ro_regions.iter() { + if region.addr <= addr && (addr as u64) < region.addr + region.len { + let c_buf: *const c_char = addr as *const c_char; + let max_size = region.addr + region.len - addr; + unsafe { + for i in 0..max_size { + if std::ptr::read(c_buf.offset(i as isize)) == 0 { + return Ok(()); + } + } + } + return Err(Error::new(ErrorKind::Other, "Error, Unterminated string")); + } + } + Err(Error::new( + ErrorKind::Other, + "Error: Load segfault, bad string pointer", + )) +} + /// Abort helper functions, called when the BPF program calls `abort()` +/// The verify function returns an error which will cause the BPF program +/// to be halted immediately pub fn helper_abort_verify( _arg1: u64, _arg2: u64, @@ -69,16 +93,29 @@ pub fn helper_abort( /// The verify function returns an error which will cause the BPF program /// to be halted immediately pub fn helper_sol_panic_verify( - _arg1: u64, - _arg2: u64, - _arg3: u64, + file: u64, + line: u64, + column: u64, _arg4: u64, _arg5: u64, _context: &mut Option>, - _ro_regions: &[MemoryRegion], + ro_regions: &[MemoryRegion], _rw_regions: &[MemoryRegion], ) -> Result<(()), Error> { - Err(Error::new(ErrorKind::Other, "Error: BPF program Panic!")) + if verify_string(file, ro_regions).is_ok() { + let c_buf: *const c_char = file as *const c_char; + let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) }; + if let Ok(slice) = c_str.to_str() { + return Err(Error::new( + ErrorKind::Other, + format!( + "Error: BPF program Panicked at {}, {}:{}", + slice, line, column + ), + )); + } + } + Err(Error::new(ErrorKind::Other, "Error: BPF program Panicked")) } pub fn helper_sol_panic( _arg1: u64, @@ -105,24 +142,7 @@ pub fn helper_sol_log_verify( ro_regions: &[MemoryRegion], _rw_regions: &[MemoryRegion], ) -> Result<(()), Error> { - for region in ro_regions.iter() { - if region.addr <= addr && (addr as u64) < region.addr + region.len { - let c_buf: *const c_char = addr as *const c_char; - let max_size = region.addr + region.len - addr; - unsafe { - for i in 0..max_size { - if std::ptr::read(c_buf.offset(i as isize)) == 0 { - return Ok(()); - } - } - } - return Err(Error::new(ErrorKind::Other, "Error, Unterminated string")); - } - } - Err(Error::new( - ErrorKind::Other, - "Error: Load segfault, bad string pointer", - )) + verify_string(addr, ro_regions) } pub fn helper_sol_log( addr: u64, diff --git a/sdk/bpf/rust-utils/src/panic.rs b/sdk/bpf/rust-utils/src/panic.rs index 681a549020..fddc6aa980 100644 --- a/sdk/bpf/rust-utils/src/panic.rs +++ b/sdk/bpf/rust-utils/src/panic.rs @@ -1,36 +1,32 @@ //! @brief Solana Rust-based BPF program panic handling use crate::log::*; +use core::fmt::{self, Write}; use core::panic::PanicInfo; #[cfg(not(test))] #[panic_handler] fn panic(info: &PanicInfo) -> ! { - sol_log("Panic!"); - // TODO crashes! sol_log(_info.payload().downcast_ref::<&str>().unwrap()); - if let Some(location) = info.location() { - if !location.file().is_empty() { - // TODO location.file() returns empty str, if we get here its been fixed - sol_log(location.file()); - sol_log("location.file() is fixed!!"); + match info.location() { + Some(location) => { + let mut file: [u8; 128] = [0; 128]; + for (i, c) in location.file().as_bytes().iter().enumerate() { + if i >= 126 { + break; + } + file[i] = *c; + } unsafe { - sol_panic_(); + sol_panic_( + file.as_ptr(), + u64::from(location.line()), + u64::from(location.column()), + ); } } - sol_log_64( - 0, - 0, - 0, - u64::from(location.line()), - u64::from(location.column()), - ); - } else { - sol_log("Panic!, but could not get location information"); - } - unsafe { - sol_panic_(); + None => unsafe { sol_panic_(0 as *const u8, 0, 0) }, } } extern "C" { - pub fn sol_panic_() -> !; + pub fn sol_panic_(message: *const u8, line: u64, column: u64) -> !; }