1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
use crate::{host, LunaticError};
/// Process configurations determine permissions of processes.
///
/// The functions `spawn_config` & `spawn_link_config` can be used to create
/// processes with a specific configuration.
pub struct ProcessConfig(ProcessConfigType);
enum ProcessConfigType {
/// ID of a configuration held by the host as a resource.
Config(u64),
/// Indicates that the configuration should be inherited from the parent
/// process.
Inherit,
}
impl Drop for ProcessConfigType {
fn drop(&mut self) {
match self {
ProcessConfigType::Config(id) => unsafe { host::api::process::drop_config(*id) },
ProcessConfigType::Inherit => (),
}
}
}
impl std::fmt::Debug for ProcessConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
ProcessConfigType::Config(_) => f
.debug_struct("ProcessConfig")
.field("max_memory", &self.get_max_memory())
.field("max_fuel", &self.get_max_fuel())
.field("can_compile_modules", &self.can_compile_modules())
.field("can_create_configs", &self.can_create_configs())
.field("can_spawn_processes", &self.can_spawn_processes())
.finish(),
ProcessConfigType::Inherit => f.debug_struct("ProcessConfig::Inherit").finish(),
}
}
}
impl ProcessConfig {
/// Create a new process configuration with all permissions denied.
///
/// There is no memory or fuel limit set on the newly created configuration,
/// they are not inherited from parent.
pub fn new() -> Result<Self, LunaticError> {
match unsafe { host::api::process::create_config() } {
-1 => Err(LunaticError::PermissionDenied),
id => Ok(Self(ProcessConfigType::Config(id as u64))),
}
}
pub(crate) fn inherit() -> Self {
Self(ProcessConfigType::Inherit)
}
/// Returns the id of the configuration resource or -1 in case it's an
/// inherited configuration.
pub fn id(&self) -> i64 {
match self.0 {
ProcessConfigType::Config(id) => id as i64,
ProcessConfigType::Inherit => -1,
}
}
/// Sets the maximum amount of memory in bytes that can be used by a
/// process.
///
/// If a process tries to allocate more memory with `memory.grow`, the
/// instruction is going to return -1.
pub fn set_max_memory(&mut self, max_memory: u64) {
unsafe { host::api::process::config_set_max_memory(self.id() as u64, max_memory) };
}
/// Returns the maximum amount of memory in bytes.
pub fn get_max_memory(&self) -> u64 {
unsafe { host::api::process::config_get_max_memory(self.id() as u64) }
}
/// Sets the maximum amount of fuel available to the process.
///
/// One unit of fuel is approximately 100k wasm instructions. If a process
/// runs out of fuel it will trap.
pub fn set_max_fuel(&mut self, max_fuel: u64) {
unsafe { host::api::process::config_set_max_fuel(self.id() as u64, max_fuel) };
}
/// Returns the maximum amount of fuel.
pub fn get_max_fuel(&self) -> u64 {
unsafe { host::api::process::config_get_max_fuel(self.id() as u64) }
}
/// Sets the ability of a process to compile WebAssembly modules.
pub fn set_can_compile_modules(&mut self, can: bool) {
unsafe { host::api::process::config_set_can_compile_modules(self.id() as u64, can as u32) };
}
/// Returns true if processes can compile WebAssembly modules.
pub fn can_compile_modules(&self) -> bool {
(unsafe { host::api::process::config_can_compile_modules(self.id() as u64) }) > 0
}
/// Sets the ability of a process to create their own sub-configuration.
///
/// This setting can be dangerous. If a process is missing a permission, but
/// has the possibility to create new configurations, it can spawn
/// sub-processes using a new config that has the permission enabled.
pub fn set_can_create_configs(&mut self, can: bool) {
unsafe { host::api::process::config_set_can_create_configs(self.id() as u64, can as u32) };
}
/// Returns true if processes can create their own configurations.
pub fn can_create_configs(&self) -> bool {
(unsafe { host::api::process::config_can_create_configs(self.id() as u64) }) > 0
}
/// Sets the ability of a process to spawn sub-processes.
pub fn set_can_spawn_processes(&mut self, can: bool) {
unsafe { host::api::process::config_set_can_spawn_processes(self.id() as u64, can as u32) };
}
/// Returns true if processes can spawn sub-processes.
pub fn can_spawn_processes(&self) -> bool {
(unsafe { host::api::process::config_can_spawn_processes(self.id() as u64) }) > 0
}
/// Adds environment variable.
pub fn add_environment_variable(&mut self, key: &str, value: &str) {
unsafe {
host::api::wasi::config_add_environment_variable(
self.id() as u64,
key.as_ptr(),
key.len(),
value.as_ptr(),
value.len(),
)
}
}
/// Adds command line argument.
pub fn add_command_line_argument(&mut self, argument: &str) {
unsafe {
host::api::wasi::config_add_command_line_argument(
self.id() as u64,
argument.as_ptr(),
argument.len(),
)
}
}
#[rustversion::before(1.67)]
/// Mark a directory as pre-opened.
///
/// This API is only available in Rust 1.66 and below. See:
/// - https://github.com/rust-lang/rust/issues/107635
/// - https://github.com/rust-lang/rust/pull/108097
pub fn preopen_dir(&mut self, dir: &str) {
unsafe { host::api::wasi::config_preopen_dir(self.id() as u64, dir.as_ptr(), dir.len()) }
}
}