All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Paolo Bonzini" <pbonzini@redhat.com>, kvm@vger.kernel.org
Subject: Re: [PATCH 28/45] KVM: x86/mmu: Take memory protection attributes into account during faults
Date: Mon, 02 Nov 2026 18:26:26 +0000	[thread overview]
Message-ID: <sashiko-outbox-193934@kernel.org> (raw)
In-Reply-To: <20261102174512.8903-12-pbonzini@redhat.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] KVM: x86/mmu: make_small_spte() re-enables exec on KVM_MEMORY_ATTRIBUTE_NX
- [High] KVM: x86/mmu: spurious -EFAULT in kvm_faultin_memory_protections() with SMEP
- [Medium] KVM: x86/mmu: broken ACC_ALL check in kvm_faultin_memory_protections()
- [Medium] KVM: x86/mmu: FNAME(sync_spte) installs 0-permission EPT SPTE on NX GFN
--

commit ed18ad0e63078d1672b15a00740ac1eefc27f904
Author: Nicolas Saenz Julienne <nsaenz@amazon.com>

KVM: x86/mmu: Take memory protection attributes into account during faults

This commit checks per-gfn memory protection attributes during guest page
faults and SPTE synchronization, restricting SPTE permissions or exiting to
userspace with -EFAULT when an access is prohibited. It also adds a trace
event when faulting in a gfn with restricted memory protections.

Link: https://patch.msgid.link/20260918135030.171564-26-pbonzini@redhat.com

> diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
> index 140a8dd5b3f5b..c4bd37427bb72 100644
> --- a/arch/x86/kvm/mmu/mmu.c
> +++ b/arch/x86/kvm/mmu/mmu.c
> @@ -4705,6 +4705,50 @@ static int kvm_mmu_faultin_pfn_gmem(struct kvm_vcpu *vcpu,
>  	return RET_PF_CONTINUE;
>  }
>  
> +static inline unsigned kvm_get_gfn_protections(struct kvm_vcpu *vcpu, gfn_t gfn)
> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	unsigned int access = vcpu->arch.mmu->root_role.access;
> +	unsigned long attrs = kvm_get_vm_memory_attributes(kvm, gfn);
> +	if (!attrs)
> +		return access;
> +
> +	WARN_ON_ONCE(!kvm_vm_mem_attributes_valid(kvm, attrs));
> +
> +	if (!kvm_mem_attributes_may_read(attrs))
> +		access &= ~ACC_READ_MASK;
> +	if (!kvm_mem_attributes_may_write(attrs))
> +		access &= ~ACC_WRITE_MASK;
> +	if (!kvm_mem_attributes_may_exec(attrs)) {
> +		access &= ~ACC_EXEC_MASK;
> +		if (shadow_xu_mask)
> +			access &= ~ACC_USER_EXEC_MASK;
> +	}
> +
> +	return access;
> +}
> +
> +static int kvm_faultin_memory_protections(struct kvm_vcpu *vcpu,
> +					  struct kvm_page_fault *fault)
> +{
> +	unsigned access;
> +
> +	/* Memory attributes don't apply to MMIO regions */
> +	if (unlikely(!fault->slot))
> +		return RET_PF_CONTINUE;
> +
> +	access = kvm_get_gfn_protections(vcpu, fault->gfn);
> +	if (access == ACC_ALL)
> +		return RET_PF_CONTINUE;

[Severity: Medium]
On AMD processors with GMET enabled, does this fast-path check in
arch/x86/kvm/mmu/mmu.c:kvm_faultin_memory_protections() ever succeed when
no memory protection attributes are present?

In arch/x86/kvm/mmu/mmu.c:kvm_calc_tdp_mmu_root_page_role(), root_role.access
has ACC_USER_MASK cleared when GMET is active:

	/* All TDP pages are supervisor-executable */
	role.access = ACC_ALL;
	if (role.cr4_smep && shadow_user_mask)
		role.access &= ~ACC_USER_MASK;

When attrs is 0, kvm_get_gfn_protections() returns root_role.access
(ACC_ALL & ~ACC_USER_MASK), so comparing access against ACC_ALL in
kvm_faultin_memory_protections() evaluates to false on every TDP page fault
and unconditionally triggers trace_kvm_faultin_memory_protections() and
__permission_fault(). Should this compare access against
vcpu->arch.mmu->root_role.access instead?

> +
> +	trace_kvm_faultin_memory_protections(vcpu, fault, access);
> +	if (__permission_fault(vcpu->arch.mmu, access, fault))
> +		return -EFAULT;

[Severity: High]
As reported by Sashiko on v2 [1], in
arch/x86/kvm/mmu/mmu.c:kvm_faultin_memory_protections(), can passing access
derived from vcpu->arch.mmu->root_role.access into __permission_fault() cause
spurious -EFAULT exits on valid supervisor instruction fetches when SMEP or
nested GMET is enabled?

In arch/x86/kvm/mmu/mmu.c:init_kvm_shadow_mmu() (when the guest enables
cr4.smep) and arch/x86/kvm/mmu/mmu.c:kvm_init_shadow_npt_mmu() (when L1
enables GMET), root_role.cr4_smep is set to 1 while root_role.access remains
ACC_ALL (which includes ACC_USER_MASK):

	cpu_role.base.cr4_smep = (misc_ctl & SVM_MISC_ENABLE_GMET) != 0;
	init_kvm_page_walk(vcpu, &vcpu->arch.ngpa_walk, cpu_role);
	root_role = cpu_role.base;

When arch/x86/kvm/mmu/mmu.c:__update_permission_bitmask() builds
mmu->fmt.permissions for non-EPT MMUs with cr4_smep enabled, any access mask
with ACC_USER_MASK set is marked as faulting on supervisor instruction
fetches:

	/* Disallow supervisor fetches of user code if cr4.smep */
	if (cr4_smep)
		ff |= (pfec & PFERR_FETCH_MASK) ? kf : 0;

If a guest under shadow paging or nested shadow NPT performs a supervisor
instruction fetch from a supervisor page (guest PTE U=0) whose GFN has
KVM_MEMORY_ATTRIBUTE_NW set, kvm_get_gfn_protections() returns
ACC_READ_MASK | ACC_EXEC_MASK | ACC_USER_MASK. Doesn't __permission_fault()
then treat the access as a SMEP violation because ACC_USER_MASK is still set
in access, returning a spurious -EFAULT to userspace?

> +
> +	fault->host_access &= access;
> +	return RET_PF_CONTINUE;
> +}

[Severity: High]
When a huge page is mapped on a GFN range with uniform
KVM_MEMORY_ATTRIBUTE_NX and later split into 4K pages, will
arch/x86/kvm/mmu/spte.c:make_small_spte() re-enable execute permissions on
the resulting child SPTEs?

During a read or write fault, kvm_faultin_memory_protections() clears
ACC_EXEC_MASK in fault->host_access, and make_spte() installs a
non-executable huge SPTE. However, sp->role.access retains ACC_EXEC_MASK.

When the huge page is later split via
arch/x86/kvm/mmu/tdp_mmu.c:tdp_mmu_split_huge_page() or
arch/x86/kvm/mmu/mmu.c:shadow_mmu_split_huge_page(), make_small_spte()
restores execute permissions from role.access whenever the NX huge page
mitigation is enabled:

	if (is_nx_huge_page_enabled(kvm))
		child_spte = change_spte_executable(child_spte, role.access);

Doesn't this make the split 4K SPTEs executable in hardware despite
KVM_MEMORY_ATTRIBUTE_NX being set on the underlying GFNs?

[ ... ]

> diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
> index 860dae872d044..e46182750567b 100644
> --- a/arch/x86/kvm/mmu/paging_tmpl.h
> +++ b/arch/x86/kvm/mmu/paging_tmpl.h
> @@ -994,7 +994,7 @@ static int FNAME(sync_spte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, int
>  
>  	sptep = &sp->spt[i];
>  	spte = *sptep;
> -	host_access = ACC_ALL;
> +	host_access = kvm_get_gfn_protections(vcpu, gfn);
>  	if (!(spte & shadow_host_writable_mask))
>  		host_access &= ~ACC_WRITE_MASK;
>  	slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);

[Severity: Medium]
In arch/x86/kvm/mmu/paging_tmpl.h:FNAME(sync_spte), what happens on nested
EPT with execute-only support when L1 updates an unsync EPT12 entry to be
execute-only (pte_access = ACC_EXEC_MASK | ACC_USER_EXEC_MASK) on a GFN that
has KVM_MEMORY_ATTRIBUTE_NX set?

Earlier in FNAME(sync_spte), the check for an effective non-present SPTE runs
before host_access is applied:

	if ((pte_access | shadow_present_mask) == SHADOW_NONPRESENT_VALUE ||
	    gfn != kvm_mmu_page_get_gfn(sp, i)) {
		drop_spte(vcpu->kvm, &sp->spt[i]);
		return 1;
	}

Because pte_access still has execute bits set at that point, the SPTE is not
dropped. When make_spte() then masks pte_access with host_access:

	WARN_ON_ONCE((pte_access | shadow_present_mask) == SHADOW_NONPRESENT_VALUE);
	...
	pte_access &= host_access;

all remaining permission bits in pte_access are cleared, leaving an EPT SPTE
with SPTE_MMU_PRESENT_MASK set but hardware bits 2:0 and 10 all zero. Should
the SHADOW_NONPRESENT_VALUE check in FNAME(sync_spte) account for the
protections from kvm_get_gfn_protections() so the SPTE is dropped instead?

[1] https://lore.kernel.org/r/20260918081543.139871-22-pbonzini@redhat.com

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

  reply	other threads:[~2026-11-02 18:26 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-02 17:40 [PATCH v4 00/45] KVM: x86: Introduce memory protection attributes Paolo Bonzini
2026-11-02 17:40 ` [PATCH 01/45] KVM: nVMX/nSVM: check unconditionally whether CR3 is valid Paolo Bonzini
2026-11-02 18:05   ` sashiko-bot
2026-11-02 17:40 ` [PATCH 02/45] KVM: x86/hyperv: do not overwrite hc->ingpa for SIGNAL_EVENT hypercall Paolo Bonzini
2026-11-02 17:40 ` [PATCH 03/45] KVM: x86: apply nGPA->GPA translation to KVM_HC_CLOCK_PAIRING Paolo Bonzini
2026-11-02 17:40 ` [PATCH 04/45] KVM: x86/emulate: Check TSS busy-bit writes during task switches Paolo Bonzini
2026-11-02 18:22   ` sashiko-bot
2026-11-02 17:40 ` [PATCH 05/45] KVM: loongarch: do full validity check on the gfn-to-hva cache Paolo Bonzini
2026-11-02 17:40 ` [PATCH 06/45] KVM: selftests: Test address translation for Hyper-V direct L2 hypercalls Paolo Bonzini
2026-11-02 17:40 ` [PATCH 07/45] KVM: selftests: Take into account mixed memory fault flags Paolo Bonzini
2026-11-02 17:50   ` sashiko-bot
2026-11-02 17:40 ` [PATCH 08/45] selftests: kvm: drop TEST_ASSERT_SUPPORTED_ATTRIBUTES Paolo Bonzini
2026-11-02 17:40 ` [PATCH 09/45] KVM: Define and communicate KVM_EXIT_MEMORY_FAULT RWX flags to userspace Paolo Bonzini
2026-11-02 17:55   ` sashiko-bot
2026-11-02 17:40 ` [PATCH 10/45] KVM: x86: Introduce memory fault on invalid hypercalls reads/writes Paolo Bonzini
2026-11-02 17:40 ` [PATCH 11/45] KVM: selftests: test hypercall memory fault exits Paolo Bonzini
2026-11-02 17:58   ` sashiko-bot
2026-11-02 17:40 ` [PATCH 12/45] KVM: x86/mmu: intersect writability from __kvm_faultin_pfn with fault->map_writable Paolo Bonzini
2026-11-02 17:40 ` [PATCH 13/45] KVM: x86/mmu: Extend map_writable to a full ACC_* mask Paolo Bonzini
2026-11-02 17:40 ` [PATCH 14/45] KVM: x86/mmu: Init memslot hugepage information for non-private_mem VMs too Paolo Bonzini
2026-11-02 17:40 ` [PATCH 15/45] KVM: VMX: return error from kvm_set_cr* Paolo Bonzini
2026-11-02 17:41 ` [PATCH 16/45] KVM: adjust for presence of more than one attribute Paolo Bonzini
2026-11-02 18:03   ` sashiko-bot
2026-11-02 17:44 ` [PATCH 17/45] KVM: Introduce NR/NW/NX memory attributes Paolo Bonzini
2026-11-02 18:04   ` sashiko-bot
2026-11-03  9:25   ` kernel test robot
2026-11-02 17:44 ` [PATCH 18/45] KVM: Include memory protections in result of gfn->hva conversion Paolo Bonzini
2026-11-02 17:44 ` [PATCH 19/45] KVM: Introduce kvm_fetch_guest_page() and use it for x86 Paolo Bonzini
2026-11-02 17:44 ` [PATCH 20/45] KVM: Take memory protections into account for memory read/write/fetch Paolo Bonzini
2026-11-02 17:44 ` [PATCH 21/45] KVM: Take memory protections into account for __kvm_vcpu_map Paolo Bonzini
2026-11-02 17:44 ` [PATCH 22/45] KVM: Encapsulate memattrs array into anonymous struct Paolo Bonzini
2026-11-02 17:44 ` [PATCH 23/45] KVM: Introduce kvm_check_gen()/kvm_memslots_check_gen() Paolo Bonzini
2026-11-02 18:04   ` sashiko-bot
2026-11-03 18:07   ` kernel test robot
2026-11-02 17:44 ` [PATCH 24/45] KVM: Introduce a generation number for memory attributes Paolo Bonzini
2026-11-02 18:20   ` sashiko-bot
2026-11-03 14:11   ` kernel test robot
2026-11-02 17:44 ` [PATCH 25/45] KVM: Take memory protections into account for accesses with cached gfn->hva Paolo Bonzini
2026-11-02 18:14   ` sashiko-bot
2026-11-02 17:44 ` [PATCH 26/45] KVM: pfncache: Fail to refresh if it contains memory protections Paolo Bonzini
2026-11-02 18:09   ` sashiko-bot
2026-11-02 17:44 ` [PATCH 27/45] KVM: x86/mmu: Do not prefetch sptes on gfns backed by memory attributes Paolo Bonzini
2026-11-02 17:44 ` [PATCH 28/45] KVM: x86/mmu: Take memory protection attributes into account during faults Paolo Bonzini
2026-11-02 18:26   ` sashiko-bot [this message]
2026-11-02 17:44 ` [PATCH 29/45] KVM: x86/emulate: change return value of emulator_io_permitted to int Paolo Bonzini
2026-11-02 17:44 ` [PATCH 30/45] KVM: x86/emulate: Propagate memory faults to userspace Paolo Bonzini
2026-11-02 18:32   ` sashiko-bot
2026-11-02 17:44 ` [PATCH 31/45] KVM: x86: "Handle" failed decode when skipping instructions Paolo Bonzini
2026-11-02 18:18   ` sashiko-bot
2026-11-02 17:44 ` [PATCH 32/45] KVM: vmx/sgx: make return value of sgx_gva_to_gpa consistent with its callers Paolo Bonzini
2026-11-02 17:45 ` [PATCH 33/45] KVM: x86: Allow page fault fixup to return errors Paolo Bonzini
2026-11-02 17:45 ` [PATCH 34/45] KVM: x86/mmu: Adjust gva_to_gpa to allow returning an error Paolo Bonzini
2026-11-02 18:19   ` sashiko-bot
2026-11-02 17:45 ` [PATCH 35/45] KVM: x86/mmu: Propagate errors from nested GPA translation Paolo Bonzini
2026-11-02 17:45 ` [PATCH 36/45] KVM: x86: Propagate memory faults through load_pdptrs() Paolo Bonzini
2026-11-02 18:29   ` sashiko-bot
2026-11-02 17:45 ` [PATCH 37/45] KVM: x86/mmu: Issue memory fault exit if walk failed due to memory attribute Paolo Bonzini
2026-11-02 18:32   ` sashiko-bot
2026-11-02 17:45 ` [PATCH 38/45] KVM: x86: mark VM as dead after KVM_SET_SREGS fails to load PDPTRs Paolo Bonzini
2026-11-02 18:28   ` sashiko-bot
2026-11-02 17:45 ` [PATCH 39/45] KVM: VMX: mark VM dead on shadow VMCS or eVMCS access failures Paolo Bonzini
2026-11-02 18:40   ` sashiko-bot
2026-11-02 17:45 ` [PATCH 40/45] KVM: let kvm_arch_post_set_memory_attributes drop mmu_lock Paolo Bonzini
2026-11-02 17:45 ` [PATCH 41/45] KVM: x86/mmu: Obsolete all roots if memattr contains gPTEs Paolo Bonzini
2026-11-02 17:45 ` [PATCH 42/45] KVM: x86: selftests: Introduce memory protection attributes test Paolo Bonzini
2026-11-02 18:43   ` sashiko-bot
2026-11-02 17:45 ` [PATCH 43/45] KVM: x86: selftests: Introduce memory attributes PTE test Paolo Bonzini
2026-11-02 17:45 ` [PATCH 44/45] KVM: x86: selftests: Introduce memory attributes side-channel tests Paolo Bonzini
2026-11-02 18:41   ` sashiko-bot
2026-11-02 17:45 ` [PATCH 45/45] KVM: x86: split out parts of load_pdptrs Paolo Bonzini
2026-11-03 14:40 ` [syzbot ci] Re: KVM: x86: Introduce memory protection attributes syzbot ci

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=sashiko-outbox-193934@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.