This patch adds SMAP handling logic when setting CR4 for guests

Signed-off-by: Feng Wu <feng...@intel.com>
---
 arch/x86/kvm/cpuid.h |  8 ++++++++
 arch/x86/kvm/mmu.c   | 22 +++++++++++++++++++---
 arch/x86/kvm/mmu.h   |  2 ++
 arch/x86/kvm/x86.c   |  6 ++++++
 4 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index f1e4895..63124a2 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 40772ef..33e656c 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3591,14 +3591,15 @@ 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, smep, smap;
 
        smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP);
+       smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
        for (byte = 0; byte < ARRAY_SIZE(mmu->permissions); ++byte) {
                pfec = byte << 1;
                map = 0;
@@ -3617,11 +3618,26 @@ 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
+                                *   - !(CPL<3 && X86_EFLAGS_AC is set)
+                                *   - Page fault in kernel mode
+                                */
+                               smap = smap && u && !uf &&
+                                       !((kvm_x86_ops->get_cpl(vcpu) < 3) &&
+                                       ((kvm_x86_ops->get_rflags(vcpu) &
+                                       X86_EFLAGS_AC) == 1));
                        } 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) || smap;
                        map |= fault << bit;
                }
                mmu->permissions[byte] = map;
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 2926152..8820f78 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -73,6 +73,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)
 {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4e33b85..f8293fb 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -630,6 +630,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;
 
@@ -658,6 +661,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);
 
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to