From 49ccd7310b8dee98d81c3891ec27222b1c62ca65 Mon Sep 17 00:00:00 2001 From: liberodark Date: Sat, 25 Jul 2026 02:41:44 +0200 Subject: [PATCH] libkrun: fix riscv64-linux build --- pkgs/by-name/li/libkrun/package.nix | 7 + .../li/libkrun/riscv64-non-tee-memory.patch | 357 ++++++++++++++++++ 2 files changed, 364 insertions(+) create mode 100644 pkgs/by-name/li/libkrun/riscv64-non-tee-memory.patch diff --git a/pkgs/by-name/li/libkrun/package.nix b/pkgs/by-name/li/libkrun/package.nix index ba4641449d8f..c5afdcc5b024 100644 --- a/pkgs/by-name/li/libkrun/package.nix +++ b/pkgs/by-name/li/libkrun/package.nix @@ -71,6 +71,13 @@ stdenv.mkDerivation (finalAttrs: { rustc ]; + patches = lib.optionals stdenv.hostPlatform.isRiscV64 [ + # https://github.com/libkrun/libkrun/commit/d4bb6e0 + # Fix riscv64 non-TEE memory region setup + # Remove in next release (Not included in 1.19.4) + ./riscv64-non-tee-memory.patch + ]; + buildInputs = [ libcap_ng libkrunfw' diff --git a/pkgs/by-name/li/libkrun/riscv64-non-tee-memory.patch b/pkgs/by-name/li/libkrun/riscv64-non-tee-memory.patch new file mode 100644 index 000000000000..47b5856b6e41 --- /dev/null +++ b/pkgs/by-name/li/libkrun/riscv64-non-tee-memory.patch @@ -0,0 +1,357 @@ +From d4bb6e040ad7b6e6a6cf68ffced3b895c2753a18 Mon Sep 17 00:00:00 2001 +From: Zewei Yang +Date: Thu, 19 Mar 2026 09:40:43 +0800 +Subject: [PATCH] vmm: fix riscv64 non-TEE memory region setup + +In non-x86 builds that don't use TEE features, vstate.rs used cfg!() to +distinguish between TEE and non-TEE memory setup paths. + +cfg!() only evaluates to a compile-time constant; code in both branches +still participates in compilation and type checking. As a result, normal +riscv64 builds still type-check guest_memfd and memory attribute code, +which leads to build failures. + +Refactor the memory-region setup into cfg-gated helpers so non-TEE builds +do not compile TEE-only memory setup code, and reject unsupported +TEE+architecture combinations during VM setup instead of during memory +initialization. + +Upstream: https://github.com/libkrun/libkrun/commit/d4bb6e040ad7b6e6a6cf68ffced3b895c2753a18 +Backported to v1.19.0: the upstream diff does not apply as-is because of +the intervening Rust 2024 edition migration / cargo fmt reordering of the +`use kvm_bindings::{...}` blocks. Only those import hunks were adjusted; +no functional change. + +Signed-off-by: Zewei Yang +--- +diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs +index 6d50e7f..c0521b1 100644 +--- a/src/vmm/src/builder.rs ++++ b/src/vmm/src/builder.rs +@@ -1562,6 +1562,23 @@ pub(crate) fn setup_vm( + .map_err(StartMicrovmError::Internal)?; + Ok(vm) + } ++ ++#[cfg(all(feature = "tee", target_arch = "x86_64"))] ++fn validate_tee_config(tee: Tee) -> std::result::Result<(), StartMicrovmError> { ++ match tee { ++ #[cfg(feature = "amd-sev")] ++ Tee::Snp => Ok(()), ++ #[cfg(feature = "tdx")] ++ Tee::Tdx => Ok(()), ++ _ => Err(StartMicrovmError::InvalidTee), ++ } ++} ++ ++#[cfg(all(feature = "tee", not(target_arch = "x86_64")))] ++fn validate_tee_config(_tee: Tee) -> std::result::Result<(), StartMicrovmError> { ++ Err(StartMicrovmError::InvalidTee) ++} ++ + #[cfg(all(target_os = "linux", feature = "tee"))] + pub(crate) fn setup_vm( + kvm: &KvmContext, +@@ -1569,6 +1586,8 @@ pub(crate) fn setup_vm( + resources: &super::resources::VmResources, + #[cfg(feature = "tdx")] _sender: Sender, + ) -> std::result::Result { ++ validate_tee_config(resources.tee_config().tee)?; ++ + let mut vm = Vm::new( + kvm.fd(), + resources.tee_config(), +diff --git a/src/vmm/src/linux/vstate.rs b/src/vmm/src/linux/vstate.rs +index 05e58fb..d87b743 100644 +--- a/src/vmm/src/linux/vstate.rs ++++ b/src/vmm/src/linux/vstate.rs +@@ -41,7 +41,9 @@ use kbs_types::Tee; + use crate::resources::TeeConfig; + use crate::vmm_config::machine_config::CpuFeaturesTemplate; + #[cfg(target_arch = "x86_64")] +-use cpuid::{c3, filter_cpuid, t2, VmSpec}; ++use cpuid::{VmSpec, c3, filter_cpuid, t2}; ++#[cfg(not(feature = "tee"))] ++use kvm_bindings::kvm_userspace_memory_region; + #[cfg(target_arch = "x86_64")] + use kvm_bindings::{ + kvm_clock_data, kvm_debugregs, kvm_irqchip, kvm_lapic_state, kvm_mp_state, kvm_pit_state2, +@@ -49,14 +51,14 @@ use kvm_bindings::{ + KVM_CLOCK_TSC_STABLE, KVM_IRQCHIP_IOAPIC, KVM_IRQCHIP_PIC_MASTER, KVM_IRQCHIP_PIC_SLAVE, + KVM_MAX_CPUID_ENTRIES, + }; ++use kvm_bindings::{KVM_API_VERSION, KVM_SYSTEM_EVENT_RESET, KVM_SYSTEM_EVENT_SHUTDOWN}; ++#[cfg(feature = "tee")] ++use kvm_bindings::{KVM_CAP_EXIT_HYPERCALL, KVM_MEMORY_EXIT_FLAG_PRIVATE, kvm_enable_cap}; ++#[cfg(all(feature = "tee", target_arch = "x86_64"))] + use kvm_bindings::{ +- kvm_create_guest_memfd, kvm_userspace_memory_region, kvm_userspace_memory_region2, +- KVM_API_VERSION, KVM_MEM_GUEST_MEMFD, KVM_SYSTEM_EVENT_RESET, KVM_SYSTEM_EVENT_SHUTDOWN, ++ KVM_MEM_GUEST_MEMFD, KVM_MEMORY_ATTRIBUTE_PRIVATE, kvm_create_guest_memfd, ++ kvm_memory_attributes, kvm_userspace_memory_region2, + }; +-#[cfg(feature = "tee")] +-use kvm_bindings::{kvm_enable_cap, KVM_CAP_EXIT_HYPERCALL, KVM_MEMORY_EXIT_FLAG_PRIVATE}; +-#[cfg(not(target_arch = "riscv64"))] +-use kvm_bindings::{kvm_memory_attributes, KVM_MEMORY_ATTRIBUTE_PRIVATE}; + use kvm_ioctls::{Cap::*, *}; + use utils::eventfd::EventFd; + use utils::signal::{register_signal_handler, sigrtmin, Killable}; +@@ -661,90 +663,121 @@ impl Vm { + None + } + +- #[allow(unused_mut)] +- fn memory_region_set( ++ // GuestMemfd is generally intended for either of two purposes: ++ // * sharing the memory with out-of-process components, and conversely, ++ // * hiding the memory completely from the VMM process (Confidential Computing). ++ // ++ // We only use it for the second use case currently, so don't even try to use it ++ // outside of TEE builds. Software-protected VMs are only available on x86_64 and ++ // are marked with strongly-worded warnings about them being for development only, ++ // as of late 2025. Also, on other architectures like aarch64, guest_memfd in ++ // general is unstable for now, so don't try to use it without a reason. ++ ++ #[cfg(not(feature = "tee"))] ++ fn create_guest_physical_memory_slot( + &mut self, +- guest_mem: &GuestMemoryMmap, ++ host_addr: u64, ++ start: u64, + region: &GuestRegionMmap, + ) -> Result<()> { +- let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap(); +- let start = region.start_addr().raw_value(); +- let end = start + region.len(); ++ let memory_region = kvm_userspace_memory_region { ++ slot: self.next_mem_slot, ++ guest_phys_addr: start, ++ memory_size: region.len(), ++ userspace_addr: host_addr, ++ flags: 0, ++ }; + +- // GuestMemfd is generally intended for either of two purposes: +- // * sharing the memory with out-of-process components, and conversely, +- // * hiding the memory completely from the VMM process (Confidential Computing). +- // +- // We only use it for the second use case currently, so don't even try to use it +- // outside of TEE builds. Software-protected VMs are only available on x86_64 and +- // are marked with strongly-worded warnings about them being for development only, +- // as of late 2025. Also, on other architectures like aarch64, guest_memfd in +- // general is unstable for now, so don't try to use it without a reason. +- +- if cfg!(not(feature = "tee")) { +- let memory_region = kvm_userspace_memory_region { +- slot: self.next_mem_slot, +- guest_phys_addr: start, +- memory_size: region.len(), +- userspace_addr: host_addr as u64, +- flags: 0, +- }; ++ // Safe because we mapped the memory region and ensured regions do not overlap. ++ unsafe { ++ self.fd ++ .set_user_memory_region(memory_region) ++ .map_err(Error::SetUserMemoryRegion)?; ++ }; + +- // Safe because we mapped the memory region, we made sure that the regions +- // are not overlapping. +- unsafe { +- self.fd +- .set_user_memory_region(memory_region) +- .map_err(Error::SetUserMemoryRegion)?; +- }; +- } else { +- if !self.fd.check_extension(GuestMemfd) { +- return Err(Error::KvmCap(GuestMemfd)); +- } ++ Ok(()) ++ } + +- // Create a guest_memfd and set the region. +- let guest_memfd = self +- .fd +- .create_guest_memfd(kvm_create_guest_memfd { +- size: region.size() as u64, +- flags: 0, +- reserved: [0; 6], +- }) +- .map_err(Error::CreateGuestMemfd)?; +- +- let memory_region = kvm_userspace_memory_region2 { +- slot: self.next_mem_slot, +- flags: KVM_MEM_GUEST_MEMFD, +- guest_phys_addr: start, +- memory_size: region.len(), +- userspace_addr: host_addr as u64, +- guest_memfd_offset: 0, +- guest_memfd: guest_memfd as u32, +- pad1: 0, +- pad2: [0; 14], +- }; +- +- // Safe because we mapped the memory region, we made sure that the regions +- // are not overlapping. +- unsafe { +- self.fd +- .set_user_memory_region2(memory_region) +- .map_err(Error::SetUserMemoryRegion)?; +- }; +- +- let attr = kvm_memory_attributes { +- address: start, +- size: region.len(), +- attributes: KVM_MEMORY_ATTRIBUTE_PRIVATE as u64, ++ #[cfg(all(feature = "tee", target_arch = "x86_64"))] ++ fn create_guest_physical_memory_slot( ++ &mut self, ++ host_addr: u64, ++ start: u64, ++ region: &GuestRegionMmap, ++ ) -> Result<()> { ++ let end = start + region.len(); ++ ++ if !self.fd.check_extension(GuestMemfd) { ++ return Err(Error::KvmCap(GuestMemfd)); ++ } ++ ++ // GuestMemfd is only used for confidential-memory setups in TEE builds. ++ let guest_memfd = self ++ .fd ++ .create_guest_memfd(kvm_create_guest_memfd { ++ size: region.size() as u64, + flags: 0, +- }; ++ reserved: [0; 6], ++ }) ++ .map_err(Error::CreateGuestMemfd)?; ++ ++ let memory_region = kvm_userspace_memory_region2 { ++ slot: self.next_mem_slot, ++ flags: KVM_MEM_GUEST_MEMFD, ++ guest_phys_addr: start, ++ memory_size: region.len(), ++ userspace_addr: host_addr, ++ guest_memfd_offset: 0, ++ guest_memfd: guest_memfd as u32, ++ pad1: 0, ++ pad2: [0; 14], ++ }; + ++ // Safe because we mapped the memory region and ensured regions do not overlap. ++ unsafe { + self.fd +- .set_memory_attributes(attr) +- .map_err(Error::SetMemoryAttributes)?; ++ .set_user_memory_region2(memory_region) ++ .map_err(Error::SetUserMemoryRegion)?; ++ }; + +- self.guest_memfds.push((Range { start, end }, guest_memfd)); +- } ++ let attr = kvm_memory_attributes { ++ address: start, ++ size: region.len(), ++ attributes: KVM_MEMORY_ATTRIBUTE_PRIVATE as u64, ++ flags: 0, ++ }; ++ ++ self.fd ++ .set_memory_attributes(attr) ++ .map_err(Error::SetMemoryAttributes)?; ++ ++ self.guest_memfds.push((Range { start, end }, guest_memfd)); ++ ++ Ok(()) ++ } ++ ++ #[cfg(all(feature = "tee", not(target_arch = "x86_64")))] ++ fn create_guest_physical_memory_slot( ++ &mut self, ++ _host_addr: u64, ++ _start: u64, ++ _region: &GuestRegionMmap, ++ ) -> Result<()> { ++ // TEE support should be rejected during VM setup on non-x86_64 targets. ++ // Do not silently fall back to the non-TEE path here, because that would ++ // ignore an invalid TEE configuration and create a normal VM instead. ++ Err(Error::InvalidTee) ++ } ++ ++ fn memory_region_set( ++ &mut self, ++ guest_mem: &GuestMemoryMmap, ++ region: &GuestRegionMmap, ++ ) -> Result<()> { ++ let host_addr = guest_mem.get_host_address(region.start_addr()).unwrap() as u64; ++ let start = region.start_addr().raw_value(); ++ ++ self.create_guest_physical_memory_slot(host_addr, start, region)?; + + self.next_mem_slot += 1; + +diff --git a/src/vmm/src/worker.rs b/src/vmm/src/worker.rs +index d0131b9..a28ed55 100644 +--- a/src/vmm/src/worker.rs ++++ b/src/vmm/src/worker.rs +@@ -1,20 +1,20 @@ + use std::io; + use std::sync::{Arc, Mutex}; + +-#[cfg(feature = "tee")] ++#[cfg(all(feature = "tee", target_arch = "x86_64"))] + use utils::worker_message::MemoryProperties; + use utils::worker_message::WorkerMessage; + + use crossbeam_channel::Receiver; +-#[cfg(feature = "tee")] ++#[cfg(all(feature = "tee", target_arch = "x86_64"))] + use crossbeam_channel::Sender; +-#[cfg(feature = "tee")] +-use kvm_bindings::{kvm_memory_attributes, KVM_MEMORY_ATTRIBUTE_PRIVATE}; +-#[cfg(feature = "tee")] +-use libc::{fallocate, madvise, FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE, MADV_DONTNEED}; +-#[cfg(feature = "tee")] ++#[cfg(all(feature = "tee", target_arch = "x86_64"))] ++use kvm_bindings::{KVM_MEMORY_ATTRIBUTE_PRIVATE, kvm_memory_attributes}; ++#[cfg(all(feature = "tee", target_arch = "x86_64"))] ++use libc::{FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE, MADV_DONTNEED, fallocate, madvise}; ++#[cfg(all(feature = "tee", target_arch = "x86_64"))] + use std::ffi::c_void; +-#[cfg(feature = "tee")] ++#[cfg(all(feature = "tee", target_arch = "x86_64"))] + use vm_memory::{ + guest_memory::GuestMemory, Address, GuestAddress, GuestMemoryRegion, MemoryRegionAddress, + }; +@@ -59,15 +59,21 @@ impl super::Vmm { + .send(self.vm.fd().set_irq_line(irq, active).is_ok()) + .unwrap(); + } +- WorkerMessage::ConvertMemory(_sender, _properties) => +- { +- #[cfg(feature = "tee")] +- self.convert_memory(_sender, _properties) ++ WorkerMessage::ConvertMemory(_sender, _properties) => { ++ #[cfg(all(feature = "tee", target_arch = "x86_64"))] ++ { ++ self.convert_memory(_sender, _properties); ++ } ++ ++ #[cfg(not(all(feature = "tee", target_arch = "x86_64")))] ++ { ++ let _ = _sender.send(false); ++ } + } + } + } + +- #[cfg(feature = "tee")] ++ #[cfg(all(feature = "tee", target_arch = "x86_64"))] + fn convert_memory(&self, sender: Sender, properties: MemoryProperties) { + let Some((guest_memfd, region_start)) = self.kvm_vm().guest_memfd_get(properties.gpa) + else { +-- +2.51.0