Skip to content

Commit

Permalink
KVM: x86: ensure emulator fetches do not span multiple pages
Browse files Browse the repository at this point in the history
When the CS base is not page-aligned, the linear address of the code could
get close to the page boundary (e.g. 0x...ffe) even if the EIP value is
not.  So we need to first linearize the address, and only then compute
the number of valid bytes that can be fetched.

This happens relatively often when executing real mode code.

Signed-off-by: Paolo Bonzini <[email protected]>
  • Loading branch information
bonzini committed Jul 11, 2014
1 parent 17052f1 commit 719d5a9
Showing 1 changed file with 7 additions and 6 deletions.
13 changes: 7 additions & 6 deletions arch/x86/kvm/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -711,14 +711,18 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size)
{
int rc;
int size;
unsigned size;
unsigned long linear;
int cur_size = ctxt->fetch.end - ctxt->fetch.data;
struct segmented_address addr = { .seg = VCPU_SREG_CS,
.ea = ctxt->eip + cur_size };

size = min(15UL ^ cur_size,
PAGE_SIZE - offset_in_page(addr.ea));
size = 15UL ^ cur_size;
rc = __linearize(ctxt, addr, size, false, true, &linear);
if (unlikely(rc != X86EMUL_CONTINUE))
return rc;

size = min_t(unsigned, size, PAGE_SIZE - offset_in_page(linear));

/*
* One instruction can only straddle two pages,
Expand All @@ -728,9 +732,6 @@ static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size)
*/
if (unlikely(size < op_size))
return X86EMUL_UNHANDLEABLE;
rc = __linearize(ctxt, addr, size, false, true, &linear);
if (unlikely(rc != X86EMUL_CONTINUE))
return rc;
rc = ctxt->ops->fetch(ctxt, linear, ctxt->fetch.end,
size, &ctxt->exception);
if (unlikely(rc != X86EMUL_CONTINUE))
Expand Down

0 comments on commit 719d5a9

Please sign in to comment.