Skip to content

Commit d1442d8

Browse files
anadavbonzini
authored andcommitted
KVM: x86: Handle errors when RIP is set during far jumps
Far jmp/call/ret may fault while loading a new RIP. Currently KVM does not handle this case, and may result in failed vm-entry once the assignment is done. The tricky part of doing so is that loading the new CS affects the VMCS/VMCB state, so if we fail during loading the new RIP, we are left in unconsistent state. Therefore, this patch saves on 64-bit the old CS descriptor and restores it if loading RIP failed. This fixes CVE-2014-3647. Cc: [email protected] Signed-off-by: Nadav Amit <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 234f3ce commit d1442d8

File tree

1 file changed

+88
-30
lines changed

1 file changed

+88
-30
lines changed

arch/x86/kvm/emulate.c

Lines changed: 88 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,7 +1443,9 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
14431443

14441444
/* Does not support long mode */
14451445
static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
1446-
u16 selector, int seg, u8 cpl, bool in_task_switch)
1446+
u16 selector, int seg, u8 cpl,
1447+
bool in_task_switch,
1448+
struct desc_struct *desc)
14471449
{
14481450
struct desc_struct seg_desc, old_desc;
14491451
u8 dpl, rpl;
@@ -1584,6 +1586,8 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
15841586
}
15851587
load:
15861588
ctxt->ops->set_segment(ctxt, selector, &seg_desc, base3, seg);
1589+
if (desc)
1590+
*desc = seg_desc;
15871591
return X86EMUL_CONTINUE;
15881592
exception:
15891593
return emulate_exception(ctxt, err_vec, err_code, true);
@@ -1593,7 +1597,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
15931597
u16 selector, int seg)
15941598
{
15951599
u8 cpl = ctxt->ops->cpl(ctxt);
1596-
return __load_segment_descriptor(ctxt, selector, seg, cpl, false);
1600+
return __load_segment_descriptor(ctxt, selector, seg, cpl, false, NULL);
15971601
}
15981602

15991603
static void write_register_operand(struct operand *op)
@@ -1987,17 +1991,31 @@ static int em_iret(struct x86_emulate_ctxt *ctxt)
19871991
static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
19881992
{
19891993
int rc;
1990-
unsigned short sel;
1994+
unsigned short sel, old_sel;
1995+
struct desc_struct old_desc, new_desc;
1996+
const struct x86_emulate_ops *ops = ctxt->ops;
1997+
u8 cpl = ctxt->ops->cpl(ctxt);
1998+
1999+
/* Assignment of RIP may only fail in 64-bit mode */
2000+
if (ctxt->mode == X86EMUL_MODE_PROT64)
2001+
ops->get_segment(ctxt, &old_sel, &old_desc, NULL,
2002+
VCPU_SREG_CS);
19912003

19922004
memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2);
19932005

1994-
rc = load_segment_descriptor(ctxt, sel, VCPU_SREG_CS);
2006+
rc = __load_segment_descriptor(ctxt, sel, VCPU_SREG_CS, cpl, false,
2007+
&new_desc);
19952008
if (rc != X86EMUL_CONTINUE)
19962009
return rc;
19972010

1998-
ctxt->_eip = 0;
1999-
memcpy(&ctxt->_eip, ctxt->src.valptr, ctxt->op_bytes);
2000-
return X86EMUL_CONTINUE;
2011+
rc = assign_eip_far(ctxt, ctxt->src.val, new_desc.l);
2012+
if (rc != X86EMUL_CONTINUE) {
2013+
WARN_ON(!ctxt->mode != X86EMUL_MODE_PROT64);
2014+
/* assigning eip failed; restore the old cs */
2015+
ops->set_segment(ctxt, old_sel, &old_desc, 0, VCPU_SREG_CS);
2016+
return rc;
2017+
}
2018+
return rc;
20012019
}
20022020

20032021
static int em_grp45(struct x86_emulate_ctxt *ctxt)
@@ -2064,21 +2082,34 @@ static int em_ret(struct x86_emulate_ctxt *ctxt)
20642082
static int em_ret_far(struct x86_emulate_ctxt *ctxt)
20652083
{
20662084
int rc;
2067-
unsigned long cs;
2085+
unsigned long eip, cs;
2086+
u16 old_cs;
20682087
int cpl = ctxt->ops->cpl(ctxt);
2088+
struct desc_struct old_desc, new_desc;
2089+
const struct x86_emulate_ops *ops = ctxt->ops;
2090+
2091+
if (ctxt->mode == X86EMUL_MODE_PROT64)
2092+
ops->get_segment(ctxt, &old_cs, &old_desc, NULL,
2093+
VCPU_SREG_CS);
20692094

2070-
rc = emulate_pop(ctxt, &ctxt->_eip, ctxt->op_bytes);
2095+
rc = emulate_pop(ctxt, &eip, ctxt->op_bytes);
20712096
if (rc != X86EMUL_CONTINUE)
20722097
return rc;
2073-
if (ctxt->op_bytes == 4)
2074-
ctxt->_eip = (u32)ctxt->_eip;
20752098
rc = emulate_pop(ctxt, &cs, ctxt->op_bytes);
20762099
if (rc != X86EMUL_CONTINUE)
20772100
return rc;
20782101
/* Outer-privilege level return is not implemented */
20792102
if (ctxt->mode >= X86EMUL_MODE_PROT16 && (cs & 3) > cpl)
20802103
return X86EMUL_UNHANDLEABLE;
2081-
rc = load_segment_descriptor(ctxt, (u16)cs, VCPU_SREG_CS);
2104+
rc = __load_segment_descriptor(ctxt, (u16)cs, VCPU_SREG_CS, 0, false,
2105+
&new_desc);
2106+
if (rc != X86EMUL_CONTINUE)
2107+
return rc;
2108+
rc = assign_eip_far(ctxt, eip, new_desc.l);
2109+
if (rc != X86EMUL_CONTINUE) {
2110+
WARN_ON(!ctxt->mode != X86EMUL_MODE_PROT64);
2111+
ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS);
2112+
}
20822113
return rc;
20832114
}
20842115

@@ -2505,19 +2536,24 @@ static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt,
25052536
* Now load segment descriptors. If fault happens at this stage
25062537
* it is handled in a context of new task
25072538
*/
2508-
ret = __load_segment_descriptor(ctxt, tss->ldt, VCPU_SREG_LDTR, cpl, true);
2539+
ret = __load_segment_descriptor(ctxt, tss->ldt, VCPU_SREG_LDTR, cpl,
2540+
true, NULL);
25092541
if (ret != X86EMUL_CONTINUE)
25102542
return ret;
2511-
ret = __load_segment_descriptor(ctxt, tss->es, VCPU_SREG_ES, cpl, true);
2543+
ret = __load_segment_descriptor(ctxt, tss->es, VCPU_SREG_ES, cpl,
2544+
true, NULL);
25122545
if (ret != X86EMUL_CONTINUE)
25132546
return ret;
2514-
ret = __load_segment_descriptor(ctxt, tss->cs, VCPU_SREG_CS, cpl, true);
2547+
ret = __load_segment_descriptor(ctxt, tss->cs, VCPU_SREG_CS, cpl,
2548+
true, NULL);
25152549
if (ret != X86EMUL_CONTINUE)
25162550
return ret;
2517-
ret = __load_segment_descriptor(ctxt, tss->ss, VCPU_SREG_SS, cpl, true);
2551+
ret = __load_segment_descriptor(ctxt, tss->ss, VCPU_SREG_SS, cpl,
2552+
true, NULL);
25182553
if (ret != X86EMUL_CONTINUE)
25192554
return ret;
2520-
ret = __load_segment_descriptor(ctxt, tss->ds, VCPU_SREG_DS, cpl, true);
2555+
ret = __load_segment_descriptor(ctxt, tss->ds, VCPU_SREG_DS, cpl,
2556+
true, NULL);
25212557
if (ret != X86EMUL_CONTINUE)
25222558
return ret;
25232559

@@ -2642,25 +2678,32 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
26422678
* Now load segment descriptors. If fault happenes at this stage
26432679
* it is handled in a context of new task
26442680
*/
2645-
ret = __load_segment_descriptor(ctxt, tss->ldt_selector, VCPU_SREG_LDTR, cpl, true);
2681+
ret = __load_segment_descriptor(ctxt, tss->ldt_selector, VCPU_SREG_LDTR,
2682+
cpl, true, NULL);
26462683
if (ret != X86EMUL_CONTINUE)
26472684
return ret;
2648-
ret = __load_segment_descriptor(ctxt, tss->es, VCPU_SREG_ES, cpl, true);
2685+
ret = __load_segment_descriptor(ctxt, tss->es, VCPU_SREG_ES, cpl,
2686+
true, NULL);
26492687
if (ret != X86EMUL_CONTINUE)
26502688
return ret;
2651-
ret = __load_segment_descriptor(ctxt, tss->cs, VCPU_SREG_CS, cpl, true);
2689+
ret = __load_segment_descriptor(ctxt, tss->cs, VCPU_SREG_CS, cpl,
2690+
true, NULL);
26522691
if (ret != X86EMUL_CONTINUE)
26532692
return ret;
2654-
ret = __load_segment_descriptor(ctxt, tss->ss, VCPU_SREG_SS, cpl, true);
2693+
ret = __load_segment_descriptor(ctxt, tss->ss, VCPU_SREG_SS, cpl,
2694+
true, NULL);
26552695
if (ret != X86EMUL_CONTINUE)
26562696
return ret;
2657-
ret = __load_segment_descriptor(ctxt, tss->ds, VCPU_SREG_DS, cpl, true);
2697+
ret = __load_segment_descriptor(ctxt, tss->ds, VCPU_SREG_DS, cpl,
2698+
true, NULL);
26582699
if (ret != X86EMUL_CONTINUE)
26592700
return ret;
2660-
ret = __load_segment_descriptor(ctxt, tss->fs, VCPU_SREG_FS, cpl, true);
2701+
ret = __load_segment_descriptor(ctxt, tss->fs, VCPU_SREG_FS, cpl,
2702+
true, NULL);
26612703
if (ret != X86EMUL_CONTINUE)
26622704
return ret;
2663-
ret = __load_segment_descriptor(ctxt, tss->gs, VCPU_SREG_GS, cpl, true);
2705+
ret = __load_segment_descriptor(ctxt, tss->gs, VCPU_SREG_GS, cpl,
2706+
true, NULL);
26642707
if (ret != X86EMUL_CONTINUE)
26652708
return ret;
26662709

@@ -2942,24 +2985,39 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt)
29422985
u16 sel, old_cs;
29432986
ulong old_eip;
29442987
int rc;
2988+
struct desc_struct old_desc, new_desc;
2989+
const struct x86_emulate_ops *ops = ctxt->ops;
2990+
int cpl = ctxt->ops->cpl(ctxt);
29452991

2946-
old_cs = get_segment_selector(ctxt, VCPU_SREG_CS);
29472992
old_eip = ctxt->_eip;
2993+
ops->get_segment(ctxt, &old_cs, &old_desc, NULL, VCPU_SREG_CS);
29482994

29492995
memcpy(&sel, ctxt->src.valptr + ctxt->op_bytes, 2);
2950-
if (load_segment_descriptor(ctxt, sel, VCPU_SREG_CS))
2996+
rc = __load_segment_descriptor(ctxt, sel, VCPU_SREG_CS, cpl, false,
2997+
&new_desc);
2998+
if (rc != X86EMUL_CONTINUE)
29512999
return X86EMUL_CONTINUE;
29523000

2953-
ctxt->_eip = 0;
2954-
memcpy(&ctxt->_eip, ctxt->src.valptr, ctxt->op_bytes);
3001+
rc = assign_eip_far(ctxt, ctxt->src.val, new_desc.l);
3002+
if (rc != X86EMUL_CONTINUE)
3003+
goto fail;
29553004

29563005
ctxt->src.val = old_cs;
29573006
rc = em_push(ctxt);
29583007
if (rc != X86EMUL_CONTINUE)
2959-
return rc;
3008+
goto fail;
29603009

29613010
ctxt->src.val = old_eip;
2962-
return em_push(ctxt);
3011+
rc = em_push(ctxt);
3012+
/* If we failed, we tainted the memory, but the very least we should
3013+
restore cs */
3014+
if (rc != X86EMUL_CONTINUE)
3015+
goto fail;
3016+
return rc;
3017+
fail:
3018+
ops->set_segment(ctxt, old_cs, &old_desc, 0, VCPU_SREG_CS);
3019+
return rc;
3020+
29633021
}
29643022

29653023
static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt)

0 commit comments

Comments
 (0)