Hi! I write a web-server and want to execute an untrusted wasm modules in it. I use wasmer runtime, but currently it doesn't have a feature for time limiting of running modules. I need to come up with some way to "kill" stuck modules after some time has passed.
I want to ask, what could be the easiest way to do this in Rust? At the moment I'm considering several options:
To kill a tokio task. Is it even possible? Can a task be canceled if it doesn't await? If yes, will it work in single threaded runtime?
To kill a thread. I could spawn a separate thread, which after a while, would kill another thread by its id. I know it is possible in pthread, but this can lead to memory leaks in Rust, since I will not have time to call the destructors. Also, I would like to be able to run the server on Windows too.
To kill a process. I would create a pool of processes and send tasks to them for execution, for example, via a socket. I hope this won't have problems on Windows, but this solution is quite expensive.
I think I will still have to choose the latter option, but I must consult. Is there a solution I don't know about?
I don't think so, but I'm no expert on async or tokio. Async-await is explicitly co-operative; if the task doesn't co-operate, blocks, and never yields to the runtime, then there's not much you can do about it.
The answers to this question also suggest using a separate process. That has other benefits for executing untrusted code, anyway ("sandboxing").
Wasmtime has several mechanisms for limiting resources. It has ResourceLimiter for all memory related resources. In addition it has fuel (deterministic) and epoch (less deterministic but much faster) based time limiting. This can be used both to throw a trap resulting in the termination of the webassembly code as well as yielding execution back to an async runtime. In the past it also used to have a method to kill a task from another thread, but I think that has been removed when the epoch based time limiting was introduced. You could epoch based limiting to yield back to the async runtime once in a while and then race the future representing the wasm call with one which resolves when you want to kill the task.
As for Wasmer, I don't know if it supports limiting any kind of resources. I have never used it myself.