Struct rbpf::EbpfVmNoData

source ·
pub struct EbpfVmNoData<'a> { /* private fields */ }
Expand description

A virtual machine to run eBPF program. This kind of VM is used for programs that do not work with any memory area—no metadata buffer, no packet data either.

Examples

let prog = &[
    0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
    0xb7, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // mov r1, 1
    0xb7, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, // mov r2, 2
    0xb7, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // mov r3, 3
    0xb7, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, // mov r4, 4
    0xb7, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, // mov r5, 5
    0xb7, 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, // mov r6, 6
    0xb7, 0x07, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, // mov r7, 7
    0xb7, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, // mov r8, 8
    0x4f, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // or r0, r5
    0x47, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, // or r0, 0xa0
    0x57, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, // and r0, 0xa3
    0xb7, 0x09, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, // mov r9, 0x91
    0x5f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // and r0, r9
    0x67, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // lsh r0, 32
    0x67, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, // lsh r0, 22
    0x6f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // lsh r0, r8
    0x77, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, // rsh r0, 32
    0x77, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, // rsh r0, 19
    0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // rsh r0, r7
    0xa7, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, // xor r0, 0x03
    0xaf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xor r0, r2
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
];

// Instantiate a VM.
let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();

// Provide only a reference to the packet data.
let res = vm.execute_program().unwrap();
assert_eq!(res, 0x11);

Implementations

Create a new virtual machine instance, and load an eBPF program into that instance. When attempting to load the program, it passes through a simple verifier.

Examples
let prog = &[
    0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
    0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
];

// Instantiate a VM.
let vm = rbpf::EbpfVmNoData::new(Some(prog));

Load a new eBPF program into the virtual machine instance.

Examples
let prog1 = &[
    0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
];
let prog2 = &[
    0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
    0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
];

let mut vm = rbpf::EbpfVmNoData::new(Some(prog1)).unwrap();

let res = vm.execute_program().unwrap();
assert_eq!(res, 0x2211);

vm.set_program(prog2);

let res = vm.execute_program().unwrap();
assert_eq!(res, 0x1122);

Set a new verifier function. The function should return an Error if the program should be rejected by the virtual machine. If a program has been loaded to the VM already, the verifier is immediately run.

Examples
use std::io::{Error, ErrorKind};
use rbpf::ebpf;

// Define a simple verifier function.
fn verifier(prog: &[u8]) -> Result<(), Error> {
    let last_insn = ebpf::get_insn(prog, (prog.len() / ebpf::INSN_SIZE) - 1);
    if last_insn.opc != ebpf::EXIT {
        return Err(Error::new(ErrorKind::Other,
                   "[Verifier] Error: program does not end with “EXIT” instruction"));
    }
    Ok(())
}

let prog1 = &[
    0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r0, 0
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
];

// Instantiate a VM.
let mut vm = rbpf::EbpfVmMbuff::new(Some(prog1)).unwrap();
// Change the verifier.
vm.set_verifier(verifier).unwrap();

Register a built-in or user-defined helper function in order to use it later from within the eBPF program. The helper is registered into a hashmap, so the key can be any u32.

If using JIT-compiled eBPF programs, be sure to register all helpers before compiling the program. You should be able to change registered helpers after compiling, but not to add new ones (i.e. with new keys).

Examples
use rbpf::helpers;

let prog = &[
    0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // mov r1, 0x010000000
    0xb7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r2, 0
    0xb7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r3, 0
    0xb7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r4, 0
    0xb7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r5, 0
    0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // call helper with key 1
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
];

let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();

// Register a helper. This helper will store the result of the square root of r1 into r0.
vm.register_helper(1, helpers::sqrti).unwrap();

let res = vm.execute_program().unwrap();
assert_eq!(res, 0x1000);

JIT-compile the loaded program. No argument required for this.

If using helper functions, be sure to register them into the VM before calling this function.

Examples
let prog = &[
    0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
    0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
];

let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();


vm.jit_compile();

Execute the program loaded, without providing pointers to any memory area whatsoever.

Examples
let prog = &[
    0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
    0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
];

let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();

// For this kind of VM, the `execute_program()` function needs no argument.
let res = vm.execute_program().unwrap();
assert_eq!(res, 0x1122);

Execute the previously JIT-compiled program, without providing pointers to any memory area whatsoever, in a manner very similar to execute_program().

Safety

WARNING: JIT-compiled assembly code is not safe, in particular there is no runtime check for memory access; so if the eBPF program attempts erroneous accesses, this may end very bad (program may segfault). It may be wise to check that the program works with the interpreter before running the JIT-compiled version of it.

For this reason the function should be called from within an unsafe bloc.

Examples
let prog = &[
    0xb7, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00, 0x00, // mov r0, 0x2211
    0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, // be16 r0
    0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // exit
];

let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();

vm.jit_compile();

unsafe {
    let res = vm.execute_program_jit().unwrap();
    assert_eq!(res, 0x1122);
}

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.