mpk: restore protection keys after mmap'ing memory images - #14076
Draft
jlb6740 wants to merge 2 commits into
Draft
mpk: restore protection keys after mmap'ing memory images#14076jlb6740 wants to merge 2 commits into
jlb6740 wants to merge 2 commits into
Conversation
A fresh `mmap` associates the pages it replaces with the default protection key 0, and key 0 is accessible from every stripe (host code needs it). `MemoryImageSlot` maps over pkey-colored pool slots in three places, so any module with a `(data ...)` segment silently lost its key. Because MPK striping deliberately shrinks the guard regions between slots, a neighboring instance could then read and write that memory for real. Note that `mprotect` preserves the key, so only `mmap` sites are affected. Fix this by re-applying the key with `pkey_mprotect` after each `mmap`: add `ProtectionKey::reprotect`, give `MemoryImageSlot` the key its stripe was colored with, and call the new `reapply_pkey` helper after `map_at`, `remap_as_zeros_at`, and `erase_existing_mapping`. Tables, stacks, and GC heaps are never pkey-colored, and decommit uses `madvise(MADV_DONTNEED)` which preserves VMA flags, so `MemoryImageSlot` was the only exposure. Cost: one extra syscall per `mmap`, and `instantiate` only `mmap`s when a slot is handed a different image than it already holds. Measured over 1000 instantiations, a module repeatedly instantiated into its affine slot adds 8 calls total (one per slot, at first use) and is in the noise end-to-end. A pool thrashing between more modules than it has slots takes 2 extra calls per instantiation, ~+43% on instantiation. With MPK disabled `ProtectionKey` is uninhabited and this all compiles away. Fixes bytecodealliance#13982 Fixes bytecodealliance#7942
jlb6740
force-pushed
the
mpk-issue-13982-fix
branch
from
August 4, 2026 01:10
d74f556 to
a5810db
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A fresh
mmapassociates the pages it replaces with the default protection key 0, and key 0 is accessible from every stripe (host code needs it).MemoryImageSlotmaps over pkey-colored pool slots in three places, so any module with a(data ...)segment silently lost its key. Because MPK striping deliberately shrinks the guard regions between slots, a neighboring instance could then read and write that memory for real. Note thatmprotectpreserves the key, so onlymmapsites are affected.Fix this by re-applying the key with
pkey_mprotectafter eachmmap: addProtectionKey::reprotect, giveMemoryImageSlotthe key its stripe was colored with, and call the newreapply_pkeyhelper aftermap_at,remap_as_zeros_at, anderase_existing_mapping.Tables, stacks, and GC heaps are never pkey-colored, and decommit uses
madvise(MADV_DONTNEED)which preserves VMA flags, soMemoryImageSlotwas the only exposure.Cost: one extra syscall per
mmap, andinstantiateonlymmaps when a slot is handed a different image than it already holds. Measured over 1000 instantiations, a module repeatedly instantiated into its affine slot adds 8 calls total (one per slot, at first use) and is in the noise end-to-end. A pool thrashing between more modules than it has slots takes 2 extra calls per instantiation, ~+43% on instantiation. With MPK disabledProtectionKeyis uninhabited and this all compiles away.Fixes #13982
Fixes #7942