Skip to content

Commit

Permalink
Check if syscall is valid during verification
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasSte committed Sep 5, 2024
1 parent de52d05 commit 44f33fc
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ impl<C: ContextObject> Executable<C> {
self.get_config(),
self.get_sbpf_version(),
self.get_function_registry(),
self.loader.get_function_registry(),
)?;
Ok(())
}
Expand Down
20 changes: 13 additions & 7 deletions src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
use crate::{
ebpf,
program::{FunctionRegistry, SBPFVersion},
vm::Config,
program::{BuiltinFunction, FunctionRegistry, SBPFVersion},
vm::{Config, ContextObject},
};
use thiserror::Error;

Expand Down Expand Up @@ -85,11 +85,12 @@ pub trait Verifier {
/// - Unknown instructions.
/// - Bad formed instruction.
/// - Unknown eBPF syscall index.
fn verify(
fn verify<C: ContextObject>(
prog: &[u8],
config: &Config,
sbpf_version: &SBPFVersion,
function_registry: &FunctionRegistry<usize>,
sysvar_registry: &FunctionRegistry<BuiltinFunction<C>>,
) -> Result<(), VerifierError>;
}

Expand Down Expand Up @@ -153,10 +154,14 @@ fn check_jmp_offset(
Ok(())
}

fn check_call_target(
fn check_call_target<T>(
key: u32,
function_registry: &FunctionRegistry<usize>,
) -> Result<(), VerifierError> {
function_registry: &FunctionRegistry<T>,
) -> Result<(), VerifierError>
where
T: Copy,
T: PartialEq,
{
function_registry
.lookup_by_key(key)
.map(|_| ())
Expand Down Expand Up @@ -216,7 +221,7 @@ pub struct RequisiteVerifier {}
impl Verifier for RequisiteVerifier {
/// Check the program against the verifier's rules
#[rustfmt::skip]
fn verify(prog: &[u8], config: &Config, sbpf_version: &SBPFVersion, function_registry: &FunctionRegistry<usize>) -> Result<(), VerifierError> {
fn verify<C: ContextObject>(prog: &[u8], config: &Config, sbpf_version: &SBPFVersion, function_registry: &FunctionRegistry<usize>, sysvar_registry: &FunctionRegistry<BuiltinFunction<C>>) -> Result<(), VerifierError> {
check_prog_len(prog)?;

let program_range = 0..prog.len() / ebpf::INSN_SIZE;
Expand Down Expand Up @@ -371,6 +376,7 @@ impl Verifier for RequisiteVerifier {
ebpf::JSLE_IMM => { check_jmp_offset(prog, insn_ptr, &function_range)?; },
ebpf::JSLE_REG => { check_jmp_offset(prog, insn_ptr, &function_range)?; },
ebpf::CALL_IMM if sbpf_version.static_syscalls() && insn.src != 0 => { check_call_target(insn.imm as u32, function_registry)?; },
ebpf::CALL_IMM if sbpf_version.static_syscalls() && insn.src == 0 => { check_call_target(insn.imm as u32, sysvar_registry)?; },
ebpf::CALL_IMM => {},
ebpf::CALL_REG => { check_callx_register(&insn, insn_ptr, config, sbpf_version)?; },
ebpf::EXIT => {},
Expand Down
51 changes: 47 additions & 4 deletions tests/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ use solana_rbpf::{
assembler::assemble,
ebpf,
elf::Executable,
program::{BuiltinProgram, FunctionRegistry, SBPFVersion},
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry, SBPFVersion},
syscalls,
verifier::{RequisiteVerifier, Verifier, VerifierError},
vm::{Config, TestContextObject},
vm::{Config, ContextObject, TestContextObject},
};
use std::sync::Arc;
use test_utils::{assert_error, create_vm};
Expand All @@ -43,23 +44,25 @@ pub enum VerifierTestError {

struct TautologyVerifier {}
impl Verifier for TautologyVerifier {
fn verify(
fn verify<C: ContextObject>(
_prog: &[u8],
_config: &Config,
_sbpf_version: &SBPFVersion,
_function_registry: &FunctionRegistry<usize>,
_syvar_registry: &FunctionRegistry<BuiltinFunction<C>>,
) -> std::result::Result<(), VerifierError> {
Ok(())
}
}

struct ContradictionVerifier {}
impl Verifier for ContradictionVerifier {
fn verify(
fn verify<C: ContextObject>(
_prog: &[u8],
_config: &Config,
_sbpf_version: &SBPFVersion,
_function_registry: &FunctionRegistry<usize>,
_sysvar_registry: &FunctionRegistry<BuiltinFunction<C>>,
) -> std::result::Result<(), VerifierError> {
Err(VerifierError::NoProgram)
}
Expand Down Expand Up @@ -299,6 +302,46 @@ fn test_verifier_err_unknown_opcode() {
executable.verify::<RequisiteVerifier>().unwrap();
}

#[test]
#[should_panic(expected = "InvalidFunction(1811268606)")]
fn test_verifier_unknown_sycall() {
let prog = &[
0x85, 0x00, 0x00, 0x00, 0xfe, 0xc3, 0xf5, 0x6b, // call 0x6bf5c3fe
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
];
let executable = Executable::<TestContextObject>::from_text_bytes(
prog,
Arc::new(BuiltinProgram::new_mock()),
SBPFVersion::V2,
FunctionRegistry::default(),
)
.unwrap();
executable.verify::<RequisiteVerifier>().unwrap();
}

#[test]
fn test_verifier_known_syscall() {
let prog = &[
0x85, 0x00, 0x00, 0x00, 0xfe, 0xc3, 0xf5, 0x6b, // call 0x6bf5c3fe
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
];
let mut function_registry = FunctionRegistry::<BuiltinFunction<TestContextObject>>::default();
function_registry
.register_function(0x6bf5c3fe, b"my_syscall", syscalls::SyscallString::vm)
.unwrap();
let executable = Executable::<TestContextObject>::from_text_bytes(
prog,
Arc::new(BuiltinProgram::new_loader(
Config::default(),
function_registry,
)),
SBPFVersion::V2,
FunctionRegistry::default(),
)
.unwrap();
executable.verify::<RequisiteVerifier>().unwrap();
}

#[test]
#[should_panic(expected = "CannotWriteR10(0)")]
fn test_verifier_err_write_r10() {
Expand Down

0 comments on commit 44f33fc

Please sign in to comment.