Repository navigation
Conversation
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.
| //! actually allowed. | ||
| //! | ||
| //! This is still linux and x86 specific. | ||
| #![cfg(all(target_os = "linux", target_arch = "x86_64", not(miri)))] |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Maybe just assert that mpk::is_supported is false on non-x86?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
29edac4 to
43907b9
Compare
832e08c to
5235a97
Compare
5235a97 to
e673de4
Compare
|
Looks like rustfmt needs a run before merging |
The tests runs regardless of platform so it cannot have an unguarded `is_illegal_instruction`.
|
While the macOS failure there is spurious the armv7 failure is genuine |
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_supportedexplicitly checked for GenuineIntel, and then for the PKU bit on the cpuid message. This is misguided for two reasons: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:
-cpu hostand default kernel settings (supported),-cpu hostbutnopkuin the kernel (unsupported),-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: