aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2018-06-06 11:38:09 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2018-06-12 09:06:34 -0400
commit3c9fa24ca7c9c47605672916491f79e8ccacb9e6 (patch)
tree938330204174cabc88a26f00f72ce8652bcb49c0
parentce14e868a54edeb2e30cb7a7b104a2fc4b9d76ca (diff)
kvm: x86: use correct privilege level for sgdt/sidt/fxsave/fxrstor access
The functions that were used in the emulation of fxrstor, fxsave, sgdt and sidt were originally meant for task switching, and as such they did not check privilege levels. This is very bad when the same functions are used in the emulation of unprivileged instructions. This is CVE-2018-10853. The obvious fix is to add a new argument to ops->read_std and ops->write_std, which decides whether the access is a "system" access or should use the processor's CPL. Fixes: 129a72a0d3c8 ("KVM: x86: Introduce segmented_write_std", 2017-01-12) Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm_emulate.h6
-rw-r--r--arch/x86/kvm/emulate.c12
-rw-r--r--arch/x86/kvm/x86.c22
3 files changed, 26 insertions, 14 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index b24b1c8b3979..0f82cd91cd3c 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -107,11 +107,12 @@ struct x86_emulate_ops {
107 * @addr: [IN ] Linear address from which to read. 107 * @addr: [IN ] Linear address from which to read.
108 * @val: [OUT] Value read from memory, zero-extended to 'u_long'. 108 * @val: [OUT] Value read from memory, zero-extended to 'u_long'.
109 * @bytes: [IN ] Number of bytes to read from memory. 109 * @bytes: [IN ] Number of bytes to read from memory.
110 * @system:[IN ] Whether the access is forced to be at CPL0.
110 */ 111 */
111 int (*read_std)(struct x86_emulate_ctxt *ctxt, 112 int (*read_std)(struct x86_emulate_ctxt *ctxt,
112 unsigned long addr, void *val, 113 unsigned long addr, void *val,
113 unsigned int bytes, 114 unsigned int bytes,
114 struct x86_exception *fault); 115 struct x86_exception *fault, bool system);
115 116
116 /* 117 /*
117 * read_phys: Read bytes of standard (non-emulated/special) memory. 118 * read_phys: Read bytes of standard (non-emulated/special) memory.
@@ -129,10 +130,11 @@ struct x86_emulate_ops {
129 * @addr: [IN ] Linear address to which to write. 130 * @addr: [IN ] Linear address to which to write.
130 * @val: [OUT] Value write to memory, zero-extended to 'u_long'. 131 * @val: [OUT] Value write to memory, zero-extended to 'u_long'.
131 * @bytes: [IN ] Number of bytes to write to memory. 132 * @bytes: [IN ] Number of bytes to write to memory.
133 * @system:[IN ] Whether the access is forced to be at CPL0.
132 */ 134 */
133 int (*write_std)(struct x86_emulate_ctxt *ctxt, 135 int (*write_std)(struct x86_emulate_ctxt *ctxt,
134 unsigned long addr, void *val, unsigned int bytes, 136 unsigned long addr, void *val, unsigned int bytes,
135 struct x86_exception *fault); 137 struct x86_exception *fault, bool system);
136 /* 138 /*
137 * fetch: Read bytes of standard (non-emulated/special) memory. 139 * fetch: Read bytes of standard (non-emulated/special) memory.
138 * Used for instruction fetch. 140 * Used for instruction fetch.
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index fcf54642b293..4c4f4263420c 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -815,14 +815,14 @@ static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel)
815static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear, 815static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear,
816 void *data, unsigned size) 816 void *data, unsigned size)
817{ 817{
818 return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); 818 return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, true);
819} 819}
820 820
821static int linear_write_system(struct x86_emulate_ctxt *ctxt, 821static int linear_write_system(struct x86_emulate_ctxt *ctxt,
822 ulong linear, void *data, 822 ulong linear, void *data,
823 unsigned int size) 823 unsigned int size)
824{ 824{
825 return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); 825 return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, true);
826} 826}
827 827
828static int segmented_read_std(struct x86_emulate_ctxt *ctxt, 828static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
@@ -836,7 +836,7 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
836 rc = linearize(ctxt, addr, size, false, &linear); 836 rc = linearize(ctxt, addr, size, false, &linear);
837 if (rc != X86EMUL_CONTINUE) 837 if (rc != X86EMUL_CONTINUE)
838 return rc; 838 return rc;
839 return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); 839 return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, false);
840} 840}
841 841
842static int segmented_write_std(struct x86_emulate_ctxt *ctxt, 842static int segmented_write_std(struct x86_emulate_ctxt *ctxt,
@@ -850,7 +850,7 @@ static int segmented_write_std(struct x86_emulate_ctxt *ctxt,
850 rc = linearize(ctxt, addr, size, true, &linear); 850 rc = linearize(ctxt, addr, size, true, &linear);
851 if (rc != X86EMUL_CONTINUE) 851 if (rc != X86EMUL_CONTINUE)
852 return rc; 852 return rc;
853 return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); 853 return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, false);
854} 854}
855 855
856/* 856/*
@@ -2928,12 +2928,12 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
2928#ifdef CONFIG_X86_64 2928#ifdef CONFIG_X86_64
2929 base |= ((u64)base3) << 32; 2929 base |= ((u64)base3) << 32;
2930#endif 2930#endif
2931 r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL); 2931 r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL, true);
2932 if (r != X86EMUL_CONTINUE) 2932 if (r != X86EMUL_CONTINUE)
2933 return false; 2933 return false;
2934 if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg)) 2934 if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg))
2935 return false; 2935 return false;
2936 r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL); 2936 r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL, true);
2937 if (r != X86EMUL_CONTINUE) 2937 if (r != X86EMUL_CONTINUE)
2938 return false; 2938 return false;
2939 if ((perm >> bit_idx) & mask) 2939 if ((perm >> bit_idx) & mask)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2bbe9858e187..439fb0c7dbc0 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4811,10 +4811,15 @@ EXPORT_SYMBOL_GPL(kvm_read_guest_virt);
4811 4811
4812static int emulator_read_std(struct x86_emulate_ctxt *ctxt, 4812static int emulator_read_std(struct x86_emulate_ctxt *ctxt,
4813 gva_t addr, void *val, unsigned int bytes, 4813 gva_t addr, void *val, unsigned int bytes,
4814 struct x86_exception *exception) 4814 struct x86_exception *exception, bool system)
4815{ 4815{
4816 struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); 4816 struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
4817 return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, exception); 4817 u32 access = 0;
4818
4819 if (!system && kvm_x86_ops->get_cpl(vcpu) == 3)
4820 access |= PFERR_USER_MASK;
4821
4822 return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, exception);
4818} 4823}
4819 4824
4820static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt, 4825static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt,
@@ -4858,12 +4863,17 @@ out:
4858} 4863}
4859 4864
4860static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, 4865static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val,
4861 unsigned int bytes, struct x86_exception *exception) 4866 unsigned int bytes, struct x86_exception *exception,
4867 bool system)
4862{ 4868{
4863 struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); 4869 struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
4870 u32 access = PFERR_WRITE_MASK;
4871
4872 if (!system && kvm_x86_ops->get_cpl(vcpu) == 3)
4873 access |= PFERR_USER_MASK;
4864 4874
4865 return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, 4875 return kvm_write_guest_virt_helper(addr, val, bytes, vcpu,
4866 PFERR_WRITE_MASK, exception); 4876 access, exception);
4867} 4877}
4868 4878
4869int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, 4879int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val,
@@ -4882,8 +4892,8 @@ int handle_ud(struct kvm_vcpu *vcpu)
4882 struct x86_exception e; 4892 struct x86_exception e;
4883 4893
4884 if (force_emulation_prefix && 4894 if (force_emulation_prefix &&
4885 kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, 4895 kvm_read_guest_virt(vcpu, kvm_get_linear_rip(vcpu),
4886 kvm_get_linear_rip(vcpu), sig, sizeof(sig), &e) == 0 && 4896 sig, sizeof(sig), &e) == 0 &&
4887 memcmp(sig, "\xf\xbkvm", sizeof(sig)) == 0) { 4897 memcmp(sig, "\xf\xbkvm", sizeof(sig)) == 0) {
4888 kvm_rip_write(vcpu, kvm_rip_read(vcpu) + sizeof(sig)); 4898 kvm_rip_write(vcpu, kvm_rip_read(vcpu) + sizeof(sig));
4889 emul_type = 0; 4899 emul_type = 0;