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

Add new syscall instruction to the verifier #614

Closed
wants to merge 5 commits into from
Closed
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
3 changes: 2 additions & 1 deletion benches/elf_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extern crate test_utils;

use solana_rbpf::{
elf::Executable,
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry},
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry},
syscalls,
vm::{Config, TestContextObject},
};
Expand All @@ -27,6 +27,7 @@ fn loader() -> Arc<BuiltinProgram<TestContextObject>> {
Arc::new(BuiltinProgram::new_loader(
Config::default(),
function_registry,
SyscallRegistry::default(),
))
}

Expand Down
3 changes: 2 additions & 1 deletion benches/vm_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ extern crate test;
use solana_rbpf::{
ebpf,
memory_region::MemoryRegion,
program::{FunctionRegistry, SBPFVersion},
program::{FunctionRegistry, SBPFVersion, SyscallRegistry},
vm::Config,
};
use solana_rbpf::{
Expand Down Expand Up @@ -88,6 +88,7 @@ fn bench_jit_vs_interpreter(
Arc::new(BuiltinProgram::new_loader(
config,
FunctionRegistry::default(),
SyscallRegistry::default(),
)),
)
.unwrap();
Expand Down
3 changes: 2 additions & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use solana_rbpf::{
ebpf,
elf::Executable,
memory_region::{MemoryMapping, MemoryRegion},
program::{BuiltinProgram, FunctionRegistry},
program::{BuiltinProgram, FunctionRegistry, SyscallRegistry},
static_analysis::Analysis,
verifier::RequisiteVerifier,
vm::{Config, DynamicAnalysis, EbpfVm, TestContextObject},
Expand Down Expand Up @@ -101,6 +101,7 @@ fn main() {
..Config::default()
},
FunctionRegistry::default(),
SyscallRegistry::default(),
));
#[allow(unused_mut)]
let mut executable = match matches.value_of("assembler") {
Expand Down
5 changes: 3 additions & 2 deletions fuzz/fuzz_targets/dumb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use solana_rbpf::{
ebpf,
elf::Executable,
memory_region::MemoryRegion,
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion},
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry, SBPFVersion},
verifier::{RequisiteVerifier, Verifier},
vm::TestContextObject,
};
Expand All @@ -29,7 +29,7 @@ fuzz_target!(|data: DumbFuzzData| {
let prog = data.prog;
let config = data.template.into();
let function_registry = FunctionRegistry::default();
let syscall_registry = FunctionRegistry::<BuiltinFunction<TestContextObject>>::default();
let syscall_registry = SyscallRegistry::<BuiltinFunction<TestContextObject>>::default();

if RequisiteVerifier::verify(&prog, &config, &SBPFVersion::V2, &function_registry, &syscall_registry).is_err() {
// verify please
Expand All @@ -41,6 +41,7 @@ fuzz_target!(|data: DumbFuzzData| {
std::sync::Arc::new(BuiltinProgram::new_loader(
config,
FunctionRegistry::default(),
syscall_registry,
)),
SBPFVersion::V2,
function_registry,
Expand Down
5 changes: 3 additions & 2 deletions fuzz/fuzz_targets/smart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use solana_rbpf::{
elf::Executable,
insn_builder::{Arch, IntoBytes},
memory_region::MemoryRegion,
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion},
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry, SBPFVersion},
verifier::{RequisiteVerifier, Verifier},
vm::TestContextObject,
};
Expand All @@ -33,7 +33,7 @@ fuzz_target!(|data: FuzzData| {
let prog = make_program(&data.prog, data.arch);
let config = data.template.into();
let function_registry = FunctionRegistry::default();
let syscall_registry = FunctionRegistry::<BuiltinFunction<TestContextObject>>::default();
let syscall_registry = SyscallRegistry::<BuiltinFunction<TestContextObject>>::default();

if RequisiteVerifier::verify(
prog.into_bytes(),
Expand All @@ -53,6 +53,7 @@ fuzz_target!(|data: FuzzData| {
std::sync::Arc::new(BuiltinProgram::new_loader(
config,
FunctionRegistry::default(),
syscall_registry,
)),
SBPFVersion::V2,
function_registry,
Expand Down
5 changes: 3 additions & 2 deletions fuzz/fuzz_targets/smart_jit_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use solana_rbpf::{
elf::Executable,
insn_builder::{Arch, Instruction, IntoBytes},
memory_region::MemoryRegion,
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion},
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry, SBPFVersion},
verifier::{RequisiteVerifier, Verifier},
vm::TestContextObject,
};
Expand Down Expand Up @@ -40,7 +40,7 @@ fuzz_target!(|data: FuzzData| {
.push();
let config = data.template.into();
let function_registry = FunctionRegistry::default();
let syscall_registry = FunctionRegistry::<BuiltinFunction<TestContextObject>>::default();
let syscall_registry = SyscallRegistry::<BuiltinFunction<TestContextObject>>::default();

if RequisiteVerifier::verify(
prog.into_bytes(),
Expand All @@ -61,6 +61,7 @@ fuzz_target!(|data: FuzzData| {
std::sync::Arc::new(BuiltinProgram::new_loader(
config,
FunctionRegistry::default(),
syscall_registry,
)),
SBPFVersion::V2,
function_registry,
Expand Down
5 changes: 3 additions & 2 deletions fuzz/fuzz_targets/smarter_jit_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use solana_rbpf::{
elf::Executable,
insn_builder::IntoBytes,
memory_region::MemoryRegion,
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion},
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SyscallRegistry, SBPFVersion},
verifier::{RequisiteVerifier, Verifier},
vm::TestContextObject,
};
Expand All @@ -30,7 +30,7 @@ fuzz_target!(|data: FuzzData| {
let prog = make_program(&data.prog);
let config = data.template.into();
let function_registry = FunctionRegistry::default();
let syscall_registry = FunctionRegistry::<BuiltinFunction<TestContextObject>>::default();
let syscall_registry = SyscallRegistry::<BuiltinFunction<TestContextObject>>::default();

if RequisiteVerifier::verify(
prog.into_bytes(),
Expand All @@ -51,6 +51,7 @@ fuzz_target!(|data: FuzzData| {
std::sync::Arc::new(BuiltinProgram::new_loader(
config,
FunctionRegistry::default(),
syscall_registry,
)),
SBPFVersion::V2,
function_registry,
Expand Down
4 changes: 2 additions & 2 deletions fuzz/fuzz_targets/verify_semantic_aware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use libfuzzer_sys::fuzz_target;
use semantic_aware::*;
use solana_rbpf::{
insn_builder::IntoBytes,
program::{BuiltinFunction, FunctionRegistry, SBPFVersion},
program::{BuiltinFunction, FunctionRegistry, SyscallRegistry, SBPFVersion},
verifier::{RequisiteVerifier, Verifier},
vm::TestContextObject,
};
Expand All @@ -25,7 +25,7 @@ fuzz_target!(|data: FuzzData| {
let prog = make_program(&data.prog);
let config = data.template.into();
let function_registry = FunctionRegistry::default();
let syscall_registry = FunctionRegistry::<BuiltinFunction<TestContextObject>>::default();
let syscall_registry = SyscallRegistry::<BuiltinFunction<TestContextObject>>::default();

RequisiteVerifier::verify(
prog.into_bytes(),
Expand Down
8 changes: 7 additions & 1 deletion src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ pub enum ElfError {
/// Invalid program header
#[error("Invalid ELF program header")]
InvalidProgramHeader,
/// Invalid syscall code
#[error("Invalid syscall code")]
InvalidSyscallCode,
}

impl From<ElfParserError> for ElfError {
Expand Down Expand Up @@ -315,7 +318,7 @@ impl<C: ContextObject> Executable<C> {
self.get_config(),
self.get_sbpf_version(),
self.get_function_registry(),
self.loader.get_function_registry(),
self.loader.get_syscall_registry(),
)?;
Ok(())
}
Expand Down Expand Up @@ -1144,6 +1147,7 @@ pub(crate) fn get_ro_region(ro_section: &Section, elf: &[u8]) -> MemoryRegion {
#[cfg(test)]
mod test {
use super::*;
use crate::program::SyscallRegistry;
use crate::{
elf_parser::{
// FIXME consts::{ELFCLASS32, ELFDATA2MSB, ET_REL},
Expand Down Expand Up @@ -1174,6 +1178,7 @@ mod test {
Arc::new(BuiltinProgram::new_loader(
Config::default(),
function_registry,
SyscallRegistry::default(),
))
}

Expand Down Expand Up @@ -1929,6 +1934,7 @@ mod test {
..Config::default()
},
FunctionRegistry::default(),
SyscallRegistry::default(),
);
let elf_bytes = std::fs::read("tests/elfs/syscall_reloc_64_32_sbpfv1.so")
.expect("failed to read elf file");
Expand Down
7 changes: 5 additions & 2 deletions src/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1696,7 +1696,9 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
mod tests {
use super::*;
use crate::{
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion},
program::{
BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion, SyscallRegistry,
},
syscalls,
vm::TestContextObject,
};
Expand Down Expand Up @@ -1748,7 +1750,8 @@ mod tests {
function_registry
.register_function_hashed(*b"gather_bytes", syscalls::SyscallGatherBytes::vm)
.unwrap();
let loader = BuiltinProgram::new_loader(config, function_registry);
let syscall_registry = SyscallRegistry::default();
let loader = BuiltinProgram::new_loader(config, function_registry, syscall_registry);
let mut function_registry = FunctionRegistry::default();
function_registry
.register_function(8, *b"function_foo", 8)
Expand Down
89 changes: 84 additions & 5 deletions src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,40 @@ impl<T: Copy + PartialEq> FunctionRegistry<T> {
}
}

/// A registry to operate with static syscalls represented by integers.
#[derive(PartialEq, Eq)]
pub struct SyscallRegistry<T> {
look_up: Vec<(Vec<u8>, T)>,
}

impl<T: Copy + PartialEq> Default for SyscallRegistry<T> {
fn default() -> Self {
SyscallRegistry::new(Vec::new())
}
}

impl<T: Copy + PartialEq> SyscallRegistry<T> {
/// Create a new registry based on a previously created vector of registrations.
/// We expect the vector to be dense, containing one function per position.
pub fn new(registry: Vec<(Vec<u8>, T)>) -> Self {
SyscallRegistry { look_up: registry }
}

/// Retrieve a syscall from the registry
pub fn lookup_syscall(&self, code: usize) -> Result<(&[u8], T), ElfError> {
if code == 0 {
return Err(ElfError::InvalidSyscallCode);
}

self.look_up
.get(code.saturating_sub(1))
.as_ref()
.map_or(Err(ElfError::InvalidSyscallCode), |(name, value)| {
Ok((name.as_slice(), *value))
})
}
}

/// Syscall function without context
pub type BuiltinFunction<C> = fn(*mut EbpfVm<C>, u64, u64, u64, u64, u64);

Expand All @@ -226,6 +260,8 @@ pub struct BuiltinProgram<C: ContextObject> {
config: Option<Box<Config>>,
/// Function pointers by symbol
functions: FunctionRegistry<BuiltinFunction<C>>,
/// Syscalls registry for this loader
syscalls: SyscallRegistry<BuiltinFunction<C>>,
}

impl<C: ContextObject> PartialEq for BuiltinProgram<C> {
Expand All @@ -236,18 +272,27 @@ impl<C: ContextObject> PartialEq for BuiltinProgram<C> {

impl<C: ContextObject> BuiltinProgram<C> {
/// Constructs a loader built-in program
pub fn new_loader(config: Config, functions: FunctionRegistry<BuiltinFunction<C>>) -> Self {
pub fn new_loader(
config: Config,
functions: FunctionRegistry<BuiltinFunction<C>>,
syscalls: SyscallRegistry<BuiltinFunction<C>>,
) -> Self {
Self {
config: Some(Box::new(config)),
functions,
syscalls,
}
}

/// Constructs a built-in program
pub fn new_builtin(functions: FunctionRegistry<BuiltinFunction<C>>) -> Self {
pub fn new_builtin(
functions: FunctionRegistry<BuiltinFunction<C>>,
syscalls: SyscallRegistry<BuiltinFunction<C>>,
) -> Self {
Self {
config: None,
functions,
syscalls,
}
}

Expand All @@ -256,6 +301,7 @@ impl<C: ContextObject> BuiltinProgram<C> {
Self {
config: Some(Box::default()),
functions: FunctionRegistry::default(),
syscalls: SyscallRegistry::default(),
}
}

Expand All @@ -269,6 +315,11 @@ impl<C: ContextObject> BuiltinProgram<C> {
&self.functions
}

/// Get the syscall registry
pub fn get_syscall_registry(&self) -> &SyscallRegistry<BuiltinFunction<C>> {
&self.syscalls
}

/// Calculate memory size
pub fn mem_size(&self) -> usize {
std::mem::size_of::<Self>()
Expand Down Expand Up @@ -378,10 +429,38 @@ mod tests {
function_registry_c
.register_function_hashed(*b"log_64", syscalls::SyscallU64::vm)
.unwrap();
let builtin_program_a = BuiltinProgram::new_loader(Config::default(), function_registry_a);
let builtin_program_b = BuiltinProgram::new_loader(Config::default(), function_registry_b);
let builtin_program_a = BuiltinProgram::new_loader(
Config::default(),
function_registry_a,
SyscallRegistry::default(),
);
let builtin_program_b = BuiltinProgram::new_loader(
Config::default(),
function_registry_b,
SyscallRegistry::default(),
);
assert_eq!(builtin_program_a, builtin_program_b);
let builtin_program_c = BuiltinProgram::new_loader(Config::default(), function_registry_c);
let builtin_program_c = BuiltinProgram::new_loader(
Config::default(),
function_registry_c,
SyscallRegistry::default(),
);
assert_ne!(builtin_program_a, builtin_program_c);
}

#[test]
fn test_syscall_registry() {
let registry_vec: Vec<(Vec<u8>, BuiltinFunction<TestContextObject>)> =
vec![(b"log".to_vec(), syscalls::SyscallString::vm)];
let registry = SyscallRegistry::<BuiltinFunction<TestContextObject>>::new(registry_vec);

let lookup_result = registry.lookup_syscall(0);
assert_eq!(lookup_result.err().unwrap(), ElfError::InvalidSyscallCode);

let lookup_result = registry.lookup_syscall(3);
assert_eq!(lookup_result.err().unwrap(), ElfError::InvalidSyscallCode);

let lookup_result = registry.lookup_syscall(1);
assert!(lookup_result.is_ok());
}
}
Loading