diff options
author | Nadav Amit <namit@cs.technion.ac.il> | 2014-12-24 19:52:23 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2015-01-08 16:48:08 -0500 |
commit | edccda7ca7e56b335c70ae512f89d0fdf7fb8c69 (patch) | |
tree | 472fe75d29ac7e228ffa48cd5c61f9ae60803b5d /arch/x86/kvm/emulate.c | |
parent | e2cefa746e7e2a1104931d411b6f5de159d98ec6 (diff) |
KVM: x86: Access to LDT/GDT that wraparound is incorrect
When access to descriptor in LDT/GDT wraparound outside long-mode, the address
of the descriptor should be truncated to 32-bit. Citing Intel SDM 2.1.1.1
"Global and Local Descriptor Tables in IA-32e Mode": "GDTR and LDTR registers
are expanded to 64-bits wide in both IA-32e sub-modes (64-bit mode and
compatibility mode)."
So in other cases, we need to truncate. Creating new function to return a
pointer to descriptor table to avoid too much code duplication.
Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
[Wrap 64-bit check with #ifdef CONFIG_X86_64, to avoid a "right shift count
>= width of type" warning and consequent undefined behavior. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 47 |
1 files changed, 34 insertions, 13 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index e36e1fc5bf85..d949287ed010 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -1444,10 +1444,8 @@ static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, | |||
1444 | ops->get_gdt(ctxt, dt); | 1444 | ops->get_gdt(ctxt, dt); |
1445 | } | 1445 | } |
1446 | 1446 | ||
1447 | /* allowed just for 8 bytes segments */ | 1447 | static int get_descriptor_ptr(struct x86_emulate_ctxt *ctxt, |
1448 | static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, | 1448 | u16 selector, ulong *desc_addr_p) |
1449 | u16 selector, struct desc_struct *desc, | ||
1450 | ulong *desc_addr_p) | ||
1451 | { | 1449 | { |
1452 | struct desc_ptr dt; | 1450 | struct desc_ptr dt; |
1453 | u16 index = selector >> 3; | 1451 | u16 index = selector >> 3; |
@@ -1458,8 +1456,34 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, | |||
1458 | if (dt.size < index * 8 + 7) | 1456 | if (dt.size < index * 8 + 7) |
1459 | return emulate_gp(ctxt, selector & 0xfffc); | 1457 | return emulate_gp(ctxt, selector & 0xfffc); |
1460 | 1458 | ||
1461 | *desc_addr_p = addr = dt.address + index * 8; | 1459 | addr = dt.address + index * 8; |
1462 | return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc, | 1460 | |
1461 | #ifdef CONFIG_X86_64 | ||
1462 | if (addr >> 32 != 0) { | ||
1463 | u64 efer = 0; | ||
1464 | |||
1465 | ctxt->ops->get_msr(ctxt, MSR_EFER, &efer); | ||
1466 | if (!(efer & EFER_LMA)) | ||
1467 | addr &= (u32)-1; | ||
1468 | } | ||
1469 | #endif | ||
1470 | |||
1471 | *desc_addr_p = addr; | ||
1472 | return X86EMUL_CONTINUE; | ||
1473 | } | ||
1474 | |||
1475 | /* allowed just for 8 bytes segments */ | ||
1476 | static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, | ||
1477 | u16 selector, struct desc_struct *desc, | ||
1478 | ulong *desc_addr_p) | ||
1479 | { | ||
1480 | int rc; | ||
1481 | |||
1482 | rc = get_descriptor_ptr(ctxt, selector, desc_addr_p); | ||
1483 | if (rc != X86EMUL_CONTINUE) | ||
1484 | return rc; | ||
1485 | |||
1486 | return ctxt->ops->read_std(ctxt, *desc_addr_p, desc, sizeof(*desc), | ||
1463 | &ctxt->exception); | 1487 | &ctxt->exception); |
1464 | } | 1488 | } |
1465 | 1489 | ||
@@ -1467,16 +1491,13 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, | |||
1467 | static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, | 1491 | static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, |
1468 | u16 selector, struct desc_struct *desc) | 1492 | u16 selector, struct desc_struct *desc) |
1469 | { | 1493 | { |
1470 | struct desc_ptr dt; | 1494 | int rc; |
1471 | u16 index = selector >> 3; | ||
1472 | ulong addr; | 1495 | ulong addr; |
1473 | 1496 | ||
1474 | get_descriptor_table_ptr(ctxt, selector, &dt); | 1497 | rc = get_descriptor_ptr(ctxt, selector, &addr); |
1475 | 1498 | if (rc != X86EMUL_CONTINUE) | |
1476 | if (dt.size < index * 8 + 7) | 1499 | return rc; |
1477 | return emulate_gp(ctxt, selector & 0xfffc); | ||
1478 | 1500 | ||
1479 | addr = dt.address + index * 8; | ||
1480 | return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc, | 1501 | return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc, |
1481 | &ctxt->exception); | 1502 | &ctxt->exception); |
1482 | } | 1503 | } |