solana-svm 4.2.0-beta.2

Solana SVM
Documentation
//! ELF loader conformance harness.

use {
    crate::conformance::{
        err::elf_error_code,
        fd_hash::{fd_hash_u64_without_seed, fd_hash_without_seed},
        feature_set::feature_set_from_proto,
    },
    prost::Message,
    protosol::protos::{
        ElfLoaderCtx as ProtoElfLoaderCtx, ElfLoaderEffects as ProtoElfLoaderEffects,
    },
    solana_compute_budget::compute_budget::ComputeBudget,
    solana_program_runtime::solana_sbpf::{ebpf, elf::Executable},
    solana_syscalls::create_program_runtime_environment,
    std::{collections::BTreeSet, ffi::c_int},
};

pub fn execute_elf_loader(input: &ProtoElfLoaderCtx) -> ProtoElfLoaderEffects {
    let feature_set = input
        .features
        .as_ref()
        .map(feature_set_from_proto)
        .unwrap_or_default()
        .runtime_features();
    let simd_0268_active = feature_set.raise_cpi_nesting_limit_to_8;
    let compute_budget = ComputeBudget::new_with_defaults(simd_0268_active);

    let program_runtime_environment = create_program_runtime_environment(
        &feature_set,
        &compute_budget.to_budget(),
        input.deploy_checks,
        std::env::var("ENABLE_VM_TRACING").is_ok(),
    )
    .unwrap();

    let executable = match Executable::load(&input.elf_data, (*program_runtime_environment).clone())
    {
        Ok(executable) => executable,
        Err(err) => {
            return ProtoElfLoaderEffects {
                err_code: elf_error_code(&err),
                ..Default::default()
            };
        }
    };

    let (text_vaddr, text_bytes) = executable.get_text_bytes();
    let calldests: Vec<u64> = executable
        .get_function_registry()
        .iter()
        .map(|(_, (_, address))| address as u64)
        .collect::<BTreeSet<_>>()
        .into_iter()
        .collect();

    ProtoElfLoaderEffects {
        err_code: 0,
        rodata_hash: fd_hash_without_seed(executable.get_ro_section()),
        entry_pc: executable.get_entrypoint_instruction_offset() as u64,
        text_off: text_vaddr.saturating_sub(ebpf::MM_BYTECODE_START),
        text_cnt: (text_bytes.len() / 8) as u64,
        calldests_hash: fd_hash_u64_without_seed(&calldests),
    }
}

/// # Safety
///
/// `in_ptr` must point to `in_sz` initialized bytes. `out_ptr` must point
/// to a writable buffer of at least `*out_psz` bytes. On return, `*out_psz`
/// is updated to the number of bytes written.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn sol_compat_elf_loader_v1(
    out_ptr: *mut u8,
    out_psz: *mut u64,
    in_ptr: *mut u8,
    in_sz: u64,
) -> c_int {
    if in_ptr.is_null() || in_sz == 0 {
        return 0;
    }
    if out_psz.is_null() || out_ptr.is_null() {
        return 0;
    }
    let in_slice = unsafe { std::slice::from_raw_parts(in_ptr, in_sz as usize) };
    let Ok(ctx) = ProtoElfLoaderCtx::decode(in_slice) else {
        return 0;
    };

    let effects = execute_elf_loader(&ctx);

    let out_slice = unsafe { std::slice::from_raw_parts_mut(out_ptr, (*out_psz) as usize) };
    let out_vec = effects.encode_to_vec();
    if out_vec.len() > out_slice.len() {
        return 0;
    }
    out_slice[..out_vec.len()].copy_from_slice(&out_vec);
    unsafe { *out_psz = out_vec.len() as u64 };

    1
}

#[cfg(test)]
mod tests {
    use {
        super::*, agave_feature_set::enable_sbpf_v3_deployment_and_execution,
        protosol::protos::FeatureSet as ProtoFeatureSet,
    };

    const NOOP_ALIGNED: &[u8] =
        include_bytes!("../../../programs/bpf_loader/test_elfs/out/noop_aligned.so");
    const NOOP_UNALIGNED: &[u8] =
        include_bytes!("../../../programs/bpf_loader/test_elfs/out/noop_unaligned.so");
    const SBPFV3_RETURN_OK: &[u8] =
        include_bytes!("../../../programs/bpf_loader/test_elfs/out/sbpfv3_return_ok.so");

    fn assert_loads_ok(elf: &[u8], deploy_checks: bool, features: Option<ProtoFeatureSet>) {
        let effects = execute_elf_loader(&ProtoElfLoaderCtx {
            features,
            elf_data: elf.to_vec(),
            deploy_checks,
        });
        assert_eq!(effects.err_code, 0);
        assert!(effects.text_cnt > 0);
    }

    #[test]
    fn test_load_noop_aligned() {
        assert_loads_ok(NOOP_ALIGNED, false, None);
    }

    #[test]
    fn test_load_noop_unaligned_with_deploy_checks() {
        assert_loads_ok(NOOP_UNALIGNED, true, None);
    }

    #[test]
    fn test_load_sbpf_v3_with_feature_enabled() {
        // The v3 ELF only loads when the SBPF v3 feature is active.
        let v3 = enable_sbpf_v3_deployment_and_execution::id();
        let features = ProtoFeatureSet {
            features: vec![u64::from_le_bytes(v3.to_bytes()[..8].try_into().unwrap())],
        };
        assert_loads_ok(SBPFV3_RETURN_OK, false, Some(features));
    }
}