All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Paolo Bonzini" <pbonzini@redhat.com>
Cc: kvm@vger.kernel.org
Subject: Re: [PATCH 09/24] KVM: Introduce NR/NW/NX memory attributes
Date: Thu, 16 Jul 2026 18:39:22 +0000	[thread overview]
Message-ID: <20260716183922.AD05F1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260716181456.402786-10-pbonzini@redhat.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] KVM advertises and accepts memory protection attributes (NR/NW/NX) but fails to enforce them in the MMU, leading to guest sandbox bypass.
- [High] A guest-controlled ioctl can trigger an unbounded, non-yielding loop holding `mmu_lock` in write mode, causing host soft lockups.
- [Medium] `kvm_range_has_memory_attributes()` incorrectly assumes any present XArray entry means non-zero attributes, ignoring the `mask`.
- [Low] Incorrect usage of `WARN_ON_ONCE` with a string literal condition.
- [Low] Leftover debugging code (`trace_printk`) and unresolved `// todo:` comments in production code.
--

--- Patch [9]: [PATCH 09/24] KVM: Introduce NR/NW/NX memory attributes ---
commit dce195fe8dd20af5f86a55891fc7d52cd1a8ed11
Author: Nicolas Saenz Julienne <nsaenz@amazon.com>

KVM: Introduce NR/NW/NX memory attributes

This commit introduces memory attributes to map guest physical memory
regions as non-readable, non-writable, and/or non-executable. It defines
the KVM_MEMORY_ATTRIBUTE_NR/NW/NX flags and adds basic architecture-specific
callbacks for x86 to support these protection attributes.

> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 3b235e9539239..6a96eb3218dc4 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1653,6 +1653,9 @@ struct kvm_memory_attributes {
>  	__u64 flags;
>  };
>  
> +#define KVM_MEMORY_ATTRIBUTE_NR		       (1ULL << 0)
> +#define KVM_MEMORY_ATTRIBUTE_NW		       (1ULL << 1)
> +#define KVM_MEMORY_ATTRIBUTE_NX		       (1ULL << 2)

[Severity: Medium]
Does the introduction of multiple memory attributes break the fast-path
optimization in kvm_range_has_memory_attributes()?

If attrs == 0, the fast-path optimization ignores the mask:

virt/kvm/kvm_main.c:kvm_range_has_memory_attributes() {
    ...
	if (!attrs)
		return !xas_find(&xas, end - 1);
    ...
}

Now that there are multiple attributes, a page might have
KVM_MEMORY_ATTRIBUTE_NR set but KVM_MEMORY_ATTRIBUTE_PRIVATE cleared.
If a caller checks if PRIVATE is 0 (i.e. mask = KVM_MEMORY_ATTRIBUTE_PRIVATE,
attrs = 0), the function incorrectly returns false simply because the NR entry
exists in the XArray.

>  #define KVM_MEMORY_ATTRIBUTE_PRIVATE           (1ULL << 3)
>  
>  #define KVM_CREATE_GUEST_MEMFD	_IOWR(KVMIO,  0xd4, struct kvm_create_guest_memfd)

[ ... ]

> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> index 80f581afb6a01..b6463b0b0b6d4 100644
> --- a/arch/x86/kvm/mmu/mmu.c
> +++ b/arch/x86/kvm/mmu/mmu.c
> @@ -8088,16 +8087,23 @@ bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm,
>  	}
>  
>  	/*
> -	 * Zap SPTEs even if the slot can't be mapped PRIVATE.  KVM x86 only
> -	 * supports KVM_MEMORY_ATTRIBUTE_PRIVATE, and so it *seems* like KVM
> -	 * can simply ignore such slots.  But if userspace is making memory
> -	 * PRIVATE, then KVM must prevent the guest from accessing the memory
> -	 * as shared.  And if userspace is making memory SHARED and this point
> -	 * is reached, then at least one page within the range was previously
> -	 * PRIVATE, i.e. the slot's possible hugepage ranges are changing.
> -	 * Zapping SPTEs in this case ensures KVM will reassess whether or not
> -	 * a hugepage can be used for affected ranges.
> +	 * For KVM_MEMORY_ATTRIBUTE_PRIVATE:
> +	 *  Zap SPTEs even if the slot can't be mapped PRIVATE.  KVM x86 only
> +	 *  supports KVM_MEMORY_ATTRIBUTE_PRIVATE, and so it *seems* like KVM
> +	 *  can simply ignore such slots.  But if userspace is making memory
> +	 *  PRIVATE, then KVM must prevent the guest from accessing the memory
> +	 *  as shared.  And if userspace is making memory SHARED and this point
> +	 *  is reached, then at least one page within the range was previously
> +	 *  PRIVATE, i.e. the slot's possible hugepage ranges are changing.
> +	 *  Zapping SPTEs in this case ensures KVM will reassess whether or not
> +	 *  a hugepage can be used for affected ranges.
> +	 *
> +	 * For KVM_MEMORY_ATTRIBUTE_NR/NW/NX:
> +	 *  Zap even when loosening restrictions R=>RW, which is nost strictly
> +	 *  necessary, but will allow KVM to reasses whether a hugepage can be
> +	 *  used for the affected pages.
>  	 */

[Severity: High]
Does setting these new attributes trigger an unbounded, non-yielding loop
holding the MMU lock?

When the KVM_SET_MEMORY_ATTRIBUTES ioctl is called, it eventually calls
kvm_arch_post_set_memory_attributes():

arch/x86/kvm/mmu/mmu.c:kvm_arch_post_set_memory_attributes() {
    ...
	for (gfn_t gfn = range->start; gfn < range->end; gfn++) {
		for_each_gfn_valid_sp_with_gptes(kvm, sp, gfn) {
			gen_update = true;
			trace_printk("needs gen update! %llx\n", gfn);
			goto exit_loop;
		}
	}
exit_loop:
    ...
	// todo: what to do with kvm_tdp_mmu_zap_invalidated_roots()?
	// add kvm_arch_post_set_memory_attributes_unlocked?
	return false;
}

Since the GFN range is controlled by the ioctl and can be massive, and the
loop executes under mmu_lock for write without cond_resched(), could this
freeze KVM and trigger host RCU stalls and soft lockups if no GPTEs are
found to break the loop early?

[Severity: Low]
Are the trace_printk() and literal "// todo:" comments in the above snippet
intended to remain in production code?

Using trace_printk() permanently allocates a large trace ring buffer at boot
and emits a loud warning banner in dmesg.

> +
>  	if (WARN_ON_ONCE(range->end <= range->start))
>  		return false;

[ ... ]

> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index fa4473d7c920a..a47b62c2c9cee 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -2421,10 +2421,15 @@ static int kvm_vm_ioctl_clear_dirty_log(struct kvm *kvm,
>  #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
>  u64 kvm_supported_mem_attributes(struct kvm *kvm)
>  {
> +	u64 supported_attrs = 0;
> +
> +	if (kvm_arch_has_memory_protection_attributes(kvm))
> +		supported_attrs |= KVM_MEMORY_ATTRIBUTE_PROT;
> +

[Severity: Critical]
Does KVM advertise and accept memory protection attributes without enforcing
them in the MMU?

KVM advertises KVM_MEMORY_ATTRIBUTE_PROT support to userspace here and allows
setting NR/NW/NX. However, the page fault handlers (e.g.,
__kvm_mmu_faultin_pfn, direct_page_fault, kvm_tdp_mmu_map) do not appear to
query kvm_get_memory_attributes() to intersect the requested access with the
memory attributes.

When the guest faults again after the SPTEs are zapped, the SPTE is rebuilt
with full host permissions, bypassing the memory protections entirely. Can this
allow a guest to escape the intended sandbox?

>  	if (kvm_arch_has_private_mem(kvm))
> -		return KVM_MEMORY_ATTRIBUTE_PRIVATE;
> +		supported_attrs |= KVM_MEMORY_ATTRIBUTE_PRIVATE;
>  
> -	return 0;
> +	return supported_attrs;
>  }

[ ... ]

> @@ -2596,6 +2601,25 @@ static int kvm_vm_set_mem_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
>  
>  	return r;
>  }
> +
> +bool __weak kvm_arch_mem_attributes_supported_prot(struct kvm *kvm, unsigned long attrs)
> +{
> +	WARN_ON_ONCE("KVM_MEMORY_ATTRIBUTE_PROT requires kvm_arch_mem_attributes_supported_prot()");

[Severity: Low]
Should this use WARN_ONCE(1, "...") instead?

The WARN_ON_ONCE macro expects a boolean expression. Since a string literal
evaluates to true, this will print the string's memory address or pointer as
the condition in the stack trace instead of the intended message.

> +	return false;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260716181456.402786-1-pbonzini@redhat.com?part=9

  reply	other threads:[~2026-07-16 18:39 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-16 18:14 [RFC PATCH 00/24] KVM: x86: Introduce memory protection attributes Paolo Bonzini
2026-07-16 18:14 ` [PATCH 01/24] KVM: selftests: Take into account mixed memory fault flags Paolo Bonzini
2026-07-16 18:14 ` [PATCH 02/24] KVM: Define and communicate KVM_EXIT_MEMORY_FAULT RWX flags to userspace Paolo Bonzini
2026-07-16 18:34   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 03/24] KVM: x86: hyperv: Introduce memory fault on hcalls with bad ingpas Paolo Bonzini
2026-07-16 18:34   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 04/24] KVM: x86/mmu: intersect writability from __kvm_faultin_pfn with fault->map_writable Paolo Bonzini
2026-07-16 18:14 ` [PATCH 05/24] KVM: x86/mmu: Extend map_writable to a full ACC_* mask Paolo Bonzini
2026-07-16 18:39   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 06/24] KVM: x86: Avoid warning when installing non-private memory attributes Paolo Bonzini
2026-07-16 18:42   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 07/24] KVM: x86/mmu: Init memslot hugepage information for non-private_mem VMs too Paolo Bonzini
2026-07-16 18:14 ` [PATCH 08/24] KVM: pass kvm == NULL case to kvm_arch_has_private_mem Paolo Bonzini
2026-07-16 18:14 ` [PATCH 09/24] KVM: Introduce NR/NW/NX memory attributes Paolo Bonzini
2026-07-16 18:39   ` sashiko-bot [this message]
2026-07-16 18:14 ` [PATCH 10/24] KVM: Include memory protections in result of gfn->hva conversion Paolo Bonzini
2026-07-16 18:29   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 11/24] KVM: Take memory protections into account in kvm_read/write_guest() Paolo Bonzini
2026-07-16 18:36   ` sashiko-bot
2026-07-16 19:17   ` Edgecombe, Rick P
2026-07-16 18:14 ` [PATCH 12/24] KVM: Encapsulate memattrs array into anonymous struct Paolo Bonzini
2026-07-16 18:14 ` [PATCH 13/24] KVM: Introduce kvm_check_gen()/kvm_memslots_check_gen() Paolo Bonzini
2026-07-16 18:26   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 14/24] KVM: Introduce a generation number for memory attributes Paolo Bonzini
2026-07-16 18:36   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 15/24] KVM: Take memory protections into account for accesses with cached gfn->hva Paolo Bonzini
2026-07-16 18:46   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 16/24] KVM: pfncache: Fail to refresh if it contains memory protections Paolo Bonzini
2026-07-16 18:14 ` [PATCH 17/24] KVM: x86/mmu: Take memory protection attributes into account during faults Paolo Bonzini
2026-07-16 19:13   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 18/24] KVM: x86/mmu: Issue memory fault exit if walk failed due to memory attribute Paolo Bonzini
2026-07-16 18:47   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 19/24] KVM: x86/mmu: Do not update accessed/dirty if guest PTE is read-only Paolo Bonzini
2026-07-16 18:40   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 20/24] KVM: x86/mmu: Do not prefetch sptes on gfns backed by memory attributes Paolo Bonzini
2026-07-16 18:35   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 21/24] KVM: x86/mmu: Obsolete all roots if memattr contains gPTEs Paolo Bonzini
2026-07-16 18:40   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 22/24] KVM: x86: selftests: Introduce memory attributes test Paolo Bonzini
2026-07-16 18:42   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 23/24] KVM: x86: selftests: Introduce memory attributes PTE test Paolo Bonzini
2026-07-16 18:49   ` sashiko-bot
2026-07-16 18:14 ` [PATCH 24/24] KVM: x86: selftests: Introduce memory attributes side-channel tests Paolo Bonzini
2026-07-16 18:54   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260716183922.AD05F1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.