This adds segment limit checks to the emulator. Also changes return value of emulate_push() and its callers accordingly. Signed-off-by: Mohammed Gamal <m.gamal005@xxxxxxxxx> --- arch/x86/kvm/emulate.c | 79 ++++++++++++++++++++++++++++++++++------------- 1 files changed, 57 insertions(+), 22 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 07ca28e..70cbc5e 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -728,6 +728,10 @@ static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, if (eip == fc->end) { cur_size = fc->end - fc->start; size = min(15UL - cur_size, PAGE_SIZE - offset_in_page(eip)); + rc = seg_limit_check(ctxt, ops, VCPU_SREG_CS, ctxt->cs_base + eip, + size, GP_VECTOR, 0); + if (rc != X86EMUL_CONTINUE) + return rc; rc = ops->fetch(ctxt->cs_base + eip, fc->data + cur_size, size, ctxt->vcpu, NULL); if (rc != X86EMUL_CONTINUE) @@ -1248,6 +1252,8 @@ done_prefixes: register_address(c, seg_override_base(ctxt, ops, c), c->regs[VCPU_REGS_RSI]); c->src.val = 0; + rc = seg_limit_check(ctxt, ops, c->seg_override, (unsigned long) c->src.ptr, + c->src.bytes, GP_VECTOR, 0); break; case SrcImmFAddr: c->src.type = OP_IMM; @@ -1344,6 +1350,8 @@ done_prefixes: register_address(c, es_base(ctxt, ops), c->regs[VCPU_REGS_RDI]); c->dst.val = 0; + rc = seg_limit_check(ctxt, ops, VCPU_SREG_ES, (unsigned long) c->dst.ptr, + c->dst.bytes, GP_VECTOR, 0); break; } @@ -1662,7 +1670,7 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt, return X86EMUL_CONTINUE; } -static inline void emulate_push(struct x86_emulate_ctxt *ctxt, +static inline int emulate_push(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) { struct decode_cache *c = &ctxt->decode; @@ -1673,6 +1681,8 @@ static inline void emulate_push(struct x86_emulate_ctxt *ctxt, register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); c->dst.ptr = (void *) register_address(c, ss_base(ctxt, ops), c->regs[VCPU_REGS_RSP]); + return seg_limit_check(ctxt, ops, VCPU_SREG_SS, (unsigned long) c->dst.ptr, + c->dst.bytes, SS_VECTOR, 0); } static int emulate_pop(struct x86_emulate_ctxt *ctxt, @@ -1680,11 +1690,16 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt, void *dest, int len) { struct decode_cache *c = &ctxt->decode; + unsigned long reg_addr = register_address(c, ss_base(ctxt, ops), + c->regs[VCPU_REGS_RSP]); int rc; - rc = read_emulated(ctxt, ops, register_address(c, ss_base(ctxt, ops), - c->regs[VCPU_REGS_RSP]), - dest, len); + + rc = read_emulated(ctxt, ops, reg_addr, dest, len); + if (rc != X86EMUL_CONTINUE) + return rc; + rc = seg_limit_check(ctxt, ops, VCPU_SREG_SS, reg_addr, len, + SS_VECTOR, 0); if (rc != X86EMUL_CONTINUE) return rc; @@ -1735,14 +1750,14 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt, return rc; } -static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, +static int emulate_push_sreg(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops, int seg) { struct decode_cache *c = &ctxt->decode; c->src.val = ops->get_segment_selector(seg, ctxt->vcpu); - emulate_push(ctxt, ops); + return emulate_push(ctxt, ops); } static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt, @@ -1772,7 +1787,9 @@ static int emulate_pusha(struct x86_emulate_ctxt *ctxt, (reg == VCPU_REGS_RSP) ? (c->src.val = old_esp) : (c->src.val = c->regs[reg]); - emulate_push(ctxt, ops); + rc = emulate_push(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + return rc; rc = writeback(ctxt, ops); if (rc != X86EMUL_CONTINUE) @@ -1884,15 +1901,13 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt, old_eip = c->eip; c->eip = c->src.val; c->src.val = old_eip; - emulate_push(ctxt, ops); - break; + return emulate_push(ctxt, ops); } case 4: /* jmp abs */ c->eip = c->src.val; break; case 6: /* push */ - emulate_push(ctxt, ops); - break; + return emulate_push(ctxt, ops); } return X86EMUL_CONTINUE; } @@ -2548,7 +2563,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; c->lock_prefix = 0; c->src.val = (unsigned long) error_code; - emulate_push(ctxt, ops); + return emulate_push(ctxt, ops); } return ret; @@ -2681,7 +2696,9 @@ special_insn: emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags); break; case 0x06: /* push es */ - emulate_push_sreg(ctxt, ops, VCPU_SREG_ES); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_ES); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x07: /* pop es */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES); @@ -2693,14 +2710,18 @@ special_insn: emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags); break; case 0x0e: /* push cs */ - emulate_push_sreg(ctxt, ops, VCPU_SREG_CS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_CS); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x10 ... 0x15: adc: /* adc */ emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags); break; case 0x16: /* push ss */ - emulate_push_sreg(ctxt, ops, VCPU_SREG_SS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_SS); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x17: /* pop ss */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS); @@ -2712,7 +2733,9 @@ special_insn: emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags); break; case 0x1e: /* push ds */ - emulate_push_sreg(ctxt, ops, VCPU_SREG_DS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_DS); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x1f: /* pop ds */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS); @@ -2742,7 +2765,9 @@ special_insn: emulate_1op("dec", c->dst, ctxt->eflags); break; case 0x50 ... 0x57: /* push reg */ - emulate_push(ctxt, ops); + rc = emulate_push(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x58 ... 0x5f: /* pop reg */ pop_instruction: @@ -2767,7 +2792,9 @@ special_insn: break; case 0x68: /* push imm */ case 0x6a: /* push imm8 */ - emulate_push(ctxt, ops); + rc = emulate_push(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x6c: /* insb */ case 0x6d: /* insw/insd */ @@ -2895,7 +2922,9 @@ special_insn: goto xchg; case 0x9c: /* pushf */ c->src.val = (unsigned long) ctxt->eflags; - emulate_push(ctxt, ops); + rc = emulate_push(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0x9d: /* popf */ c->dst.type = OP_REG; @@ -2959,7 +2988,9 @@ special_insn: long int rel = c->src.val; c->src.val = (unsigned long) c->eip; jmp_rel(c, rel); - emulate_push(ctxt, ops); + rc = emulate_push(ctxt, ops); + if (rc != X86EMUL_CONTINUE) + goto done; break; } case 0xe9: /* jmp rel */ @@ -3286,7 +3317,9 @@ twobyte_insn: c->dst.type = OP_NONE; break; case 0xa0: /* push fs */ - emulate_push_sreg(ctxt, ops, VCPU_SREG_FS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_FS); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0xa1: /* pop fs */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS); @@ -3305,7 +3338,9 @@ twobyte_insn: emulate_2op_cl("shld", c->src2, c->src, c->dst, ctxt->eflags); break; case 0xa8: /* push gs */ - emulate_push_sreg(ctxt, ops, VCPU_SREG_GS); + rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_GS); + if (rc != X86EMUL_CONTINUE) + goto done; break; case 0xa9: /* pop gs */ rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS); -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html