Apply the allocated guest memory protection key to all guest RAMBlocks using `pkey_mprotect()` to enforce hardware-assisted access control.
This ensures that guest physical RAM mappings are tagged with our dedicated Pkey in the host page tables, allowing the PKRU register to dynamically permit or block access to guest memory. Signed-off-by: Jacky Li <[email protected]> --- include/exec/cpu-common.h | 1 + include/qemu/mmap-alloc.h | 5 +++++ system/physmem.c | 16 ++++++++++++++-- util/mmap-alloc.c | 3 +-- util/pkey.c | 16 ++++++++++++++++ 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 5ede0c65dc..28399088f6 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -113,4 +113,5 @@ static inline CPUState *env_cpu(CPUArchState *env) } void qemu_init_guest_memory_pkey(void); +int qemu_pkey_mprotect_guest_memory(void *addr, size_t len, int prot); #endif /* CPU_COMMON_H */ diff --git a/include/qemu/mmap-alloc.h b/include/qemu/mmap-alloc.h index 8344daaa03..82fe7f0c3d 100644 --- a/include/qemu/mmap-alloc.h +++ b/include/qemu/mmap-alloc.h @@ -63,4 +63,9 @@ void qemu_ram_munmap(int fd, void *ptr, size_t size); */ #define QEMU_MAP_NORESERVE (1 << 3) +static inline int qemu_map_flags_to_prot(uint32_t qemu_map_flags) +{ + return PROT_READ | ((qemu_map_flags & QEMU_MAP_READONLY) ? 0 : PROT_WRITE); +} + #endif diff --git a/system/physmem.c b/system/physmem.c index 362a00f76c..9f5a0f194c 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -2144,6 +2144,12 @@ static void dirty_memory_extend(ram_addr_t new_ram_size) ram_list.num_dirty_blocks = new_num_blocks; } +static inline int ramblock_get_prot(const RAMBlock *rb) +{ + uint32_t map_flags = (rb->flags & RAM_READONLY) ? QEMU_MAP_READONLY : 0; + return qemu_map_flags_to_prot(map_flags); +} + static void ram_block_add(RAMBlock *new_block, Error **errp) { const bool noreserve = qemu_ram_is_noreserve(new_block); @@ -2282,6 +2288,13 @@ static void ram_block_add(RAMBlock *new_block, Error **errp) } ram_block_notify_add(new_block->host, new_block->used_length, new_block->max_length); + int prot = ramblock_get_prot(new_block); + int ret = qemu_pkey_mprotect_guest_memory(new_block->host, + new_block->max_length, prot); + if (ret != 0) { + error_report("qemu_pkey_mprotect failed for guest RAMBlock: %s", + strerror(errno)); + } } return; @@ -2624,8 +2637,7 @@ static int qemu_ram_remap_mmap(RAMBlock *block, uint64_t start, size_t length) flags = MAP_FIXED | MAP_ANONYMOUS; flags |= block->flags & RAM_SHARED ? MAP_SHARED : MAP_PRIVATE; flags |= block->flags & RAM_NORESERVE ? MAP_NORESERVE : 0; - prot = PROT_READ; - prot |= block->flags & RAM_READONLY ? 0 : PROT_WRITE; + prot = ramblock_get_prot(block); area = mmap(host_startaddr, length, prot, flags, -1, 0); return area != host_startaddr ? -errno : 0; } diff --git a/util/mmap-alloc.c b/util/mmap-alloc.c index ed14f9c64d..0dc8e8275d 100644 --- a/util/mmap-alloc.c +++ b/util/mmap-alloc.c @@ -185,10 +185,9 @@ static void *mmap_activate(void *ptr, size_t size, int fd, uint32_t qemu_map_flags, off_t map_offset) { const bool noreserve = qemu_map_flags & QEMU_MAP_NORESERVE; - const bool readonly = qemu_map_flags & QEMU_MAP_READONLY; const bool shared = qemu_map_flags & QEMU_MAP_SHARED; const bool sync = qemu_map_flags & QEMU_MAP_SYNC; - const int prot = PROT_READ | (readonly ? 0 : PROT_WRITE); + const int prot = qemu_map_flags_to_prot(qemu_map_flags); int map_sync_flags = 0; int flags = MAP_FIXED; void *activated_ptr; diff --git a/util/pkey.c b/util/pkey.c index 249e36d508..0151714f32 100644 --- a/util/pkey.c +++ b/util/pkey.c @@ -106,6 +106,17 @@ __attribute__((target("pku"))) void qemu_init_guest_memory_pkey(void) } } +__attribute__((target("pku"))) int qemu_pkey_mprotect_guest_memory(void *addr, + size_t len, + int prot) +{ + int pkey = guest_memory_pkey; + if (pkey == -1) { + return 0; + } + return pkey_mprotect(addr, len, prot, pkey); +} + #else /* Dummy implementations for all other configurations (non-x86_64 Linux, */ /* Windows, macOS, etc.) */ @@ -116,4 +127,9 @@ __attribute__((target("pku"))) void qemu_init_guest_memory_pkey(void) void qemu_init_guest_memory_pkey(void) {} + +int qemu_pkey_mprotect_guest_memory(void *addr, size_t len, int prot) +{ + return 0; +} #endif -- 2.55.0.737.g08866a6d13-goog
