lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20250618133355.2af1dcc4@donnerap.manchester.arm.com>
Date: Wed, 18 Jun 2025 13:33:55 +0100
From: Andre Przywara <andre.przywara@....com>
To: Steven Price <steven.price@....com>
Cc: kvm@...r.kernel.org, kvmarm@...ts.linux.dev, Catalin Marinas
 <catalin.marinas@....com>, Marc Zyngier <maz@...nel.org>, Will Deacon
 <will@...nel.org>, James Morse <james.morse@....com>, Oliver Upton
 <oliver.upton@...ux.dev>, Suzuki K Poulose <suzuki.poulose@....com>,
 Zenghui Yu <yuzenghui@...wei.com>, linux-arm-kernel@...ts.infradead.org,
 linux-kernel@...r.kernel.org, Joey Gouly <joey.gouly@....com>, Alexandru
 Elisei <alexandru.elisei@....com>, Christoffer Dall
 <christoffer.dall@....com>, Fuad Tabba <tabba@...gle.com>,
 linux-coco@...ts.linux.dev, Ganapatrao Kulkarni
 <gankulkarni@...amperecomputing.com>, Gavin Shan <gshan@...hat.com>,
 Shanker Donthineni <sdonthineni@...dia.com>, Alper Gun
 <alpergun@...gle.com>, "Aneesh Kumar K . V" <aneesh.kumar@...nel.org>, Emi
 Kisanuki <fj0570is@...itsu.com>
Subject: Re: [PATCH v9 15/43] arm64: RME: Allow VMM to set RIPAS

On Wed, 11 Jun 2025 11:48:12 +0100
Steven Price <steven.price@....com> wrote:

Hi Steven,

one build error below, on my machine (with GCC10):

> Each page within the protected region of the realm guest can be marked
> as either RAM or EMPTY. Allow the VMM to control this before the guest
> has started and provide the equivalent functions to change this (with
> the guest's approval) at runtime.
> 
> When transitioning from RIPAS RAM (1) to RIPAS EMPTY (0) the memory is
> unmapped from the guest and undelegated allowing the memory to be reused
> by the host. When transitioning to RIPAS RAM the actual population of
> the leaf RTTs is done later on stage 2 fault, however it may be
> necessary to allocate additional RTTs to allow the RMM track the RIPAS
> for the requested range.
> 
> When freeing a block mapping it is necessary to temporarily unfold the
> RTT which requires delegating an extra page to the RMM, this page can
> then be recovered once the contents of the block mapping have been
> freed.
> 
> Signed-off-by: Steven Price <steven.price@....com>
> ---
> Changes from v8:
>  * Propagate the 'may_block' flag to allow conditional calls to
>    cond_resched_rwlock_write().
>  * Introduce alloc_rtt() to wrap alloc_delegated_granule() and
>    kvm_account_pgtable_pages() and use when allocating RTTs.
>  * Code reorganisation to allow init_ipa_state and set_ipa_state to
>    share a common ripas_change() function,
>  * Other minor changes following review.
> Changes from v7:
>  * Replace use of "only_shared" with the upstream "attr_filter" field
>    of struct kvm_gfn_range.
>  * Clean up the logic in alloc_delegated_granule() for when to call
>    kvm_account_pgtable_pages().
>  * Rename realm_destroy_protected_granule() to
>    realm_destroy_private_granule() to match the naming elsewhere. Also
>    fix the return codes in the function to be descriptive.
>  * Several other minor changes to names/return codes.
> Changes from v6:
>  * Split the code dealing with the guest triggering a RIPAS change into
>    a separate patch, so this patch is purely for the VMM setting up the
>    RIPAS before the guest first runs.
>  * Drop the useless flags argument from alloc_delegated_granule().
>  * Account RTTs allocated for a guest using kvm_account_pgtable_pages().
>  * Deal with the RMM granule size potentially being smaller than the
>    host's PAGE_SIZE. Although note alloc_delegated_granule() currently
>    still allocates an entire host page for every RMM granule (so wasting
>    memory when PAGE_SIZE>4k).
> Changes from v5:
>  * Adapt to rebasing.
>  * Introduce find_map_level()
>  * Rename some functions to be clearer.
>  * Drop the "spare page" functionality.
> Changes from v2:
>  * {alloc,free}_delegated_page() moved from previous patch to this one.
>  * alloc_delegated_page() now takes a gfp_t flags parameter.
>  * Fix the reference counting of guestmem pages to avoid leaking memory.
>  * Several misc code improvements and extra comments.
> ---
>  arch/arm64/include/asm/kvm_rme.h |   6 +
>  arch/arm64/kvm/mmu.c             |   8 +-
>  arch/arm64/kvm/rme.c             | 447 +++++++++++++++++++++++++++++++
>  3 files changed, 458 insertions(+), 3 deletions(-)
> 

[ ... ]

> diff --git a/arch/arm64/kvm/rme.c b/arch/arm64/kvm/rme.c
> index 25705da6f153..fe75c41d6ac3 100644
> --- a/arch/arm64/kvm/rme.c
> +++ b/arch/arm64/kvm/rme.c

[ ... ]

> @@ -318,6 +619,140 @@ static int realm_create_rd(struct kvm *kvm)
>  	return r;
>  }
>  
> +static void realm_unmap_private_range(struct kvm *kvm,
> +				      unsigned long start,
> +				      unsigned long end,
> +				      bool may_block)
> +{
> +	struct realm *realm = &kvm->arch.realm;
> +	unsigned long next_addr, addr;
> +	int ret;
> +
> +	for (addr = start; addr < end; addr = next_addr) {
> +		ret = realm_unmap_private_page(realm, addr, &next_addr);
> +
> +		if (ret)
> +			break;
> +
> +		if (may_block)
> +			cond_resched_rwlock_write(&kvm->mmu_lock);
> +	}
> +
> +	realm_fold_rtt_level(realm, get_start_level(realm) + 1,
> +			     start, end);
> +}
> +
> +void kvm_realm_unmap_range(struct kvm *kvm, unsigned long start,
> +			   unsigned long size, bool unmap_private,
> +			   bool may_block)
> +{
> +	unsigned long end = start + size;
> +	struct realm *realm = &kvm->arch.realm;
> +
> +	end = min(BIT(realm->ia_bits - 1), end);
> +
> +	if (!kvm_realm_is_created(kvm))
> +		return;
> +
> +	realm_unmap_shared_range(kvm, find_map_level(realm, start, end),
> +				 start, end, may_block);
> +	if (unmap_private)
> +		realm_unmap_private_range(kvm, start, end, may_block);
> +}
> +
> +enum ripas_action {
> +	RIPAS_INIT,
> +	RIPAS_SET,
> +};
> +
> +static int ripas_change(struct kvm *kvm,
> +			struct kvm_vcpu *vcpu,
> +			unsigned long ipa,
> +			unsigned long end,
> +			enum ripas_action action,
> +			unsigned long *top_ipa)
> +{
> +	struct realm *realm = &kvm->arch.realm;
> +	phys_addr_t rd_phys = virt_to_phys(realm->rd);
> +	phys_addr_t rec_phys;
> +	struct kvm_mmu_memory_cache *memcache = NULL;
> +	int ret = 0;
> +
> +	if (vcpu) {
> +		rec_phys = virt_to_phys(vcpu->arch.rec.rec_page);
> +		memcache = &vcpu->arch.mmu_page_cache;
> +
> +		WARN_ON(action != RIPAS_SET);
> +	} else {
> +		WARN_ON(action != RIPAS_INIT);
> +	}
> +
> +	while (ipa < end) {
> +		unsigned long next;
> +
> +		switch (action) {
> +		case RIPAS_INIT:
> +			ret = rmi_rtt_init_ripas(rd_phys, ipa, end, &next);
> +			break;
> +		case RIPAS_SET:
> +			ret = rmi_rtt_set_ripas(rd_phys, rec_phys, ipa, end,
> +						&next);
> +			break;
> +		}
> +
> +		switch (RMI_RETURN_STATUS(ret)) {
> +		case RMI_SUCCESS:
> +			ipa = next;
> +			break;
> +		case RMI_ERROR_RTT:
> +			int err_level = RMI_RETURN_INDEX(ret);

This breaks the build on GCC <= v10:

/src/linux/arch/arm64/kvm/rme.c: In function ‘ripas_change’:
/src/linux/arch/arm64/kvm/rme.c:1190:4: error: a label can only be part of a statement and a declaration is not a statement
 1190 |    int err_level = RMI_RETURN_INDEX(ret);
      |    ^~~
/src/linux/arch/arm64/kvm/rme.c:1191:4: error: expected expression before int’
 1191 |    int level = find_map_level(realm, ipa, end);
      |    ^~~
/src/linux/arch/arm64/kvm/rme.c:1193:21: error: ‘level’ undeclared (first use in this function)
 1193 |    if (err_level >= level)
      |                     ^~~~~

With GCC 11 and later I see this still as a warning when using -Wpedantic,
but it vanishes when also paired with -std=gnu2x.

So either hoist the variable declaration up, or use brackets, this worked
for me as well, and I see it in other places:

		case RMI_ERROR_RTT: {
			....
		}
		default:

Cheers,
Andre


> +			int level = find_map_level(realm, ipa, end);
> +
> +			if (err_level >= level)
> +				return -EINVAL;
> +
> +			ret = realm_create_rtt_levels(realm, ipa,
> err_level,
> +						      level, memcache);
> +			if (ret)
> +				return ret;
> +			/* Retry with the RTT levels in place */
> +			break;
> +		default:
> +			WARN_ON(1);
> +			return -ENXIO;
> +		}
> +	}
> +
> +	if (top_ipa)
> +		*top_ipa = ipa;
> +
> +	return 0;
> +}
> +
> +static int realm_init_ipa_state(struct kvm *kvm,
> +				unsigned long ipa,
> +				unsigned long end)
> +{
> +	return ripas_change(kvm, NULL, ipa, end, RIPAS_INIT, NULL);
> +}
> +
> +static int kvm_init_ipa_range_realm(struct kvm *kvm,
> +				    struct arm_rme_init_ripas *args)
> +{
> +	gpa_t addr, end;
> +
> +	addr = args->base;
> +	end = addr + args->size;
> +
> +	if (end < addr)
> +		return -EINVAL;
> +
> +	if (kvm_realm_state(kvm) != REALM_STATE_NEW)
> +		return -EPERM;
> +
> +	return realm_init_ipa_state(kvm, addr, end);
> +}
> +
>  /* Protects access to rme_vmid_bitmap */
>  static DEFINE_SPINLOCK(rme_vmid_lock);
>  static unsigned long *rme_vmid_bitmap;
> @@ -441,6 +876,18 @@ int kvm_realm_enable_cap(struct kvm *kvm, struct
> kvm_enable_cap *cap) case KVM_CAP_ARM_RME_CREATE_REALM:
>  		r = kvm_create_realm(kvm);
>  		break;
> +	case KVM_CAP_ARM_RME_INIT_RIPAS_REALM: {
> +		struct arm_rme_init_ripas args;
> +		void __user *argp = u64_to_user_ptr(cap->args[1]);
> +
> +		if (copy_from_user(&args, argp, sizeof(args))) {
> +			r = -EFAULT;
> +			break;
> +		}
> +
> +		r = kvm_init_ipa_range_realm(kvm, &args);
> +		break;
> +	}
>  	default:
>  		r = -EINVAL;
>  		break;


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ