Sandboxing

Rune is capable of enforcing the following types of limitations:

  • Memory limiting, where you specify the maxium amount of memory that Rune may use either during compilation or execution.
  • Instruction budgeting, where you can specify how many instructions the virtual machine is permitted to execute.

Instruction budgeting

Instruction budgeting is performed using the with function in the rune::budget module.

The with function is capable of wrapping functions and futures. When wrapping a future it ensures that the budget is suspended appropriately with the execution of the future.

Budgeting is only performed on a per-instruction basis in the virtual machine. What exactly constitutes an instruction might be a bit vague. But important to note is that without explicit co-operation from native functions the budget cannot be enforced. So care must be taken with the native functions that you provide to Rune to ensure that the limits you impose cannot be circumvented.

Memory limiting

Memory limiting is performed using the with function in the rune::alloc::limit module.

#![allow(unused)]
fn main() {
use rune::alloc::prelude::*;
use rune::alloc::limit;

let f = limit::with(1024, || {
    let mut vec = Vec::<u32>::try_with_capacity(256)?;

    for n in 0..256u32 {
        vec.try_push(n)?;
    }

    Ok::<_, rune_alloc::Error>(vec.into_iter().sum::<u32>())
});

let sum = f.call()?;
assert_eq!(sum, 32640);
}

In order for memory limiting to work as intended, you're may only use the collections provided in the rune::alloc module. These contain forks of popular collections such as std::collections and hashbrown.

The with function is capable of wrapping functions and [futures]. When wrapping a future it ensures that the limit is suspended appropriately with the execution of the future.