Loading arch/x86/include/asm/kvm_host.h +1 −0 Original line number Diff line number Diff line Loading @@ -678,6 +678,7 @@ void kvm_disable_tdp(void); int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); int complete_pio(struct kvm_vcpu *vcpu); bool kvm_check_iopl(struct kvm_vcpu *vcpu); struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn); Loading arch/x86/kvm/emulate.c +82 −7 Original line number Diff line number Diff line Loading @@ -1698,6 +1698,57 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt) return 0; } static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt) { int iopl; if (ctxt->mode == X86EMUL_MODE_REAL) return false; if (ctxt->mode == X86EMUL_MODE_VM86) return true; iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT; return kvm_x86_ops->get_cpl(ctxt->vcpu) > iopl; } static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, u16 port, u16 len) { struct kvm_segment tr_seg; int r; u16 io_bitmap_ptr; u8 perm, bit_idx = port & 0x7; unsigned mask = (1 << len) - 1; kvm_get_segment(ctxt->vcpu, &tr_seg, VCPU_SREG_TR); if (tr_seg.unusable) return false; if (tr_seg.limit < 103) return false; r = ops->read_std(tr_seg.base + 102, &io_bitmap_ptr, 2, ctxt->vcpu, NULL); if (r != X86EMUL_CONTINUE) return false; if (io_bitmap_ptr + port/8 > tr_seg.limit) return false; r = ops->read_std(tr_seg.base + io_bitmap_ptr + port/8, &perm, 1, ctxt->vcpu, NULL); if (r != X86EMUL_CONTINUE) return false; if ((perm >> bit_idx) & mask) return false; return true; } static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, u16 port, u16 len) { if (emulator_bad_iopl(ctxt)) if (!emulator_io_port_access_allowed(ctxt, ops, port, len)) return false; return true; } int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { Loading Loading @@ -1889,6 +1940,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) break; case 0x6c: /* insb */ case 0x6d: /* insw/insd */ if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX], (c->d & ByteOp) ? 1 : c->op_bytes)) { kvm_inject_gp(ctxt->vcpu, 0); goto done; } if (kvm_emulate_pio_string(ctxt->vcpu, 1, (c->d & ByteOp) ? 1 : c->op_bytes, Loading @@ -1905,6 +1961,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) return 0; case 0x6e: /* outsb */ case 0x6f: /* outsw/outsd */ if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX], (c->d & ByteOp) ? 1 : c->op_bytes)) { kvm_inject_gp(ctxt->vcpu, 0); goto done; } if (kvm_emulate_pio_string(ctxt->vcpu, 0, (c->d & ByteOp) ? 1 : c->op_bytes, Loading Loading @@ -2202,7 +2263,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) case 0xef: /* out (e/r)ax,dx */ port = c->regs[VCPU_REGS_RDX]; io_dir_in = 0; do_io: if (kvm_emulate_pio(ctxt->vcpu, io_dir_in, do_io: if (!emulator_io_permited(ctxt, ops, port, (c->d & ByteOp) ? 1 : c->op_bytes)) { kvm_inject_gp(ctxt->vcpu, 0); goto done; } if (kvm_emulate_pio(ctxt->vcpu, io_dir_in, (c->d & ByteOp) ? 1 : c->op_bytes, port) != 0) { c->eip = saved_eip; Loading @@ -2227,13 +2294,21 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xfa: /* cli */ if (emulator_bad_iopl(ctxt)) kvm_inject_gp(ctxt->vcpu, 0); else { ctxt->eflags &= ~X86_EFLAGS_IF; c->dst.type = OP_NONE; /* Disable writeback. */ } break; case 0xfb: /* sti */ if (emulator_bad_iopl(ctxt)) kvm_inject_gp(ctxt->vcpu, 0); else { toggle_interruptibility(ctxt, X86_SHADOW_INT_STI); ctxt->eflags |= X86_EFLAGS_IF; c->dst.type = OP_NONE; /* Disable writeback. */ } break; case 0xfc: /* cld */ ctxt->eflags &= ~EFLG_DF; Loading arch/x86/kvm/x86.c +4 −6 Original line number Diff line number Diff line Loading @@ -3599,6 +3599,8 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port) { unsigned long val; trace_kvm_pio(!in, port, size, 1); vcpu->run->exit_reason = KVM_EXIT_IO; vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; vcpu->run->io.size = vcpu->arch.pio.size = size; Loading @@ -3610,9 +3612,6 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port) vcpu->arch.pio.down = 0; vcpu->arch.pio.rep = 0; trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port, size, 1); if (!vcpu->arch.pio.in) { val = kvm_register_read(vcpu, VCPU_REGS_RAX); memcpy(vcpu->arch.pio_data, &val, 4); Loading @@ -3633,6 +3632,8 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in, unsigned now, in_page; int ret = 0; trace_kvm_pio(!in, port, size, count); vcpu->run->exit_reason = KVM_EXIT_IO; vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; vcpu->run->io.size = vcpu->arch.pio.size = size; Loading @@ -3644,9 +3645,6 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in, vcpu->arch.pio.down = down; vcpu->arch.pio.rep = rep; trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port, size, count); if (!count) { kvm_x86_ops->skip_emulated_instruction(vcpu); return 1; Loading Loading
arch/x86/include/asm/kvm_host.h +1 −0 Original line number Diff line number Diff line Loading @@ -678,6 +678,7 @@ void kvm_disable_tdp(void); int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); int complete_pio(struct kvm_vcpu *vcpu); bool kvm_check_iopl(struct kvm_vcpu *vcpu); struct kvm_memory_slot *gfn_to_memslot_unaliased(struct kvm *kvm, gfn_t gfn); Loading
arch/x86/kvm/emulate.c +82 −7 Original line number Diff line number Diff line Loading @@ -1698,6 +1698,57 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt) return 0; } static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt) { int iopl; if (ctxt->mode == X86EMUL_MODE_REAL) return false; if (ctxt->mode == X86EMUL_MODE_VM86) return true; iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT; return kvm_x86_ops->get_cpl(ctxt->vcpu) > iopl; } static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, u16 port, u16 len) { struct kvm_segment tr_seg; int r; u16 io_bitmap_ptr; u8 perm, bit_idx = port & 0x7; unsigned mask = (1 << len) - 1; kvm_get_segment(ctxt->vcpu, &tr_seg, VCPU_SREG_TR); if (tr_seg.unusable) return false; if (tr_seg.limit < 103) return false; r = ops->read_std(tr_seg.base + 102, &io_bitmap_ptr, 2, ctxt->vcpu, NULL); if (r != X86EMUL_CONTINUE) return false; if (io_bitmap_ptr + port/8 > tr_seg.limit) return false; r = ops->read_std(tr_seg.base + io_bitmap_ptr + port/8, &perm, 1, ctxt->vcpu, NULL); if (r != X86EMUL_CONTINUE) return false; if ((perm >> bit_idx) & mask) return false; return true; } static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, u16 port, u16 len) { if (emulator_bad_iopl(ctxt)) if (!emulator_io_port_access_allowed(ctxt, ops, port, len)) return false; return true; } int x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { Loading Loading @@ -1889,6 +1940,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) break; case 0x6c: /* insb */ case 0x6d: /* insw/insd */ if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX], (c->d & ByteOp) ? 1 : c->op_bytes)) { kvm_inject_gp(ctxt->vcpu, 0); goto done; } if (kvm_emulate_pio_string(ctxt->vcpu, 1, (c->d & ByteOp) ? 1 : c->op_bytes, Loading @@ -1905,6 +1961,11 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) return 0; case 0x6e: /* outsb */ case 0x6f: /* outsw/outsd */ if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX], (c->d & ByteOp) ? 1 : c->op_bytes)) { kvm_inject_gp(ctxt->vcpu, 0); goto done; } if (kvm_emulate_pio_string(ctxt->vcpu, 0, (c->d & ByteOp) ? 1 : c->op_bytes, Loading Loading @@ -2202,7 +2263,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) case 0xef: /* out (e/r)ax,dx */ port = c->regs[VCPU_REGS_RDX]; io_dir_in = 0; do_io: if (kvm_emulate_pio(ctxt->vcpu, io_dir_in, do_io: if (!emulator_io_permited(ctxt, ops, port, (c->d & ByteOp) ? 1 : c->op_bytes)) { kvm_inject_gp(ctxt->vcpu, 0); goto done; } if (kvm_emulate_pio(ctxt->vcpu, io_dir_in, (c->d & ByteOp) ? 1 : c->op_bytes, port) != 0) { c->eip = saved_eip; Loading @@ -2227,13 +2294,21 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) c->dst.type = OP_NONE; /* Disable writeback. */ break; case 0xfa: /* cli */ if (emulator_bad_iopl(ctxt)) kvm_inject_gp(ctxt->vcpu, 0); else { ctxt->eflags &= ~X86_EFLAGS_IF; c->dst.type = OP_NONE; /* Disable writeback. */ } break; case 0xfb: /* sti */ if (emulator_bad_iopl(ctxt)) kvm_inject_gp(ctxt->vcpu, 0); else { toggle_interruptibility(ctxt, X86_SHADOW_INT_STI); ctxt->eflags |= X86_EFLAGS_IF; c->dst.type = OP_NONE; /* Disable writeback. */ } break; case 0xfc: /* cld */ ctxt->eflags &= ~EFLG_DF; Loading
arch/x86/kvm/x86.c +4 −6 Original line number Diff line number Diff line Loading @@ -3599,6 +3599,8 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port) { unsigned long val; trace_kvm_pio(!in, port, size, 1); vcpu->run->exit_reason = KVM_EXIT_IO; vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; vcpu->run->io.size = vcpu->arch.pio.size = size; Loading @@ -3610,9 +3612,6 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, int in, int size, unsigned port) vcpu->arch.pio.down = 0; vcpu->arch.pio.rep = 0; trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port, size, 1); if (!vcpu->arch.pio.in) { val = kvm_register_read(vcpu, VCPU_REGS_RAX); memcpy(vcpu->arch.pio_data, &val, 4); Loading @@ -3633,6 +3632,8 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in, unsigned now, in_page; int ret = 0; trace_kvm_pio(!in, port, size, count); vcpu->run->exit_reason = KVM_EXIT_IO; vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; vcpu->run->io.size = vcpu->arch.pio.size = size; Loading @@ -3644,9 +3645,6 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, int in, vcpu->arch.pio.down = down; vcpu->arch.pio.rep = rep; trace_kvm_pio(vcpu->run->io.direction == KVM_EXIT_IO_OUT, port, size, count); if (!count) { kvm_x86_ops->skip_emulated_instruction(vcpu); return 1; Loading