From 003483ecab5258fbbf6593983dfde0b7ef59dcdb Mon Sep 17 00:00:00 2001 From: Gleb Natapov <gleb@redhat.com> Date: Mon, 1 Feb 2010 17:14:58 +0200 Subject: [PATCH 7/7] Check CPL level during privilege instruction emulation. Add CPL checking in case emulator is tricked into emulating privilege instruction. Message-Id: <1265037298-12612-8-git-send-email-gleb@redhat.com> CVE: CVE-2010-0306 Bugzilla: 560698 Acked-by: Marcelo Tosatti <mtosatti@redhat.com> Acked-by: Juan Quintela <quintela@redhat.com> Acked-by: Chris Wright <chrisw@redhat.com> Signed-off-by: Gleb Natapov <gleb@redhat.com> --- arch/x86/kvm/x86_emulate.c | 137 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 137 insertions(+), 0 deletions(-) diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c index 69caed0..9e7d5ca 100644 --- a/arch/x86/kvm/x86_emulate.c +++ b/arch/x86/kvm/x86_emulate.c @@ -1900,6 +1900,14 @@ special_insn: } break; case 0xf4: /* hlt */ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } ctxt->vcpu->arch.halt_request = 1; break; case 0xf5: /* cmc */ @@ -1975,6 +1983,11 @@ twobyte_insn: if (c->modrm_mod != 3 || c->modrm_rm != 1) goto cannot_emulate; + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + rc = kvm_fix_hypercall(ctxt->vcpu); if (rc) goto done; @@ -1985,6 +1998,16 @@ twobyte_insn: c->dst.type = OP_NONE; break; case 2: /* lgdt */ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + rc = read_descriptor(ctxt, ops, c->src.ptr, &size, &address, c->op_bytes); if (rc) @@ -1995,11 +2018,26 @@ twobyte_insn: break; case 3: /* lidt/vmmcall */ if (c->modrm_mod == 3 && c->modrm_rm == 1) { + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + rc = kvm_fix_hypercall(ctxt->vcpu); if (rc) goto done; kvm_emulate_hypercall(ctxt->vcpu); } else { + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + rc = read_descriptor(ctxt, ops, c->src.ptr, &size, &address, c->op_bytes); @@ -2015,11 +2053,26 @@ twobyte_insn: c->dst.val = realmode_get_cr(ctxt->vcpu, 0); break; case 6: /* lmsw */ + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + realmode_lmsw(ctxt->vcpu, (u16)c->src.val, &ctxt->eflags); c->dst.type = OP_NONE; break; case 7: /* invlpg*/ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + emulate_invlpg(ctxt->vcpu, memop); /* Disable writeback. */ c->dst.type = OP_NONE; @@ -2029,23 +2082,67 @@ twobyte_insn: } break; case 0x06: + if (c->lock_prefix) { + if (ctxt->mode == X86EMUL_MODE_REAL || + !(ctxt->vcpu->arch.cr0 & X86_CR0_PE)) + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + else + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + emulate_clts(ctxt->vcpu); c->dst.type = OP_NONE; break; case 0x08: /* invd */ case 0x09: /* wbinvd */ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } case 0x0d: /* GrpP (prefetch) */ case 0x18: /* Grp16 (prefetch/nop) */ c->dst.type = OP_NONE; break; case 0x20: /* mov cr, reg */ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + if (c->modrm_mod != 3) goto cannot_emulate; + c->regs[c->modrm_rm] = realmode_get_cr(ctxt->vcpu, c->modrm_reg); c->dst.type = OP_NONE; /* no writeback */ break; case 0x21: /* mov from dr to reg */ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + if (c->modrm_mod != 3) goto cannot_emulate; rc = emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]); @@ -2054,6 +2151,16 @@ twobyte_insn: c->dst.type = OP_NONE; /* no writeback */ break; case 0x22: /* mov reg, cr */ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + if (c->modrm_mod != 3) goto cannot_emulate; realmode_set_cr(ctxt->vcpu, @@ -2061,6 +2168,16 @@ twobyte_insn: c->dst.type = OP_NONE; break; case 0x23: /* mov from reg to dr */ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + if (c->modrm_mod != 3) goto cannot_emulate; rc = emulator_set_dr(ctxt, c->modrm_reg, @@ -2071,6 +2188,16 @@ twobyte_insn: break; case 0x30: /* wrmsr */ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + msr_data = (u32)c->regs[VCPU_REGS_RAX] | ((u64)c->regs[VCPU_REGS_RDX] << 32); rc = kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data); @@ -2083,6 +2210,16 @@ twobyte_insn: break; case 0x32: /* rdmsr */ + if (c->lock_prefix) { + kvm_queue_exception(ctxt->vcpu, UD_VECTOR); + goto done; + } + + if (kvm_x86_ops->get_cpl(ctxt->vcpu)) { + kvm_inject_gp(ctxt->vcpu, 0); + goto done; + } + rc = kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data); if (rc) { kvm_inject_gp(ctxt->vcpu, 0); -- 1.6.3.rc4.29.g8146