Skip to content

Revise MPK support check to allow non-Intel CPUs. - #14967

Open
V0ldek wants to merge 9 commits into
bytecodealliance:mainfrom
V0ldek:v0ldek/amd-mpk
Open

V0ldek wants to merge 9 commits into
bytecodealliance:mainfrom
V0ldek:v0ldek/amd-mpk

Conversation

@V0ldek

@V0ldek V0ldek commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

While poking around in the pooling allocator I noticed that my machine actually does not use the MPK features, which was weird since I've used them before. Turns out AMD is just rejected by wasmtime for this feature. After looking into it I actually found a more critical issue.

The check for mpk::is_supported explicitly checked for GenuineIntel, and then for the PKU bit on the cpuid message. This is misguided for two reasons:

  1. Zen3 AMD also supports MPKs but wasmtime misses out on using them;
  2. the OSPKE bit also has to be checked to actually be correct.

Number 1. seems to have been done as an attempt to avoid CI crashes. In #7445, #7446 MPK was disabled and then reenabled for Intel only in PR #7513. I believe that was actually a red herring and those crashes were caused by the second point.

PKU only says if the CPU supports MPKs on the hardware level. However, the OS still needs to enable it (CR4.PKE). If it is not enabled, RDPKRU/WRPKRU raise #UD, which kills the process with SIGILL. An example is a VM that runs on a modern CPU as the hardware, but whose hypervisor has PKU disabled. This would actually fault on any vendor, Intel included. You can test it today on the old version by running wasmtime in QEMU with nopku passed (-append "nopku"), it will crash with the pooling allocator when it tries to set up PKs.

In this commit we switch to checking both PKE and OSPKE, removing the vendor check. This is confirmed to work on modern AMD and Intel, and correctly recognises MPK when ran under QEMU:

  • with -cpu host and default kernel settings (supported),
  • with -cpu host but nopku in the kernel (unsupported),
  • with -cpu host,-pku (unsupported).

We now have a test in tests/mpk.rs to ensure the result of the check agrees with actual capabilities the process has.

Additionally, removed a stale test in pkru::tests::check_read, it was ignored since forever and the new mpk test supersedes it.

If you want confirmation on the CPU bits to be read:

The check for `mpk::is_supported` explicitly checked for GenuineIntel,
and then for the PKU bit on the cpuid message. This is misguided for two
reasons:

1. Zen3 AMD also supports MPKs but wasmtime misses out on using them;
2. the OSPKE bit also has to be checked to actually be correct.

Number 1. seems to have been done as an attempt to avoid CI crashes.
In bytecodealliance#7445, bytecodealliance#7446 MPK was disabled and then reenabled for Intel only in
PR bytecodealliance#7513. I believe that was actually a red herring and those crashes
were caused by the second point.

PKU only says if the CPU supports MPKs on the hardware level. However,
the OS still needs to enable PKE. If it is not enabled, RDPKRU/WRPKRU
raise #UD, which kills the process with SIGILL. An example is a VM that
runs on a modern CPU as the hardware, but whose hypervisor has PKU
disabled. This would actually fault on *any* vendor, Intel included.
You can test it today on the old version by running wasmtime in QEMU
with nopku passed (`-append "nopku"`), it will crash with the pooling
allocator when it tries to set up PKs.

In this commit we switch to checking both PKE and OSPKE, removing the
vendor check. This is confirmed to work on modern AMD and Intel, and
correctly recognises MPK when ran under QEMU:
- with `-cpu host` and default kernel settings (supported),
- with `-cpu host` but `nopku` in the kernel (unsupported),
- with `-cpu host,-pku` (unsupported).

We now have a test in tests/mpk.rs to ensure the result
of the check agrees with actual capabilities the process has.

Additionally, removed a stale test in `pkru::tests::check_read`,
it was ignored since forever and the new mpk test supersedes it.
@V0ldek
V0ldek requested review from a team as code owners October 23, 2026 17:30
@V0ldek
V0ldek requested review from fitzgen and pchickey and removed request for a team October 23, 2026 17:31
@pchickey
pchickey removed their request for review October 23, 2026 19:33

@alexcrichton alexcrichton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment thread crates/core/tests/mpk.rs Resolved
Comment thread crates/core/tests/mpk.rs Outdated
//! actually allowed.
//!
//! This is still linux and x86 specific.
#![cfg(all(target_os = "linux", target_arch = "x86_64", not(miri)))]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be compiled/run on all platforms and non-x86_64 platforms exit with a failure? That'd help test that is_supported returns false on non-linux and non-x86_64 platforms fo example

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just assert that mpk::is_supported is false on non-x86?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds reasonable yeah, but I think that'd naturally fall out of "the spawned subprocess failed" as opposed to special-casing it, where the special-casing would be the libc::syscall and asm! blocks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll need to work more on this and test how it interacts with different platforms. One finding is that I'm pretty sure we actually don't want to gate is_support behind x86_64 cause on 32-bit you can also use MPKs.

Another one is FreeBSD. They don't have libc pkey_alloc or pkey_free but they do support PKUs, so the is_support flag would actually say yes. Their API is different, so wasmtime would have to have a separate cfg path for FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=pkru&sektion=3.

I have no idea what happens on macOS and no means to test it either.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So ARM also has its own MPK system, but it is different, e.g. they only have 7 usable keys instead of 15. It would also require rewriting the code in vm/mpk/pkru.rs.

At this point I honestly think that the test should just be "do we return false on those platforms", because FreeBSD and Linux on ARM support MPK architecturally, but wasmtime does not hook into that and it'd be a separate PR to allow that. I will try to figure out how hard it'd be for FreeBSD in this PR, but for ARM I have no machine to test it on so I wouldn't tackle that.

@fitzgen
fitzgen removed their request for review October 23, 2026 21:41
@github-actions github-actions Bot added the wasmtime:api Related to the API of the `wasmtime` crate itself label Oct 24, 2026
@alexcrichton

Copy link
Copy Markdown
Member

Looks like rustfmt needs a run before merging

@alexcrichton
alexcrichton added this pull request to the merge queue Oct 27, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 27, 2026
The tests runs regardless of platform so it cannot have an unguarded `is_illegal_instruction`.
@alexcrichton
alexcrichton added this pull request to the merge queue Oct 30, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 30, 2026
@alexcrichton
alexcrichton added this pull request to the merge queue Nov 4, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 4, 2026
@alexcrichton

Copy link
Copy Markdown
Member

While the macOS failure there is spurious the armv7 failure is genuine

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

wasmtime:api Related to the API of the `wasmtime` crate itself

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants