Add initialization logic during early QEMU startup to allocate a dedicated userspace protection key (Pkey) for protecting guest physical memory when enabled via QEMU_ENABLE_PKEY_GUEST_MEMORY.
Signed-off-by: Jacky Li <[email protected]> --- include/exec/cpu-common.h | 1 + system/vl.c | 1 + util/meson.build | 2 +- util/pkey.c | 23 +++++++++++++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 6594f7fa1b..5ede0c65dc 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -112,4 +112,5 @@ static inline CPUState *env_cpu(CPUArchState *env) return (CPUState *)env_cpu_const(env); } +void qemu_init_guest_memory_pkey(void); #endif /* CPU_COMMON_H */ diff --git a/system/vl.c b/system/vl.c index 061cbdf860..e49c6fed39 100644 --- a/system/vl.c +++ b/system/vl.c @@ -2907,6 +2907,7 @@ void qemu_init(int argc, char **argv) module_allow_arch(target_name()); qemu_init_subsystems(); + qemu_init_guest_memory_pkey(); /* first pass of option parsing */ optind = 1; diff --git a/util/meson.build b/util/meson.build index fa174c07a5..682a078a3d 100644 --- a/util/meson.build +++ b/util/meson.build @@ -9,7 +9,7 @@ if host_os != 'windows' util_ss.add(files('compatfd.c')) util_ss.add(files('event_notifier-posix.c')) if host_os != 'emscripten' - util_ss.add(files('mmap-alloc.c')) + util_ss.add(files('mmap-alloc.c', 'pkey.c')) endif freebsd_dep = [] if host_os == 'freebsd' diff --git a/util/pkey.c b/util/pkey.c index 4f14a72151..249e36d508 100644 --- a/util/pkey.c +++ b/util/pkey.c @@ -40,6 +40,8 @@ #define PKEY_DISABLE_ACCESS 0x1 #endif +static int guest_memory_pkey = -1; + /* Each protection key occupies exactly 2 bits in the PKRU register. */ #define BITS_PER_KEY 2 /* The mask used to extract/write the 2-bit permission flags. */ @@ -86,6 +88,24 @@ static inline __attribute__((always_inline)) intptr_t local_syscall3( return ret; } +__attribute__((target("pku"))) void qemu_init_guest_memory_pkey(void) +{ + if (guest_memory_pkey != -1) { + return; + } + + const char *enable_pkey = getenv("QEMU_ENABLE_PKEY_GUEST_MEMORY"); + if (enable_pkey && strcmp(enable_pkey, "1") == 0) { + int pkey = pkey_alloc(0, 0); + if (pkey == -1) { + error_report("pkey_alloc failed for guest memory: %s", + strerror(errno)); + } else { + guest_memory_pkey = pkey; + } + } +} + #else /* Dummy implementations for all other configurations (non-x86_64 Linux, */ /* Windows, macOS, etc.) */ @@ -93,4 +113,7 @@ static inline __attribute__((always_inline)) intptr_t local_syscall3( #include <linux/kvm.h> #include <sys/ioctl.h> #endif + +void qemu_init_guest_memory_pkey(void) +{} #endif -- 2.55.0.737.g08866a6d13-goog
