Wasm in the Kernel

Evolving Threat Detection at Runtime

Mimic Image

Mimic

  • System level threat detection and mitigation
  • Reconfigure and redeploy during ongoing attacks
  • Modifying system in production is risky

WebAssembly at Mimic

  • Process system events from kernel to cloud
  • Wasm-centric product
    • Environment customization
    • Dynamic updates
  • Component Model
  • Help build and maintain an ecosystem
  • Virtualization for cross-platform development

Kernel Programming

  • ... is hard!
    • Low-level system API
    • Asynchronous environment
    • Minor bugs cause full system crashes
  • eBPF (extended Berkeley Packet Filter) for Linux kernel
    • Change kernel's behavior without restart
    • Restricted logic for safety
  • eBPF for Windows is under development
     microsoft/ebpf-for-windows

Wasm in Windows Kernel

  • Update code in kernel without restart
  • Sandboxing for safety guarantees
  • Policy-driven execution
    • Resource limiting
    • Fine-grained access control

Challenges

  • No standard library (#[no_std])
  • No executable memory due to kernel security policies
  • No Just in Time (JIT) compilation

Interpreting Wasm

  • TinyWasm, Wasmi, and Wasmtime with Pulley
  • Wasmi is ~10x slower than Wasmtime with JIT
  • Wasmi is ~20-50% faster than Wasmtime with Pulley

Component Model

  • Secure and modular ecosystem
  • Compatibility with user-space ecosystem
  • Wasmtime was the only viable option

Kernel Embedding

  • Run as a minifilter driver

    • Intercept and process I/O events
    • High-level API
  • Host functions interact with kernel (no WASI)

  • Compile to Pulley in user space

Host implementation

  • Enforce no_std in Wasmtime
    •  bytecodealliance/wasmtime#11152
  • IRQL (Interrupt Request Level) aware error handling
  • Implement host primitives through C API
    • Memory mapping via heap allocation
    • Structured Exception Handling instead of panic unwinding
    • Custom TLS (Thread Local Storage )

Multithreading

  • Run concurrent Wasm components
  • Wasmtime no_std assumed single threaded host
    • Panic on contention
  • Host provided synchronization primitives
    •  bytecodealliance/wasmtime#11836

Thread-Local Storage

  • The standard library usually implements TLS for you
  • Custom TLS implementation
    • Stack pinned thread scopes and IDs
  • Thread-scope registry pattern
    • Per-thread stacks of values

Wrapping up

  • Safe kernel development with Wasm
  • Dynamic sandboxing vs. static verification
  • Be aware of performance cost

20 mins slides, 5 mins demo, 5 mins Q&A

welcome to our presentations "Evolving Threat Detection at Runtime" I am Mikhail and this is my co-presenter Salman We are going to talk about how we at Mimic use WebAssembly to dynamically update behavior in the windows kernel

Transition:

let me tell you a little about Mimic

~ 2 minutes

Mikhail

we are a member of the BytecodeAlliance that specializes in...

the technology we are developing allows us to rapidly react to ongoing attacks from adversaries

- Modifying it often is even riskier

Transition:

We use Wasm to mitigate some of this risk through sandboxing

~ 2 minutes

Mikhail

Our product monitors system events from the core of the operating system, the kernel, to the cloud to detect threats.

and we use Wasm for safe customization and dynamic updates

Wasm allows us to customize the product to meet the individual needs of our customer's environment

We use Wasm to rapidly configure and update our product

we do this by leveraging the Component Model at mimic

we built a modular ecosystem using the Component Model for our product

Virtualization with the Componen Model allows us to reuse code across platforms

Transition:

One of the places we deploy this kind of dynamic logic is in the operating system's Kernel

~ 1 minute

Salman

eBPF allows safe customization and dynamic updates in the Linux kernel

But in Windows...

Transition:

So...

2 minutes

Salman

our own safe space inside a hostile kernel environment

restriction v.s. sandboxing

we have full control on a running instance of Wasm

Transition:

Kernel programming is notoriously hard

getting Wasm working in the kernel wasn't easy

~ 1 minute

Mikhail

first, we don't have access to all the tools we get in the standard library

second ... you can't run random wasn binaries in the Kernel <!-- only code that has been reviewed and signed by microsoft can run with standard security policies

hypervisor kernel mode integrity windows

and ... that means we also can't to JIT compilation

Transition:

thus, we decided to interpret Wasm

2 minutes

Mikhail

constrained environment

we wanted Wasm interpreters that supported no_std environment

Pulley, by the way is an optimized bytecode format and interpreter for Wasmtime

these were the high level results of OUR micro-benchmarking, Wasmi was the fastest one

Interpreting was an magnitude slower for OUR micro-benchmarks than JIT

interpreted Wasmi is faster

Transition:

BUT we still chose Wasmtime+Pulley instead of Wasmi

Salman

~ 1 minute

capability-based Compatibility

technology independence is important for building ecosystems

compatibility enables workload migration

Component Model is difficult to adopt

we wish there were more implementations that handled the Component Model

Transition:

So how do we make wasmtime run in the kernel...

2 minutes

Salman

Technical Details

?? We should expand the following sections.

We embed wasmtime as a minifilter in the kernel

TODO should be a keynote and have a simpler bullet point

- minifilters provide a way for developers to monitor and modify file system operations

without needing to interact directly with lower-level file system drivers

- we are not supporting Wasi but we are implementing the host functions in the kernel

- the host functions interact with the kernel and need to be fully tested

this "unsafe" portion of our code

we compile modules in user space

what we are deploying is not standard wasm, it's optimized pulley bytecode

2 minutes

Salman

When you are in no_std you have to implement the C API

Wasmtime was still pulling in the standard library with no_std

talk about "respect `std` PR" #11152

shoutout to Alex C for the quick turnaround

IRQLs limits what you can and cannot do based on your level

performing wrong operation at wrong IRQL causes BSoD

Transition:

we wanted our hosts to run multiple Wasm components at once

2 minutes

Mikhail

when we tried spawning multiple worker threads, wasmtime panicking on contention

Wasmtime needed the std to provide synchronization primitives to avoid contention

we modified Wasmtime to allow the host to provide synchronization primitives through C API

Transition:

We also had to implement our own thread-local storage (TLS)

2 minutes

Mikhail

In computer programming, thread-local storage (TLS) is a lock-free memory management method

that gives each thread its own copy of a global variable. <!-- When the thread exits, its copied variables are destroyed

Solution

we use stack pinning to ensure that allocated memory does not shift when thread scopes are passed around

and that their IDs stay relevant even after leaving the current scope

we use a registry pattern to link threads to their parents and the resources they own

...now we can can run multiple components at once

Transition:

What does this get us

1 minutes

Salman

we allowed WebAssembly to handle dynamic updates in the kernel without restart

This allows us and our customers to safely write logic for the kernel

it meets our business use cases

logic restriction v.s. sandboxing

Interpreting Wasm comes at a cost

Wasm solution should not be used on the hot path

Transition:

We will now show you a demo to see our solution in practice...