Crates.io | embive |
lib.rs | embive |
version | 0.1.0 |
source | src |
created_at | 2024-11-17 03:30:11.649456 |
updated_at | 2024-11-22 23:33:01.759486 |
description | A low-level sandboxing library for RISC-V bytecode |
homepage | |
repository | https://github.com/embive/embive |
max_upload_size | |
id | 1450874 |
size | 430,828 |
Embive is a low-level sandboxing library focused on the embedding of untrusted code for constrained environments.
As it interprets RISC-V bytecode, multiple languages are supported out of the box by Embive (Rust, C, C++, Zig, TinyGo, etc.).
By default, it doesn’t require external crates, dynamic memory allocation or the standard library (no_std
& no_alloc
).
Embive is designed for any error during execution to be recoverable, allowing the host to handle it as needed. As so, no panics should occur on release builds, despite the bytecode being executed.
Currently, it supports the RV32I[M]
unprivileged instruction set (M extension enabled by default).
The following templates are available for programs that run inside Embive:
use embive::{engine::{Engine, Config, SYSCALL_ARGS}, memory::Memory, register::Register};
/// A simple syscall example. Check [`engine::SyscallFn`] for more information.
fn syscall(nr: i32, args: &[i32; SYSCALL_ARGS], memory: &mut Memory) -> Result<i32, i32> {
println!("Syscall nr: {}, Args: {:?}", nr, args);
match nr {
1 => Ok(args[0] + args[1]), // Add two numbers (arg[0] + arg[1])
2 => match memory.load(args[0] as u32) { // Load from RAM (arg[0])
Ok(val) => Ok(i32::from_le_bytes(val)), // RISC-V is little endian
Err(_) => Err(1),
},
_ => Err(2),
}
}
fn main() {
// "10 + 20" using syscalls (load from ram and add two numbers)
let code = &[
0x93, 0x08, 0x20, 0x00, // li a7, 2 (Syscall nr = 2)
0x13, 0x05, 0x10, 0x00, // li a0, 1 (a0 = 1)
0x13, 0x15, 0xf5, 0x01, // slli a0, a0, 31 (a0 << 31) (0x80000000)
0x73, 0x00, 0x00, 0x00, // ecall (Syscall, load from arg0)
0x93, 0x08, 0x10, 0x00, // li a7, 1 (Syscall nr = 1)
0x13, 0x05, 0x40, 0x01, // li a0,20 (a0 = 20)
0x73, 0x00, 0x00, 0x00, // ecall (Syscall, add two args)
0x73, 0x00, 0x10, 0x00 // ebreak (Halt)
];
let mut ram = [0; 1024];
// Store value 10 at RAM address 0 (0x80000000)
ram[..4].copy_from_slice(&u32::to_le_bytes(10));
// Create engine config
let config = Config {
syscall_fn: Some(syscall),
..Default::default()
};
// Create engine
let mut engine = Engine::new(code, &mut ram, config).unwrap();
// Run it
engine.run().unwrap();
// Check the result
assert_eq!(engine.registers().get(Register::A0 as usize).unwrap(), 0);
assert_eq!(engine.registers().get(Register::A1 as usize).unwrap(), 30);
}
RV32G
(RV32IMAFDZicsr_Zifencei)
i32
arguments / resultsThis is a maybe, but good to keep in mind while developing other features (especially AOT/JIT).
Embive is guaranteed to compile on stable Rust 1.81 and up.
Embive is licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.