aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Wolf <kwolf@redhat.com>2012-02-08 08:34:38 -0500
committerAvi Kivity <avi@redhat.com>2012-03-08 07:10:26 -0500
commit7f3d35fddd173e52886d03bc34b5b5d6f5bea343 (patch)
tree9561913495a92c398b9b8e372d4e9a5c1d55c7f4
parent9cc815e46911486f52bec60517d0f7b40d323bbc (diff)
KVM: x86 emulator: Fix task switch privilege checks
Currently, all task switches check privileges against the DPL of the TSS. This is only correct for jmp/call to a TSS. If a task gate is used, the DPL of this take gate is used for the check instead. Exceptions, external interrupts and iret shouldn't perform any check. [avi: kill kvm-kmod remnants] Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm_emulate.h2
-rw-r--r--arch/x86/include/asm/kvm_host.h4
-rw-r--r--arch/x86/kvm/emulate.c53
-rw-r--r--arch/x86/kvm/svm.c5
-rw-r--r--arch/x86/kvm/vmx.c8
-rw-r--r--arch/x86/kvm/x86.c6
6 files changed, 61 insertions, 17 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 7b9cfc4878af..df437b68f42b 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -388,7 +388,7 @@ bool x86_page_table_writing_insn(struct x86_emulate_ctxt *ctxt);
388#define EMULATION_INTERCEPTED 2 388#define EMULATION_INTERCEPTED 2
389int x86_emulate_insn(struct x86_emulate_ctxt *ctxt); 389int x86_emulate_insn(struct x86_emulate_ctxt *ctxt);
390int emulator_task_switch(struct x86_emulate_ctxt *ctxt, 390int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
391 u16 tss_selector, int reason, 391 u16 tss_selector, int idt_index, int reason,
392 bool has_error_code, u32 error_code); 392 bool has_error_code, u32 error_code);
393int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq); 393int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq);
394#endif /* _ASM_X86_KVM_X86_EMULATE_H */ 394#endif /* _ASM_X86_KVM_X86_EMULATE_H */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 74c9edf2bb18..e216ba066e79 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -768,8 +768,8 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu);
768void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); 768void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
769int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg); 769int kvm_load_segment_descriptor(struct kvm_vcpu *vcpu, u16 selector, int seg);
770 770
771int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, 771int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
772 bool has_error_code, u32 error_code); 772 int reason, bool has_error_code, u32 error_code);
773 773
774int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); 774int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
775int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); 775int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 71450aca3b86..fa310a48591c 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1152,6 +1152,22 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
1152 return 1; 1152 return 1;
1153} 1153}
1154 1154
1155static int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt,
1156 u16 index, struct desc_struct *desc)
1157{
1158 struct desc_ptr dt;
1159 ulong addr;
1160
1161 ctxt->ops->get_idt(ctxt, &dt);
1162
1163 if (dt.size < index * 8 + 7)
1164 return emulate_gp(ctxt, index << 3 | 0x2);
1165
1166 addr = dt.address + index * 8;
1167 return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc,
1168 &ctxt->exception);
1169}
1170
1155static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, 1171static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
1156 u16 selector, struct desc_ptr *dt) 1172 u16 selector, struct desc_ptr *dt)
1157{ 1173{
@@ -2421,7 +2437,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
2421} 2437}
2422 2438
2423static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, 2439static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
2424 u16 tss_selector, int reason, 2440 u16 tss_selector, int idt_index, int reason,
2425 bool has_error_code, u32 error_code) 2441 bool has_error_code, u32 error_code)
2426{ 2442{
2427 struct x86_emulate_ops *ops = ctxt->ops; 2443 struct x86_emulate_ops *ops = ctxt->ops;
@@ -2443,12 +2459,35 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
2443 2459
2444 /* FIXME: check that next_tss_desc is tss */ 2460 /* FIXME: check that next_tss_desc is tss */
2445 2461
2446 if (reason != TASK_SWITCH_IRET) { 2462 /*
2447 if ((tss_selector & 3) > next_tss_desc.dpl || 2463 * Check privileges. The three cases are task switch caused by...
2448 ops->cpl(ctxt) > next_tss_desc.dpl) 2464 *
2449 return emulate_gp(ctxt, 0); 2465 * 1. jmp/call/int to task gate: Check against DPL of the task gate
2466 * 2. Exception/IRQ/iret: No check is performed
2467 * 3. jmp/call to TSS: Check agains DPL of the TSS
2468 */
2469 if (reason == TASK_SWITCH_GATE) {
2470 if (idt_index != -1) {
2471 /* Software interrupts */
2472 struct desc_struct task_gate_desc;
2473 int dpl;
2474
2475 ret = read_interrupt_descriptor(ctxt, idt_index,
2476 &task_gate_desc);
2477 if (ret != X86EMUL_CONTINUE)
2478 return ret;
2479
2480 dpl = task_gate_desc.dpl;
2481 if ((tss_selector & 3) > dpl || ops->cpl(ctxt) > dpl)
2482 return emulate_gp(ctxt, (idt_index << 3) | 0x2);
2483 }
2484 } else if (reason != TASK_SWITCH_IRET) {
2485 int dpl = next_tss_desc.dpl;
2486 if ((tss_selector & 3) > dpl || ops->cpl(ctxt) > dpl)
2487 return emulate_gp(ctxt, tss_selector);
2450 } 2488 }
2451 2489
2490
2452 desc_limit = desc_limit_scaled(&next_tss_desc); 2491 desc_limit = desc_limit_scaled(&next_tss_desc);
2453 if (!next_tss_desc.p || 2492 if (!next_tss_desc.p ||
2454 ((desc_limit < 0x67 && (next_tss_desc.type & 8)) || 2493 ((desc_limit < 0x67 && (next_tss_desc.type & 8)) ||
@@ -2501,7 +2540,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
2501} 2540}
2502 2541
2503int emulator_task_switch(struct x86_emulate_ctxt *ctxt, 2542int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
2504 u16 tss_selector, int reason, 2543 u16 tss_selector, int idt_index, int reason,
2505 bool has_error_code, u32 error_code) 2544 bool has_error_code, u32 error_code)
2506{ 2545{
2507 int rc; 2546 int rc;
@@ -2509,7 +2548,7 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
2509 ctxt->_eip = ctxt->eip; 2548 ctxt->_eip = ctxt->eip;
2510 ctxt->dst.type = OP_NONE; 2549 ctxt->dst.type = OP_NONE;
2511 2550
2512 rc = emulator_do_task_switch(ctxt, tss_selector, reason, 2551 rc = emulator_do_task_switch(ctxt, tss_selector, idt_index, reason,
2513 has_error_code, error_code); 2552 has_error_code, error_code);
2514 2553
2515 if (rc == X86EMUL_CONTINUE) 2554 if (rc == X86EMUL_CONTINUE)
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 0b7690ee20bd..95cdeaf9c718 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -2799,7 +2799,10 @@ static int task_switch_interception(struct vcpu_svm *svm)
2799 (int_vec == OF_VECTOR || int_vec == BP_VECTOR))) 2799 (int_vec == OF_VECTOR || int_vec == BP_VECTOR)))
2800 skip_emulated_instruction(&svm->vcpu); 2800 skip_emulated_instruction(&svm->vcpu);
2801 2801
2802 if (kvm_task_switch(&svm->vcpu, tss_selector, reason, 2802 if (int_type != SVM_EXITINTINFO_TYPE_SOFT)
2803 int_vec = -1;
2804
2805 if (kvm_task_switch(&svm->vcpu, tss_selector, int_vec, reason,
2803 has_error_code, error_code) == EMULATE_FAIL) { 2806 has_error_code, error_code) == EMULATE_FAIL) {
2804 svm->vcpu.run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 2807 svm->vcpu.run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
2805 svm->vcpu.run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; 2808 svm->vcpu.run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index d2bd719925a6..124a0952a040 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4658,9 +4658,10 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
4658 bool has_error_code = false; 4658 bool has_error_code = false;
4659 u32 error_code = 0; 4659 u32 error_code = 0;
4660 u16 tss_selector; 4660 u16 tss_selector;
4661 int reason, type, idt_v; 4661 int reason, type, idt_v, idt_index;
4662 4662
4663 idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK); 4663 idt_v = (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK);
4664 idt_index = (vmx->idt_vectoring_info & VECTORING_INFO_VECTOR_MASK);
4664 type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK); 4665 type = (vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK);
4665 4666
4666 exit_qualification = vmcs_readl(EXIT_QUALIFICATION); 4667 exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
@@ -4698,8 +4699,9 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
4698 type != INTR_TYPE_NMI_INTR)) 4699 type != INTR_TYPE_NMI_INTR))
4699 skip_emulated_instruction(vcpu); 4700 skip_emulated_instruction(vcpu);
4700 4701
4701 if (kvm_task_switch(vcpu, tss_selector, reason, 4702 if (kvm_task_switch(vcpu, tss_selector,
4702 has_error_code, error_code) == EMULATE_FAIL) { 4703 type == INTR_TYPE_SOFT_INTR ? idt_index : -1, reason,
4704 has_error_code, error_code) == EMULATE_FAIL) {
4703 vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 4705 vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
4704 vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; 4706 vcpu->run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION;
4705 vcpu->run->internal.ndata = 0; 4707 vcpu->run->internal.ndata = 0;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ca74c1dadf3a..490a1b1a255f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5655,15 +5655,15 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
5655 return 0; 5655 return 0;
5656} 5656}
5657 5657
5658int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, 5658int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index,
5659 bool has_error_code, u32 error_code) 5659 int reason, bool has_error_code, u32 error_code)
5660{ 5660{
5661 struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; 5661 struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
5662 int ret; 5662 int ret;
5663 5663
5664 init_emulate_ctxt(vcpu); 5664 init_emulate_ctxt(vcpu);
5665 5665
5666 ret = emulator_task_switch(ctxt, tss_selector, reason, 5666 ret = emulator_task_switch(ctxt, tss_selector, idt_index, reason,
5667 has_error_code, error_code); 5667 has_error_code, error_code);
5668 5668
5669 if (ret) 5669 if (ret)