mleonhard edited Issue #2273:
I wish to use wasmtime in a server to run small untrusted code blocks. I need to limit the maximum memory consumed by each running block to 5MB. I looked through the docs and found no way to restrict how much memory the VM can allocate. There seems to be a built-in limit of 4GB. See #1872 .
Let's support or document how to restrict total instance memory.
mleonhard edited Issue #2273:
I wish to use wasmtime in a server to run small untrusted code blocks. I need to limit the maximum memory consumed by each running block to 5MB. I looked through the docs and found no way to restrict how much memory the VM can allocate. There seems to be a built-in limit of 4GB. See #1872 .
Let's support or document how to restrict memory usage.
bjorn3 commented on Issue #2273:
For imported memory you can set the limit when creating the memory. For exported memory you could parse the module and check that the memory limit is at most 5MB.
alexcrichton commented on Issue #2273:
You can control memory via a number of different means. Application-level configuration happens through the
Config
type. For example you can usestatic_memory_maximum_size
,static_memory_guard_size
, anddynamic_memory_guard_size
to tweak how wasmtime allocates memory. The smallest VM reservations will come with a static max size of 0 and a dynamic guard of zero, but code will not perform as well at runtime.You can further configure the
with_host_memory
method which means that your application is bringing its own memory allocation strategy, where you can limit even the size of locally defined memories in a wasm module.And as @bjorn3 mentioned if you're creating the memory itself then you can specify the maximum size at runtime.
mleonhard commented on Issue #2273:
Thank you both for your quick replies.
Is there a way to use
static_memory_maximum_size
,static_memory_guard_size
, anddynamic_memory_guard_size
to restrict the VM from allocating more memory? Could I set the static_memory_guard_size to 4GB - 5MB? I suppose this could work on a platform with a wide-enough memory address space.To use
wasmtime::Config::with_host_memory
, I must implement wasmtime::MemoryCreator. The MemoryCreator is configured on theEngine
which contains many VMs.InstanceHandle::new
callsinstance::create_memories
callsMemoryCreator::new_memory
and does not pass any data about which VM (Store
orInstance
) the memory is for. How could I use the engine-specific struct to decide if a particular VM has reached its allocation limit?I looked at how to check the size of memories in a module. I'm not familiar with WASM memories. Are all module-allocated memories exported? Would this work?
- Call
wasmtime::Module::exports
- Iterate through the result and examine
ExternType::Memory
entries- Error if there is a missing
Limits::max
value- Sum up the
Limits::max
values and error if they go over the limit
wasmparser::Parser
can parse the Memory entries. There is ashared
flag. I supposeshared=true
means the memory is exported. So some WASM binaries might haveshared=false
memories, which would not appear in the list of exports. So I cannot usewasmtime::Module::exports
to count total memory usage.wasmparser::Parser
should work. I think this might be the solution.Does WASM define any way for a module to make new Memory objects at runtime?
mleonhard commented on Issue #2273:
An article that describes how WASM memories work:
https://depth-first.com/articles/2019/10/16/compiling-c-to-webassembly-and-running-it-without-emscripten/
alexcrichton commented on Issue #2273:
@mleonhard I'd recommend reading the documentation about dynamic/static memories. Unfortunately there is no "disallow more than 5MB per instance" switch in Wasmtime, and this is something that will require work to be done at this time. The
MemoryCreator
trait allows a custom implementation which you can embed with specifics related to your application. You can track growth and allocation to disallow or arbitrarily "fail" growth beyond a certain point.For wasm memories in general, I'd recommend reading up on documentation in the wasm spec or in various posts online. Wasm modules can define or import a memory. Memories always state a minimum size and optionally have a maximum size. You would probably want to validate in your application that the minimum size isn't too big.
mleonhard commented on Issue #2273:
I found the answer: Code in a Wasm VM cannot make new Memory objects. See WebAssembly 1.1 Memories. Every Wasm binary can define exactly one Memory object with a specified initial size and an optional max size. Code inside the VM can use memory instructions to grow a Memory region, up to its max size.
Code in a Wasm VM could import and call a function that makes a new Memory object or does anything. By default, a wasmtime VM does not provide any importable functions to code inside the VM. Call
wasmtime_wasi::Wasi::new
to make WASI functions importable. See example Embedding in Rust - WASI.To check the max memory usage of a program running inside a wasmtime VM, parse the binary and check the max size of the single
Memory
entry.To set the memory usage limit of a program running inside a wasmtime VM, modify the binary to set the max size value of the
Memory
entry. The object crate has an API and an example that could be adapted to modify Wasm binaries, but it won't be pretty.I also found WASM Micro Runtime which provides a simple way to limit memory. But it has no Rust bindings.
mleonhard commented on Issue #2273:
https://crates.io/crates/parity-wasm looks like a very clean library for modifying Wasm binaries to set memory max size.
Last updated: Dec 23 2024 at 13:07 UTC