Skip to content

Commit 13d1c5b

Browse files
bonzinigregkh
authored andcommitted
kvm: x86: use correct privilege level for sgdt/sidt/fxsave/fxrstor access
commit 3c9fa24 upstream. 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: 129a72a ("KVM: x86: Introduce segmented_write_std", 2017-01-12) Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 018e519 commit 13d1c5b

3 files changed

Lines changed: 24 additions & 12 deletions

File tree

arch/x86/include/asm/kvm_emulate.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,12 @@ struct x86_emulate_ops {
105105
* @addr: [IN ] Linear address from which to read.
106106
* @val: [OUT] Value read from memory, zero-extended to 'u_long'.
107107
* @bytes: [IN ] Number of bytes to read from memory.
108+
* @system:[IN ] Whether the access is forced to be at CPL0.
108109
*/
109110
int (*read_std)(struct x86_emulate_ctxt *ctxt,
110111
unsigned long addr, void *val,
111112
unsigned int bytes,
112-
struct x86_exception *fault);
113+
struct x86_exception *fault, bool system);
113114

114115
/*
115116
* read_phys: Read bytes of standard (non-emulated/special) memory.
@@ -127,10 +128,11 @@ struct x86_emulate_ops {
127128
* @addr: [IN ] Linear address to which to write.
128129
* @val: [OUT] Value write to memory, zero-extended to 'u_long'.
129130
* @bytes: [IN ] Number of bytes to write to memory.
131+
* @system:[IN ] Whether the access is forced to be at CPL0.
130132
*/
131133
int (*write_std)(struct x86_emulate_ctxt *ctxt,
132134
unsigned long addr, void *val, unsigned int bytes,
133-
struct x86_exception *fault);
135+
struct x86_exception *fault, bool system);
134136
/*
135137
* fetch: Read bytes of standard (non-emulated/special) memory.
136138
* Used for instruction fetch.

arch/x86/kvm/emulate.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -805,14 +805,14 @@ static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel)
805805
static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear,
806806
void *data, unsigned size)
807807
{
808-
return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception);
808+
return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, true);
809809
}
810810

811811
static int linear_write_system(struct x86_emulate_ctxt *ctxt,
812812
ulong linear, void *data,
813813
unsigned int size)
814814
{
815-
return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception);
815+
return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, true);
816816
}
817817

818818
static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
@@ -826,7 +826,7 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
826826
rc = linearize(ctxt, addr, size, false, &linear);
827827
if (rc != X86EMUL_CONTINUE)
828828
return rc;
829-
return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception);
829+
return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, false);
830830
}
831831

832832
static int segmented_write_std(struct x86_emulate_ctxt *ctxt,
@@ -840,7 +840,7 @@ static int segmented_write_std(struct x86_emulate_ctxt *ctxt,
840840
rc = linearize(ctxt, addr, size, true, &linear);
841841
if (rc != X86EMUL_CONTINUE)
842842
return rc;
843-
return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception);
843+
return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, false);
844844
}
845845

846846
/*
@@ -2912,12 +2912,12 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
29122912
#ifdef CONFIG_X86_64
29132913
base |= ((u64)base3) << 32;
29142914
#endif
2915-
r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL);
2915+
r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL, true);
29162916
if (r != X86EMUL_CONTINUE)
29172917
return false;
29182918
if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg))
29192919
return false;
2920-
r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL);
2920+
r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL, true);
29212921
if (r != X86EMUL_CONTINUE)
29222922
return false;
29232923
if ((perm >> bit_idx) & mask)

arch/x86/kvm/x86.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4408,10 +4408,15 @@ EXPORT_SYMBOL_GPL(kvm_read_guest_virt);
44084408

44094409
static int emulator_read_std(struct x86_emulate_ctxt *ctxt,
44104410
gva_t addr, void *val, unsigned int bytes,
4411-
struct x86_exception *exception)
4411+
struct x86_exception *exception, bool system)
44124412
{
44134413
struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
4414-
return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, exception);
4414+
u32 access = 0;
4415+
4416+
if (!system && kvm_x86_ops->get_cpl(vcpu) == 3)
4417+
access |= PFERR_USER_MASK;
4418+
4419+
return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, exception);
44154420
}
44164421

44174422
static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt,
@@ -4455,12 +4460,17 @@ static int kvm_write_guest_virt_helper(gva_t addr, void *val, unsigned int bytes
44554460
}
44564461

44574462
static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val,
4458-
unsigned int bytes, struct x86_exception *exception)
4463+
unsigned int bytes, struct x86_exception *exception,
4464+
bool system)
44594465
{
44604466
struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
4467+
u32 access = PFERR_WRITE_MASK;
4468+
4469+
if (!system && kvm_x86_ops->get_cpl(vcpu) == 3)
4470+
access |= PFERR_USER_MASK;
44614471

44624472
return kvm_write_guest_virt_helper(addr, val, bytes, vcpu,
4463-
PFERR_WRITE_MASK, exception);
4473+
access, exception);
44644474
}
44654475

44664476
int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val,

0 commit comments

Comments
 (0)