aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiao Guangrong <guangrong.xiao@linux.intel.com>2015-05-11 10:55:21 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2015-05-11 11:17:50 -0400
commit0be0226f07d14b153a5eedf2bb86e1eb7dcefab5 (patch)
treea69e9c24597cd620922617e6315ba07b7bd63ca3
parent898761158be7682082955e3efa4ad24725305fc7 (diff)
KVM: MMU: fix SMAP virtualization
KVM may turn a user page to a kernel page when kernel writes a readonly user page if CR0.WP = 1. This shadow page entry will be reused after SMAP is enabled so that kernel is allowed to access this user page Fix it by setting SMAP && !CR0.WP into shadow page's role and reset mmu once CR4.SMAP is updated Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com> Cc: stable@vger.kernel.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--Documentation/virtual/kvm/mmu.txt18
-rw-r--r--arch/x86/include/asm/kvm_host.h1
-rw-r--r--arch/x86/kvm/mmu.c16
-rw-r--r--arch/x86/kvm/mmu.h2
-rw-r--r--arch/x86/kvm/x86.c8
5 files changed, 30 insertions, 15 deletions
diff --git a/Documentation/virtual/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt
index 53838d9c6295..c59bd9bc41ef 100644
--- a/Documentation/virtual/kvm/mmu.txt
+++ b/Documentation/virtual/kvm/mmu.txt
@@ -169,6 +169,10 @@ Shadow pages contain the following information:
169 Contains the value of cr4.smep && !cr0.wp for which the page is valid 169 Contains the value of cr4.smep && !cr0.wp for which the page is valid
170 (pages for which this is true are different from other pages; see the 170 (pages for which this is true are different from other pages; see the
171 treatment of cr0.wp=0 below). 171 treatment of cr0.wp=0 below).
172 role.smap_andnot_wp:
173 Contains the value of cr4.smap && !cr0.wp for which the page is valid
174 (pages for which this is true are different from other pages; see the
175 treatment of cr0.wp=0 below).
172 gfn: 176 gfn:
173 Either the guest page table containing the translations shadowed by this 177 Either the guest page table containing the translations shadowed by this
174 page, or the base page frame for linear translations. See role.direct. 178 page, or the base page frame for linear translations. See role.direct.
@@ -344,10 +348,16 @@ on fault type:
344 348
345(user write faults generate a #PF) 349(user write faults generate a #PF)
346 350
347In the first case there is an additional complication if CR4.SMEP is 351In the first case there are two additional complications:
348enabled: since we've turned the page into a kernel page, the kernel may now 352- if CR4.SMEP is enabled: since we've turned the page into a kernel page,
349execute it. We handle this by also setting spte.nx. If we get a user 353 the kernel may now execute it. We handle this by also setting spte.nx.
350fetch or read fault, we'll change spte.u=1 and spte.nx=gpte.nx back. 354 If we get a user fetch or read fault, we'll change spte.u=1 and
355 spte.nx=gpte.nx back.
356- if CR4.SMAP is disabled: since the page has been changed to a kernel
357 page, it can not be reused when CR4.SMAP is enabled. We set
358 CR4.SMAP && !CR0.WP into shadow page's role to avoid this case. Note,
359 here we do not care the case that CR4.SMAP is enabled since KVM will
360 directly inject #PF to guest due to failed permission check.
351 361
352To prevent an spte that was converted into a kernel page with cr0.wp=0 362To prevent an spte that was converted into a kernel page with cr0.wp=0
353from being written by the kernel after cr0.wp has changed to 1, we make 363from being written by the kernel after cr0.wp has changed to 1, we make
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index dea2e7e962e3..e61c3a4ee131 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -207,6 +207,7 @@ union kvm_mmu_page_role {
207 unsigned nxe:1; 207 unsigned nxe:1;
208 unsigned cr0_wp:1; 208 unsigned cr0_wp:1;
209 unsigned smep_andnot_wp:1; 209 unsigned smep_andnot_wp:1;
210 unsigned smap_andnot_wp:1;
210 }; 211 };
211}; 212};
212 213
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 209fe1477465..44a7d2515497 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3736,8 +3736,8 @@ static void reset_rsvds_bits_mask_ept(struct kvm_vcpu *vcpu,
3736 } 3736 }
3737} 3737}
3738 3738
3739void update_permission_bitmask(struct kvm_vcpu *vcpu, 3739static void update_permission_bitmask(struct kvm_vcpu *vcpu,
3740 struct kvm_mmu *mmu, bool ept) 3740 struct kvm_mmu *mmu, bool ept)
3741{ 3741{
3742 unsigned bit, byte, pfec; 3742 unsigned bit, byte, pfec;
3743 u8 map; 3743 u8 map;
@@ -3918,6 +3918,7 @@ static void init_kvm_tdp_mmu(struct kvm_vcpu *vcpu)
3918void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu) 3918void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu)
3919{ 3919{
3920 bool smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP); 3920 bool smep = kvm_read_cr4_bits(vcpu, X86_CR4_SMEP);
3921 bool smap = kvm_read_cr4_bits(vcpu, X86_CR4_SMAP);
3921 struct kvm_mmu *context = &vcpu->arch.mmu; 3922 struct kvm_mmu *context = &vcpu->arch.mmu;
3922 3923
3923 MMU_WARN_ON(VALID_PAGE(context->root_hpa)); 3924 MMU_WARN_ON(VALID_PAGE(context->root_hpa));
@@ -3936,6 +3937,8 @@ void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu)
3936 context->base_role.cr0_wp = is_write_protection(vcpu); 3937 context->base_role.cr0_wp = is_write_protection(vcpu);
3937 context->base_role.smep_andnot_wp 3938 context->base_role.smep_andnot_wp
3938 = smep && !is_write_protection(vcpu); 3939 = smep && !is_write_protection(vcpu);
3940 context->base_role.smap_andnot_wp
3941 = smap && !is_write_protection(vcpu);
3939} 3942}
3940EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu); 3943EXPORT_SYMBOL_GPL(kvm_init_shadow_mmu);
3941 3944
@@ -4207,12 +4210,18 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
4207 const u8 *new, int bytes) 4210 const u8 *new, int bytes)
4208{ 4211{
4209 gfn_t gfn = gpa >> PAGE_SHIFT; 4212 gfn_t gfn = gpa >> PAGE_SHIFT;
4210 union kvm_mmu_page_role mask = { .word = 0 };
4211 struct kvm_mmu_page *sp; 4213 struct kvm_mmu_page *sp;
4212 LIST_HEAD(invalid_list); 4214 LIST_HEAD(invalid_list);
4213 u64 entry, gentry, *spte; 4215 u64 entry, gentry, *spte;
4214 int npte; 4216 int npte;
4215 bool remote_flush, local_flush, zap_page; 4217 bool remote_flush, local_flush, zap_page;
4218 union kvm_mmu_page_role mask = (union kvm_mmu_page_role) {
4219 .cr0_wp = 1,
4220 .cr4_pae = 1,
4221 .nxe = 1,
4222 .smep_andnot_wp = 1,
4223 .smap_andnot_wp = 1,
4224 };
4216 4225
4217 /* 4226 /*
4218 * If we don't have indirect shadow pages, it means no page is 4227 * If we don't have indirect shadow pages, it means no page is
@@ -4238,7 +4247,6 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
4238 ++vcpu->kvm->stat.mmu_pte_write; 4247 ++vcpu->kvm->stat.mmu_pte_write;
4239 kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE); 4248 kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE);
4240 4249
4241 mask.cr0_wp = mask.cr4_pae = mask.nxe = mask.smep_andnot_wp = 1;
4242 for_each_gfn_indirect_valid_sp(vcpu->kvm, sp, gfn) { 4250 for_each_gfn_indirect_valid_sp(vcpu->kvm, sp, gfn) {
4243 if (detect_write_misaligned(sp, gpa, bytes) || 4251 if (detect_write_misaligned(sp, gpa, bytes) ||
4244 detect_write_flooding(sp)) { 4252 detect_write_flooding(sp)) {
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 06eb2fc1bab8..0ada65ecddcf 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -71,8 +71,6 @@ enum {
71int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct); 71int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct);
72void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu); 72void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu);
73void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly); 73void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly);
74void update_permission_bitmask(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
75 bool ept);
76 74
77static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm) 75static inline unsigned int kvm_mmu_available_pages(struct kvm *kvm)
78{ 76{
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index c73efcd03e29..986b3f5d0523 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -702,8 +702,9 @@ EXPORT_SYMBOL_GPL(kvm_set_xcr);
702int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) 702int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
703{ 703{
704 unsigned long old_cr4 = kvm_read_cr4(vcpu); 704 unsigned long old_cr4 = kvm_read_cr4(vcpu);
705 unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | 705 unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE |
706 X86_CR4_PAE | X86_CR4_SMEP; 706 X86_CR4_SMEP | X86_CR4_SMAP;
707
707 if (cr4 & CR4_RESERVED_BITS) 708 if (cr4 & CR4_RESERVED_BITS)
708 return 1; 709 return 1;
709 710
@@ -744,9 +745,6 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
744 (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE))) 745 (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
745 kvm_mmu_reset_context(vcpu); 746 kvm_mmu_reset_context(vcpu);
746 747
747 if ((cr4 ^ old_cr4) & X86_CR4_SMAP)
748 update_permission_bitmask(vcpu, vcpu->arch.walk_mmu, false);
749
750 if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE) 748 if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE)
751 kvm_update_cpuid(vcpu); 749 kvm_update_cpuid(vcpu);
752 750