All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v3 2/4] KVM: Add SMAP support when setting CR4
  2014-03-31 18:08 ` [PATCH v3 2/4] KVM: Add SMAP support when setting CR4 Feng Wu
@ 2014-03-31 13:30   ` Paolo Bonzini
  2014-04-01  1:17     ` Wu, Feng
  0 siblings, 1 reply; 9+ messages in thread
From: Paolo Bonzini @ 2014-03-31 13:30 UTC (permalink / raw)
  To: Feng Wu, gleb, hpa, kvm

Just a few comments...

> -static void update_permission_bitmask(struct kvm_vcpu *vcpu,
> +void update_permission_bitmask(struct kvm_vcpu *vcpu,
>  		struct kvm_mmu *mmu, bool ept)
>  {
>  	unsigned bit, byte, pfec;
>  	u8 map;
> -	bool fault, x, w, u, wf, uf, ff, smep;
> +	bool fault, x, w, u, wf, uf, ff, smapf, cr4_smap, smep, smap = 0;
>
>  	smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP);

Can you make an additional patch to rename this to cr4_smep?

> +	cr4_smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
>  	for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) {
>  		pfec = byte << 1;
>  		map = 0;
>  		wf = pfec & PFERR_WRITE_MASK;
>  		uf = pfec & PFERR_USER_MASK;
>  		ff = pfec & PFERR_FETCH_MASK;
> +		/*
> +		 * PFERR_RSVD_MASK bit is used to detect SMAP violation.
> +		 * We will check it in permission_fault(), this bit is
> +		 * set in pfec for normal fault, while it is cleared for
> +		 * SMAP violations.
> +		 */

"This bit is set in PFEC if we the access is _not_ subject to SMAP 
restrictions, and cleared otherwise.  The bit is only meaningful if
the SMAP bit is set in CR4."

> +		smapf = !(pfec & PFERR_RSVD_MASK);
>  		for (bit = 0; bit < 8; ++bit) {
>  			x = bit & ACC_EXEC_MASK;
>  			w = bit & ACC_WRITE_MASK;
> @@ -3627,11 +3635,32 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
>  				w |= !is_write_protection(vcpu) && !uf;
>  				/* Disallow supervisor fetches of user code if cr4.smep */
>  				x &= !(smep && u && !uf);
> +
> +				/*
> +				 * SMAP:kernel-mode data accesses from user-mode
> +				 * mappings should fault. A fault is considered
> +				 * as a SMAP violation if all of the following
> +				 * conditions are ture:
> +				 *   - X86_CR4_SMAP is set in CR4
> +				 *   - An user page is accessed
> +				 *   - Page fault in kernel mode
> +				 *   - !(CPL<3 && X86_EFLAGS_AC is set)

- if CPL < 3, EFLAGS.AC is clear

> +				 *   Here, we cover the first three conditions,
> +				 *   The CPL and X86_EFLAGS_AC is in smapf,which
> +				 *   permission_fault() computes dynamically.

The fourth is computed dynamically in permission_fault() and is in SMAPF.

> +				 *   Also, SMAP does not affect instruction
> +				 *   fetches, add the !ff check here to make it
> +				 *   clearer.
> +				 */
> +				smap = cr4_smap && u && !uf && !ff;
>  			} else
>  				/* Not really needed: no U/S accesses on ept  */
>  				u = 1;
>
> -			fault = (ff && !x) || (uf && !u) || (wf && !w);
> +			fault = (ff && !x) || (uf && !u) || (wf && !w) ||
> +				(smapf && smap);
>  			map |= fault << bit;
>  		}
>  		mmu->permissions[byte] = map;
> diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
> index 2926152..822190f 100644
> --- a/arch/x86/kvm/mmu.h
> +++ b/arch/x86/kvm/mmu.h
> @@ -44,11 +44,17 @@
>  #define PT_DIRECTORY_LEVEL 2
>  #define PT_PAGE_TABLE_LEVEL 1
>
> -#define PFERR_PRESENT_MASK (1U << 0)
> -#define PFERR_WRITE_MASK (1U << 1)
> -#define PFERR_USER_MASK (1U << 2)
> -#define PFERR_RSVD_MASK (1U << 3)
> -#define PFERR_FETCH_MASK (1U << 4)
> +#define PFERR_PRESENT_BIT 0
> +#define PFERR_WRITE_BIT 1
> +#define PFERR_USER_BIT 2
> +#define PFERR_RSVD_BIT 3
> +#define PFERR_FETCH_BIT 4
> +
> +#define PFERR_PRESENT_MASK (1U << PFERR_PRESENT_BIT)
> +#define PFERR_WRITE_MASK (1U << PFERR_WRITE_BIT)
> +#define PFERR_USER_MASK (1U << PFERR_USER_BIT)
> +#define PFERR_RSVD_MASK (1U << PFERR_RSVD_BIT)
> +#define PFERR_FETCH_MASK (1U << PFERR_FETCH_BIT)
>
>  int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]);
>  void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask);
> @@ -73,6 +79,8 @@ int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct);
>  void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
>  void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context,
>  		bool execonly);
> +void update_permission_bitmask(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
> +		bool ept);
>
>  static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
>  {
> @@ -110,10 +118,30 @@ static inline bool is_write_protection(struct kvm_vcpu *vcpu)
>   * Will a fault with a given page-fault error code (pfec) cause a permission
>   * fault with the given access (in ACC_* format)?
>   */
> -static inline bool permission_fault(struct kvm_mmu *mmu, unsigned pte_access,
> -				    unsigned pfec)
> +static inline bool permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
> +				    unsigned pte_access, unsigned pfec)
>  {
> -	return (mmu->permissions[pfec >> 1] >> pte_access) & 1;
> +	int cpl = kvm_x86_ops->get_cpl(vcpu);
> +	unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
> +
> +	/*
> +	 * If CPL < 3, SMAP prevention are disabled if EFLAGS.AC = 1.
> +	 *
> +	 * If CPL = 3, SMAP applies to all supervisor-mode data accesses
> +	 * (these are implicit supervisor accesses) regardless of the value
> +	 * of EFLAGS.AC.
> +	 *
> +	 * This computes (cpl < 3) && (rflags & X86_EFLAGS_AC), leaving
> +	 * the result in X86_EFLAGS_AC. We then insert it in place of
> +	 * the PFERR_RSVD_MASK bit; this bit will always be zero in pfec,
> +	 * but it will be one in index if SMAP checks are being overridden.
> +	 * It is important to keep this branchless.
> +	 */
> +	unsigned long smap = (cpl-3) & (rflags & X86_EFLAGS_AC);

Spaces around minus.

> +	int index = (pfec >> 1) +
> +		    (smap >> (X86_EFLAGS_AC_BIT - PFERR_RSVD_BIT + 1));
> +
> +	return (mmu->permissions[index] >> pte_access) & 1;
>  }
>
>  void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
> diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
> index cba218a..4107765 100644
> --- a/arch/x86/kvm/paging_tmpl.h
> +++ b/arch/x86/kvm/paging_tmpl.h
> @@ -353,7 +353,7 @@ retry_walk:
>  		walker->ptes[walker->level - 1] = pte;
>  	} while (!is_last_gpte(mmu, walker->level, pte));
>
> -	if (unlikely(permission_fault(mmu, pte_access, access))) {
> +	if (unlikely(permission_fault(vcpu, mmu, pte_access, access))) {
>  		errcode |= PFERR_PRESENT_MASK;
>  		goto error;
>  	}
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 2b85784..5869c6d 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -646,6 +646,9 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
>  	if (!guest_cpuid_has_smep(vcpu) && (cr4 & X86_CR4_SMEP))
>  		return 1;
>
> +	if (!guest_cpuid_has_smap(vcpu) && (cr4 & X86_CR4_SMAP))
> +		return 1;
> +
>  	if (!guest_cpuid_has_fsgsbase(vcpu) && (cr4 & X86_CR4_FSGSBASE))
>  		return 1;
>
> @@ -674,6 +677,9 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
>  	    (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
>  		kvm_mmu_reset_context(vcpu);
>
> +	if ((cr4 ^ old_cr4) & X86_CR4_SMAP)
> +		update_permission_bitmask(vcpu, vcpu->arch.walk_mmu, false);
> +
>  	if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE)
>  		kvm_update_cpuid(vcpu);
>
> @@ -4108,7 +4114,8 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
>  		| (write ? PFERR_WRITE_MASK : 0);
>
>  	if (vcpu_match_mmio_gva(vcpu, gva)
> -	    && !permission_fault(vcpu->arch.walk_mmu, vcpu->arch.access, access)) {
> +	    && !permission_fault(vcpu, vcpu->arch.walk_mmu,
> +				 vcpu->arch.access, access)) {
>  		*gpa = vcpu->arch.mmio_gfn << PAGE_SHIFT |
>  					(gva & (PAGE_SIZE - 1));
>  		trace_vcpu_match_mmio(gva, *gpa, write, false);
>

Thanks!

Paolo

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 0/4] KVM: enable Intel SMAP for KVM
@ 2014-03-31 18:08 Feng Wu
  2014-03-31 18:08 ` [PATCH v3 1/4] KVM: Remove SMAP bit from CR4_RESERVED_BITS Feng Wu
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Feng Wu @ 2014-03-31 18:08 UTC (permalink / raw)
  To: pbonzini, gleb, hpa, kvm; +Cc: Feng Wu

Supervisor Mode Access Prevention (SMAP) is a new security feature 
disclosed by Intel, please refer to the following document: 

http://software.intel.com/sites/default/files/319433-014.pdf
 
Every access to a linear address is either a supervisor-mode access
or a user-mode access. All accesses performed while the current
privilege level (CPL) is less than 3 are supervisor-mode accesses.
If CPL = 3, accesses are generally user-mode accesses. However, some
operations implicitly access system data structures, and the resulting
accesses to those data structures are supervisor-mode accesses regardless
of CPL. Examples of such implicit supervisor accesses include the following:
accesses to the global descriptor table (GDT) or local descriptor table
(LDT) to load a segment descriptor; accesses to the interrupt descriptor
table (IDT) when delivering an interrupt or exception; and accesses to the
task-state segment (TSS) as part of a task switch or change of CPL.

If CR4.SMAP = 1, supervisor-mode data accesses are not allowed to linear
addresses that are accessible in user mode. If CPL < 3, SMAP protections
are disabled if EFLAGS.AC = 1. If CPL = 3, SMAP applies to all supervisor-mode
data accesses (these are implicit supervisor accesses) regardless of the
value of EFLAGS.AC.

This patchset pass-through SMAP feature to guests, and let guests
benefit from it.

Version 1:
  * Remove SMAP bit from CR4_RESERVED_BITS.
  * Add SMAP support when setting CR4
  * Disable SMAP for guests in EPT realmode and EPT unpaging mode
  * Expose SMAP feature to guest

Version 2:
  * Change the logic of updating mmu permission bitmap for SMAP violation
  * Expose SMAP feature to guest in the last patch of this series.

Version 3:
  * Changes in update_permission_bitmask().
  * Use a branchless way suggested by Paolo Bonzini to detect SMAP
    violation in permission_fault(). 

Feng Wu (4):
  KVM: Remove SMAP bit from CR4_RESERVED_BITS.
  KVM: Add SMAP support when setting CR4
  KVM: Disable SMAP for guests in EPT realmode and EPT unpaging mode
  KVM: expose SMAP feature to guest

 arch/x86/include/asm/kvm_host.h |  2 +-
 arch/x86/kvm/cpuid.c            |  2 +-
 arch/x86/kvm/cpuid.h            |  8 ++++++++
 arch/x86/kvm/mmu.c              | 35 +++++++++++++++++++++++++++++---
 arch/x86/kvm/mmu.h              | 44 +++++++++++++++++++++++++++++++++--------
 arch/x86/kvm/paging_tmpl.h      |  2 +-
 arch/x86/kvm/vmx.c              | 11 ++++++-----
 arch/x86/kvm/x86.c              |  9 ++++++++-
 8 files changed, 93 insertions(+), 20 deletions(-)

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/4] KVM: Remove SMAP bit from CR4_RESERVED_BITS.
  2014-03-31 18:08 [PATCH v3 0/4] KVM: enable Intel SMAP for KVM Feng Wu
@ 2014-03-31 18:08 ` Feng Wu
  2014-03-31 18:08 ` [PATCH v3 2/4] KVM: Add SMAP support when setting CR4 Feng Wu
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Feng Wu @ 2014-03-31 18:08 UTC (permalink / raw)
  To: pbonzini, gleb, hpa, kvm; +Cc: Feng Wu

This patch removes SMAP bit from CR4_RESERVED_BITS.

Signed-off-by: Feng Wu <feng.wu@intel.com>
---
 arch/x86/include/asm/kvm_host.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index fdf83af..4eeb049 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -60,7 +60,7 @@
 			  | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE     \
 			  | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \
 			  | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \
-			  | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
+			  | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE | X86_CR4_SMAP))
 
 #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
 
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 2/4] KVM: Add SMAP support when setting CR4
  2014-03-31 18:08 [PATCH v3 0/4] KVM: enable Intel SMAP for KVM Feng Wu
  2014-03-31 18:08 ` [PATCH v3 1/4] KVM: Remove SMAP bit from CR4_RESERVED_BITS Feng Wu
@ 2014-03-31 18:08 ` Feng Wu
  2014-03-31 13:30   ` Paolo Bonzini
  2014-03-31 18:08 ` [PATCH v3 3/4] KVM: Disable SMAP for guests in EPT realmode and EPT unpaging mode Feng Wu
  2014-03-31 18:08 ` [PATCH v3 4/4] KVM: expose SMAP feature to guest Feng Wu
  3 siblings, 1 reply; 9+ messages in thread
From: Feng Wu @ 2014-03-31 18:08 UTC (permalink / raw)
  To: pbonzini, gleb, hpa, kvm; +Cc: Feng Wu

This patch adds SMAP handling logic when setting CR4 for guests

Thanks a lot to Paolo Bonzini for his suggestion to use the branchless
way to detect SMAP violation.

Signed-off-by: Feng Wu <feng.wu@intel.com>
---
 arch/x86/kvm/cpuid.h       |  8 ++++++++
 arch/x86/kvm/mmu.c         | 35 ++++++++++++++++++++++++++++++++---
 arch/x86/kvm/mmu.h         | 44 ++++++++++++++++++++++++++++++++++++--------
 arch/x86/kvm/paging_tmpl.h |  2 +-
 arch/x86/kvm/x86.c         |  9 ++++++++-
 5 files changed, 85 insertions(+), 13 deletions(-)

diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index a2a1bb7..eeecbed 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -48,6 +48,14 @@ static inline bool guest_cpuid_has_smep(struct kvm_vcpu *vcpu)
 	return best && (best->ebx & bit(X86_FEATURE_SMEP));
 }
 
+static inline bool guest_cpuid_has_smap(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpuid_entry2 *best;
+
+	best = kvm_find_cpuid_entry(vcpu, 7, 0);
+	return best && (best->ebx & bit(X86_FEATURE_SMAP));
+}
+
 static inline bool guest_cpuid_has_fsgsbase(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpuid_entry2 *best;
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 9b53135..5a1ed38 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3601,20 +3601,28 @@ static void reset_rsvds_bits_mask_ept(struct kvm_vcpu *vcpu,
 	}
 }
 
-static void update_permission_bitmask(struct kvm_vcpu *vcpu,
+void update_permission_bitmask(struct kvm_vcpu *vcpu,
 		struct kvm_mmu *mmu, bool ept)
 {
 	unsigned bit, byte, pfec;
 	u8 map;
-	bool fault, x, w, u, wf, uf, ff, smep;
+	bool fault, x, w, u, wf, uf, ff, smapf, cr4_smap, smep, smap = 0;
 
 	smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP);
+	cr4_smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
 	for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) {
 		pfec = byte << 1;
 		map = 0;
 		wf = pfec & PFERR_WRITE_MASK;
 		uf = pfec & PFERR_USER_MASK;
 		ff = pfec & PFERR_FETCH_MASK;
+		/*
+		 * PFERR_RSVD_MASK bit is used to detect SMAP violation.
+		 * We will check it in permission_fault(), this bit is
+		 * set in pfec for normal fault, while it is cleared for
+		 * SMAP violations.
+		 */
+		smapf = !(pfec & PFERR_RSVD_MASK);
 		for (bit = 0; bit < 8; ++bit) {
 			x = bit & ACC_EXEC_MASK;
 			w = bit & ACC_WRITE_MASK;
@@ -3627,11 +3635,32 @@ static void update_permission_bitmask(struct kvm_vcpu *vcpu,
 				w |= !is_write_protection(vcpu) && !uf;
 				/* Disallow supervisor fetches of user code if cr4.smep */
 				x &= !(smep && u && !uf);
+
+				/*
+				 * SMAP:kernel-mode data accesses from user-mode
+				 * mappings should fault. A fault is considered
+				 * as a SMAP violation if all of the following
+				 * conditions are ture:
+				 *   - X86_CR4_SMAP is set in CR4
+				 *   - An user page is accessed
+				 *   - Page fault in kernel mode
+				 *   - !(CPL<3 && X86_EFLAGS_AC is set)
+				 *
+				 *   Here, we cover the first three conditions,
+				 *   The CPL and X86_EFLAGS_AC is in smapf,which
+				 *   permission_fault() computes dynamically.
+				 *
+				 *   Also, SMAP does not affect instruction
+				 *   fetches, add the !ff check here to make it
+				 *   clearer.
+				 */
+				smap = cr4_smap && u && !uf && !ff;
 			} else
 				/* Not really needed: no U/S accesses on ept  */
 				u = 1;
 
-			fault = (ff && !x) || (uf && !u) || (wf && !w);
+			fault = (ff && !x) || (uf && !u) || (wf && !w) ||
+				(smapf && smap);
 			map |= fault << bit;
 		}
 		mmu->permissions[byte] = map;
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 2926152..822190f 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -44,11 +44,17 @@
 #define PT_DIRECTORY_LEVEL 2
 #define PT_PAGE_TABLE_LEVEL 1
 
-#define PFERR_PRESENT_MASK (1U << 0)
-#define PFERR_WRITE_MASK (1U << 1)
-#define PFERR_USER_MASK (1U << 2)
-#define PFERR_RSVD_MASK (1U << 3)
-#define PFERR_FETCH_MASK (1U << 4)
+#define PFERR_PRESENT_BIT 0
+#define PFERR_WRITE_BIT 1
+#define PFERR_USER_BIT 2
+#define PFERR_RSVD_BIT 3
+#define PFERR_FETCH_BIT 4
+
+#define PFERR_PRESENT_MASK (1U << PFERR_PRESENT_BIT)
+#define PFERR_WRITE_MASK (1U << PFERR_WRITE_BIT)
+#define PFERR_USER_MASK (1U << PFERR_USER_BIT)
+#define PFERR_RSVD_MASK (1U << PFERR_RSVD_BIT)
+#define PFERR_FETCH_MASK (1U << PFERR_FETCH_BIT)
 
 int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]);
 void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask);
@@ -73,6 +79,8 @@ int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct);
 void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
 void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context,
 		bool execonly);
+void update_permission_bitmask(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+		bool ept);
 
 static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
 {
@@ -110,10 +118,30 @@ static inline bool is_write_protection(struct kvm_vcpu *vcpu)
  * Will a fault with a given page-fault error code (pfec) cause a permission
  * fault with the given access (in ACC_* format)?
  */
-static inline bool permission_fault(struct kvm_mmu *mmu, unsigned pte_access,
-				    unsigned pfec)
+static inline bool permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+				    unsigned pte_access, unsigned pfec)
 {
-	return (mmu->permissions[pfec >> 1] >> pte_access) & 1;
+	int cpl = kvm_x86_ops->get_cpl(vcpu);
+	unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
+
+	/*
+	 * If CPL < 3, SMAP prevention are disabled if EFLAGS.AC = 1.
+	 *
+	 * If CPL = 3, SMAP applies to all supervisor-mode data accesses
+	 * (these are implicit supervisor accesses) regardless of the value
+	 * of EFLAGS.AC.
+	 *
+	 * This computes (cpl < 3) && (rflags & X86_EFLAGS_AC), leaving
+	 * the result in X86_EFLAGS_AC. We then insert it in place of
+	 * the PFERR_RSVD_MASK bit; this bit will always be zero in pfec,
+	 * but it will be one in index if SMAP checks are being overridden.
+	 * It is important to keep this branchless.
+	 */
+	unsigned long smap = (cpl-3) & (rflags & X86_EFLAGS_AC);
+	int index = (pfec >> 1) +
+		    (smap >> (X86_EFLAGS_AC_BIT - PFERR_RSVD_BIT + 1));
+
+	return (mmu->permissions[index] >> pte_access) & 1;
 }
 
 void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index cba218a..4107765 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -353,7 +353,7 @@ retry_walk:
 		walker->ptes[walker->level - 1] = pte;
 	} while (!is_last_gpte(mmu, walker->level, pte));
 
-	if (unlikely(permission_fault(mmu, pte_access, access))) {
+	if (unlikely(permission_fault(vcpu, mmu, pte_access, access))) {
 		errcode |= PFERR_PRESENT_MASK;
 		goto error;
 	}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2b85784..5869c6d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -646,6 +646,9 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 	if (!guest_cpuid_has_smep(vcpu) && (cr4 & X86_CR4_SMEP))
 		return 1;
 
+	if (!guest_cpuid_has_smap(vcpu) && (cr4 & X86_CR4_SMAP))
+		return 1;
+
 	if (!guest_cpuid_has_fsgsbase(vcpu) && (cr4 & X86_CR4_FSGSBASE))
 		return 1;
 
@@ -674,6 +677,9 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 	    (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
 		kvm_mmu_reset_context(vcpu);
 
+	if ((cr4 ^ old_cr4) & X86_CR4_SMAP)
+		update_permission_bitmask(vcpu, vcpu->arch.walk_mmu, false);
+
 	if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE)
 		kvm_update_cpuid(vcpu);
 
@@ -4108,7 +4114,8 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
 		| (write ? PFERR_WRITE_MASK : 0);
 
 	if (vcpu_match_mmio_gva(vcpu, gva)
-	    && !permission_fault(vcpu->arch.walk_mmu, vcpu->arch.access, access)) {
+	    && !permission_fault(vcpu, vcpu->arch.walk_mmu,
+				 vcpu->arch.access, access)) {
 		*gpa = vcpu->arch.mmio_gfn << PAGE_SHIFT |
 					(gva & (PAGE_SIZE - 1));
 		trace_vcpu_match_mmio(gva, *gpa, write, false);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 3/4] KVM: Disable SMAP for guests in EPT realmode and EPT unpaging mode
  2014-03-31 18:08 [PATCH v3 0/4] KVM: enable Intel SMAP for KVM Feng Wu
  2014-03-31 18:08 ` [PATCH v3 1/4] KVM: Remove SMAP bit from CR4_RESERVED_BITS Feng Wu
  2014-03-31 18:08 ` [PATCH v3 2/4] KVM: Add SMAP support when setting CR4 Feng Wu
@ 2014-03-31 18:08 ` Feng Wu
  2014-03-31 18:08 ` [PATCH v3 4/4] KVM: expose SMAP feature to guest Feng Wu
  3 siblings, 0 replies; 9+ messages in thread
From: Feng Wu @ 2014-03-31 18:08 UTC (permalink / raw)
  To: pbonzini, gleb, hpa, kvm; +Cc: Feng Wu

SMAP is disabled if CPU is in non-paging mode in hardware.
However KVM always uses paging mode to emulate guest non-paging
mode with TDP. To emulate this behavior, SMAP needs to be
manually disabled when guest switches to non-paging mode.

Signed-off-by: Feng Wu <feng.wu@intel.com>
---
 arch/x86/kvm/vmx.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 3927528..e58cb5f 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3452,13 +3452,14 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
 			hw_cr4 &= ~X86_CR4_PAE;
 			hw_cr4 |= X86_CR4_PSE;
 			/*
-			 * SMEP is disabled if CPU is in non-paging mode in
-			 * hardware. However KVM always uses paging mode to
+			 * SMEP/SMAP is disabled if CPU is in non-paging mode
+			 * in hardware. However KVM always uses paging mode to
 			 * emulate guest non-paging mode with TDP.
-			 * To emulate this behavior, SMEP needs to be manually
-			 * disabled when guest switches to non-paging mode.
+			 * To emulate this behavior, SMEP/SMAP needs to be
+			 * manually disabled when guest switches to non-paging
+			 * mode.
 			 */
-			hw_cr4 &= ~X86_CR4_SMEP;
+			hw_cr4 &= ~(X86_CR4_SMEP | X86_CR4_SMAP);
 		} else if (!(cr4 & X86_CR4_PAE)) {
 			hw_cr4 &= ~X86_CR4_PAE;
 		}
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 4/4] KVM: expose SMAP feature to guest
  2014-03-31 18:08 [PATCH v3 0/4] KVM: enable Intel SMAP for KVM Feng Wu
                   ` (2 preceding siblings ...)
  2014-03-31 18:08 ` [PATCH v3 3/4] KVM: Disable SMAP for guests in EPT realmode and EPT unpaging mode Feng Wu
@ 2014-03-31 18:08 ` Feng Wu
  3 siblings, 0 replies; 9+ messages in thread
From: Feng Wu @ 2014-03-31 18:08 UTC (permalink / raw)
  To: pbonzini, gleb, hpa, kvm; +Cc: Feng Wu

This patch exposes SMAP feature to guest

Signed-off-by: Feng Wu <feng.wu@intel.com>
---
 arch/x86/kvm/cpuid.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index c697625..deb5f9b 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -303,7 +303,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
 	/* cpuid 7.0.ebx */
 	const u32 kvm_supported_word9_x86_features =
 		F(FSGSBASE) | F(BMI1) | F(HLE) | F(AVX2) | F(SMEP) |
-		F(BMI2) | F(ERMS) | f_invpcid | F(RTM);
+		F(BMI2) | F(ERMS) | f_invpcid | F(RTM) | F(SMAP);
 
 	/* all calls to cpuid_count() should be made on the same cpu */
 	get_cpu();
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* RE: [PATCH v3 2/4] KVM: Add SMAP support when setting CR4
  2014-03-31 13:30   ` Paolo Bonzini
@ 2014-04-01  1:17     ` Wu, Feng
  2014-04-01  9:26       ` Paolo Bonzini
  0 siblings, 1 reply; 9+ messages in thread
From: Wu, Feng @ 2014-04-01  1:17 UTC (permalink / raw)
  To: Paolo Bonzini, gleb, hpa, kvm



> -----Original Message-----
> From: kvm-owner@vger.kernel.org [mailto:kvm-owner@vger.kernel.org] On
> Behalf Of Paolo Bonzini
> Sent: Monday, March 31, 2014 9:31 PM
> To: Wu, Feng; gleb@redhat.com; hpa@zytor.com; kvm@vger.kernel.org
> Subject: Re: [PATCH v3 2/4] KVM: Add SMAP support when setting CR4
> 
> Just a few comments...
> 
> > -static void update_permission_bitmask(struct kvm_vcpu *vcpu,
> > +void update_permission_bitmask(struct kvm_vcpu *vcpu,
> >  		struct kvm_mmu *mmu, bool ept)
> >  {
> >  	unsigned bit, byte, pfec;
> >  	u8 map;
> > -	bool fault, x, w, u, wf, uf, ff, smep;
> > +	bool fault, x, w, u, wf, uf, ff, smapf, cr4_smap, smep, smap = 0;
> >
> >  	smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP);
> 
> Can you make an additional patch to rename this to cr4_smep?

Sure! I noticed your comments about this issue in the previous email, I was prepare to make a patch for it, will send out it today!
> 
> > +	cr4_smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
> >  	for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) {
> >  		pfec = byte << 1;
> >  		map = 0;
> >  		wf = pfec & PFERR_WRITE_MASK;
> >  		uf = pfec & PFERR_USER_MASK;
> >  		ff = pfec & PFERR_FETCH_MASK;
> > +		/*
> > +		 * PFERR_RSVD_MASK bit is used to detect SMAP violation.
> > +		 * We will check it in permission_fault(), this bit is
> > +		 * set in pfec for normal fault, while it is cleared for
> > +		 * SMAP violations.
> > +		 */
> 
> "This bit is set in PFEC if we the access is _not_ subject to SMAP
> restrictions, and cleared otherwise.  The bit is only meaningful if
> the SMAP bit is set in CR4."
> 
> > +		smapf = !(pfec & PFERR_RSVD_MASK);
> >  		for (bit = 0; bit < 8; ++bit) {
> >  			x = bit & ACC_EXEC_MASK;
> >  			w = bit & ACC_WRITE_MASK;
> > @@ -3627,11 +3635,32 @@ static void update_permission_bitmask(struct
> kvm_vcpu *vcpu,
> >  				w |= !is_write_protection(vcpu) && !uf;
> >  				/* Disallow supervisor fetches of user code if cr4.smep */
> >  				x &= !(smep && u && !uf);
> > +
> > +				/*
> > +				 * SMAP:kernel-mode data accesses from user-mode
> > +				 * mappings should fault. A fault is considered
> > +				 * as a SMAP violation if all of the following
> > +				 * conditions are ture:
> > +				 *   - X86_CR4_SMAP is set in CR4
> > +				 *   - An user page is accessed
> > +				 *   - Page fault in kernel mode
> > +				 *   - !(CPL<3 && X86_EFLAGS_AC is set)
> 
> - if CPL < 3, EFLAGS.AC is clear

Should it be "if CPL =3 or EFLAGS.AC is clear" ?

> 
> > +				 *   Here, we cover the first three conditions,
> > +				 *   The CPL and X86_EFLAGS_AC is in smapf,which
> > +				 *   permission_fault() computes dynamically.
> 
> The fourth is computed dynamically in permission_fault() and is in SMAPF.
> 
> > +				 *   Also, SMAP does not affect instruction
> > +				 *   fetches, add the !ff check here to make it
> > +				 *   clearer.
> > +				 */
> > +				smap = cr4_smap && u && !uf && !ff;
> >  			} else
> >  				/* Not really needed: no U/S accesses on ept  */
> >  				u = 1;
> >
> > -			fault = (ff && !x) || (uf && !u) || (wf && !w);
> > +			fault = (ff && !x) || (uf && !u) || (wf && !w) ||
> > +				(smapf && smap);
> >  			map |= fault << bit;
> >  		}
> >  		mmu->permissions[byte] = map;
> > diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
> > index 2926152..822190f 100644
> > --- a/arch/x86/kvm/mmu.h
> > +++ b/arch/x86/kvm/mmu.h
> > @@ -44,11 +44,17 @@
> >  #define PT_DIRECTORY_LEVEL 2
> >  #define PT_PAGE_TABLE_LEVEL 1
> >
> > -#define PFERR_PRESENT_MASK (1U << 0)
> > -#define PFERR_WRITE_MASK (1U << 1)
> > -#define PFERR_USER_MASK (1U << 2)
> > -#define PFERR_RSVD_MASK (1U << 3)
> > -#define PFERR_FETCH_MASK (1U << 4)
> > +#define PFERR_PRESENT_BIT 0
> > +#define PFERR_WRITE_BIT 1
> > +#define PFERR_USER_BIT 2
> > +#define PFERR_RSVD_BIT 3
> > +#define PFERR_FETCH_BIT 4
> > +
> > +#define PFERR_PRESENT_MASK (1U << PFERR_PRESENT_BIT)
> > +#define PFERR_WRITE_MASK (1U << PFERR_WRITE_BIT)
> > +#define PFERR_USER_MASK (1U << PFERR_USER_BIT)
> > +#define PFERR_RSVD_MASK (1U << PFERR_RSVD_BIT)
> > +#define PFERR_FETCH_MASK (1U << PFERR_FETCH_BIT)
> >
> >  int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64
> sptes[4]);
> >  void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask);
> > @@ -73,6 +79,8 @@ int handle_mmio_page_fault_common(struct
> kvm_vcpu *vcpu, u64 addr, bool direct);
> >  void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu
> *context);
> >  void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu
> *context,
> >  		bool execonly);
> > +void update_permission_bitmask(struct kvm_vcpu *vcpu, struct kvm_mmu
> *mmu,
> > +		bool ept);
> >
> >  static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
> >  {
> > @@ -110,10 +118,30 @@ static inline bool is_write_protection(struct
> kvm_vcpu *vcpu)
> >   * Will a fault with a given page-fault error code (pfec) cause a permission
> >   * fault with the given access (in ACC_* format)?
> >   */
> > -static inline bool permission_fault(struct kvm_mmu *mmu, unsigned
> pte_access,
> > -				    unsigned pfec)
> > +static inline bool permission_fault(struct kvm_vcpu *vcpu, struct kvm_mmu
> *mmu,
> > +				    unsigned pte_access, unsigned pfec)
> >  {
> > -	return (mmu->permissions[pfec >> 1] >> pte_access) & 1;
> > +	int cpl = kvm_x86_ops->get_cpl(vcpu);
> > +	unsigned long rflags = kvm_x86_ops->get_rflags(vcpu);
> > +
> > +	/*
> > +	 * If CPL < 3, SMAP prevention are disabled if EFLAGS.AC = 1.
> > +	 *
> > +	 * If CPL = 3, SMAP applies to all supervisor-mode data accesses
> > +	 * (these are implicit supervisor accesses) regardless of the value
> > +	 * of EFLAGS.AC.
> > +	 *
> > +	 * This computes (cpl < 3) && (rflags & X86_EFLAGS_AC), leaving
> > +	 * the result in X86_EFLAGS_AC. We then insert it in place of
> > +	 * the PFERR_RSVD_MASK bit; this bit will always be zero in pfec,
> > +	 * but it will be one in index if SMAP checks are being overridden.
> > +	 * It is important to keep this branchless.
> > +	 */
> > +	unsigned long smap = (cpl-3) & (rflags & X86_EFLAGS_AC);
> 
> Spaces around minus.
> 
> > +	int index = (pfec >> 1) +
> > +		    (smap >> (X86_EFLAGS_AC_BIT - PFERR_RSVD_BIT + 1));
> > +
> > +	return (mmu->permissions[index] >> pte_access) & 1;
> >  }
> >
> >  void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
> > diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
> > index cba218a..4107765 100644
> > --- a/arch/x86/kvm/paging_tmpl.h
> > +++ b/arch/x86/kvm/paging_tmpl.h
> > @@ -353,7 +353,7 @@ retry_walk:
> >  		walker->ptes[walker->level - 1] = pte;
> >  	} while (!is_last_gpte(mmu, walker->level, pte));
> >
> > -	if (unlikely(permission_fault(mmu, pte_access, access))) {
> > +	if (unlikely(permission_fault(vcpu, mmu, pte_access, access))) {
> >  		errcode |= PFERR_PRESENT_MASK;
> >  		goto error;
> >  	}
> > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> > index 2b85784..5869c6d 100644
> > --- a/arch/x86/kvm/x86.c
> > +++ b/arch/x86/kvm/x86.c
> > @@ -646,6 +646,9 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned
> long cr4)
> >  	if (!guest_cpuid_has_smep(vcpu) && (cr4 & X86_CR4_SMEP))
> >  		return 1;
> >
> > +	if (!guest_cpuid_has_smap(vcpu) && (cr4 & X86_CR4_SMAP))
> > +		return 1;
> > +
> >  	if (!guest_cpuid_has_fsgsbase(vcpu) && (cr4 & X86_CR4_FSGSBASE))
> >  		return 1;
> >
> > @@ -674,6 +677,9 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned
> long cr4)
> >  	    (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
> >  		kvm_mmu_reset_context(vcpu);
> >
> > +	if ((cr4 ^ old_cr4) & X86_CR4_SMAP)
> > +		update_permission_bitmask(vcpu, vcpu->arch.walk_mmu, false);
> > +
> >  	if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE)
> >  		kvm_update_cpuid(vcpu);
> >
> > @@ -4108,7 +4114,8 @@ static int vcpu_mmio_gva_to_gpa(struct
> kvm_vcpu *vcpu, unsigned long gva,
> >  		| (write ? PFERR_WRITE_MASK : 0);
> >
> >  	if (vcpu_match_mmio_gva(vcpu, gva)
> > -	    && !permission_fault(vcpu->arch.walk_mmu, vcpu->arch.access,
> access)) {
> > +	    && !permission_fault(vcpu, vcpu->arch.walk_mmu,
> > +				 vcpu->arch.access, access)) {
> >  		*gpa = vcpu->arch.mmio_gfn << PAGE_SHIFT |
> >  					(gva & (PAGE_SIZE - 1));
> >  		trace_vcpu_match_mmio(gva, *gpa, write, false);
> >
> 
> Thanks!
> 
> Paolo
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Thanks,
Feng

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/4] KVM: Add SMAP support when setting CR4
  2014-04-01  1:17     ` Wu, Feng
@ 2014-04-01  9:26       ` Paolo Bonzini
  2014-04-01 11:54         ` Wu, Feng
  0 siblings, 1 reply; 9+ messages in thread
From: Paolo Bonzini @ 2014-04-01  9:26 UTC (permalink / raw)
  To: Wu, Feng, gleb, hpa, kvm

Il 01/04/2014 03:17, Wu, Feng ha scritto:
>>> A fault is considered
>>> > > +				 * as a SMAP violation if all of the following
>>> > > +				 * conditions are ture:
>>> > > +				 *   - X86_CR4_SMAP is set in CR4
>>> > > +				 *   - An user page is accessed
>>> > > +				 *   - Page fault in kernel mode
>>> > > +				 *   - !(CPL<3 && X86_EFLAGS_AC is set)
>> >
>> > - if CPL < 3, EFLAGS.AC is clear
> Should it be "if CPL =3 or EFLAGS.AC is clear" ?
>

What I meant is "if CPL < 3, EFLAGS.AC must also be clear", but your 
version is fine too.  You choose!

Paolo

^ permalink raw reply	[flat|nested] 9+ messages in thread

* RE: [PATCH v3 2/4] KVM: Add SMAP support when setting CR4
  2014-04-01  9:26       ` Paolo Bonzini
@ 2014-04-01 11:54         ` Wu, Feng
  0 siblings, 0 replies; 9+ messages in thread
From: Wu, Feng @ 2014-04-01 11:54 UTC (permalink / raw)
  To: Paolo Bonzini, gleb, hpa, kvm



> -----Original Message-----
> From: Paolo Bonzini [mailto:pbonzini@redhat.com]
> Sent: Tuesday, April 01, 2014 5:27 PM
> To: Wu, Feng; gleb@redhat.com; hpa@zytor.com; kvm@vger.kernel.org
> Subject: Re: [PATCH v3 2/4] KVM: Add SMAP support when setting CR4
> 
> Il 01/04/2014 03:17, Wu, Feng ha scritto:
> >>> A fault is considered
> >>> > > +				 * as a SMAP violation if all of the following
> >>> > > +				 * conditions are ture:
> >>> > > +				 *   - X86_CR4_SMAP is set in CR4
> >>> > > +				 *   - An user page is accessed
> >>> > > +				 *   - Page fault in kernel mode
> >>> > > +				 *   - !(CPL<3 && X86_EFLAGS_AC is set)
> >> >
> >> > - if CPL < 3, EFLAGS.AC is clear
> > Should it be "if CPL =3 or EFLAGS.AC is clear" ?
> >
> 
> What I meant is "if CPL < 3, EFLAGS.AC must also be clear", but your
> version is fine too.  You choose!

Thanks for your comments! :)
BTW: I tested nested today, this patch set works well for nested virtualization!
> 
> Paolo

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-04-01 11:55 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-31 18:08 [PATCH v3 0/4] KVM: enable Intel SMAP for KVM Feng Wu
2014-03-31 18:08 ` [PATCH v3 1/4] KVM: Remove SMAP bit from CR4_RESERVED_BITS Feng Wu
2014-03-31 18:08 ` [PATCH v3 2/4] KVM: Add SMAP support when setting CR4 Feng Wu
2014-03-31 13:30   ` Paolo Bonzini
2014-04-01  1:17     ` Wu, Feng
2014-04-01  9:26       ` Paolo Bonzini
2014-04-01 11:54         ` Wu, Feng
2014-03-31 18:08 ` [PATCH v3 3/4] KVM: Disable SMAP for guests in EPT realmode and EPT unpaging mode Feng Wu
2014-03-31 18:08 ` [PATCH v3 4/4] KVM: expose SMAP feature to guest Feng Wu

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.