On 10 Sep 2024, at 12:45, Vadim Goncharov <vadimnucli...@gmail.com> wrote:
> 
> It's easy for your Lua code (or whatever) code to hang kernel by
> infinite loop. Or crash it by access on arbitrary pointer. That's why
> original BPF has no backward jumps and memory access, and eBPF's
> nightmare verifier walks all code paths and check pointers.

I’m not convinced by the second: Lua has a GC’d heap, you’d need to expose FFI 
things to it that did unsafe things, and that’s equally a problem for eBPF.

The first is not a problem.  The Lua interpreter has a bytecode limit.  You can 
define a bounded number of bytecodes that it will execute.  The problem comes 
from the standard library.  Things like string.gmatch can have high-order 
polynomial complexity and so it’s possible for a Lua program that executes a 
small number of bytecodes to create a string that takes a vast amount of time 
to match on.  Again, this is also a problem for eBPF if you expose a similar 
function, the solution is to not expose functions with large data-dependent 
runtimes to untrusted script.

More generally, there are a lot of problems with interpreting or JITing 
untrusted code in the kernel in *any* runtime.  Speculative execution makes it 
easy to use these as primitives to leak kernel secrets, either via timing of 
the programs themselves, using the JIT to generate gadgets, or by leaking data 
via cache priming.

Both eBPF and Lua have these problems.

The thing I would like to see for our current use of semi-trusted Lua in the 
kernel (ZFS channel programs) is a way of exposing them (under /dev/something) 
as file descriptors and modifying the ioctls that run them to take a file 
descriptor argument.  I would like to separate the two operations:

 - Load a channel program.
 - Run a channel program.

In the post-Spectre world, the former remains a privileged operation.  Even 
though Linux pretends it isn’t, allowing arbitrary (even arbitrary constrained) 
code to run in the kernel’s address space is a problem.  Invoking such code; 
however, should follow the same rules as everything else.  A trusted entity 
should be able to load a pile of Lua / eBPF / BPF64 / whatever programs into 
the kernel and then set up permissions so that sandboxed programs (and jails) 
can use a defined subset of them.

David

Reply via email to