mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
e2cefa746e
commit
edccda7ca7
|
@ -1444,28 +1444,8 @@ static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
|
||||||
ops->get_gdt(ctxt, dt);
|
ops->get_gdt(ctxt, dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allowed just for 8 bytes segments */
|
static int get_descriptor_ptr(struct x86_emulate_ctxt *ctxt,
|
||||||
static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
u16 selector, ulong *desc_addr_p)
|
||||||
u16 selector, struct desc_struct *desc,
|
|
||||||
ulong *desc_addr_p)
|
|
||||||
{
|
|
||||||
struct desc_ptr dt;
|
|
||||||
u16 index = selector >> 3;
|
|
||||||
ulong addr;
|
|
||||||
|
|
||||||
get_descriptor_table_ptr(ctxt, selector, &dt);
|
|
||||||
|
|
||||||
if (dt.size < index * 8 + 7)
|
|
||||||
return emulate_gp(ctxt, selector & 0xfffc);
|
|
||||||
|
|
||||||
*desc_addr_p = addr = dt.address + index * 8;
|
|
||||||
return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc,
|
|
||||||
&ctxt->exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allowed just for 8 bytes segments */
|
|
||||||
static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
|
||||||
u16 selector, struct desc_struct *desc)
|
|
||||||
{
|
{
|
||||||
struct desc_ptr dt;
|
struct desc_ptr dt;
|
||||||
u16 index = selector >> 3;
|
u16 index = selector >> 3;
|
||||||
|
@ -1477,6 +1457,47 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||||||
return emulate_gp(ctxt, selector & 0xfffc);
|
return emulate_gp(ctxt, selector & 0xfffc);
|
||||||
|
|
||||||
addr = dt.address + index * 8;
|
addr = dt.address + index * 8;
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_64
|
||||||
|
if (addr >> 32 != 0) {
|
||||||
|
u64 efer = 0;
|
||||||
|
|
||||||
|
ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
|
||||||
|
if (!(efer & EFER_LMA))
|
||||||
|
addr &= (u32)-1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*desc_addr_p = addr;
|
||||||
|
return X86EMUL_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allowed just for 8 bytes segments */
|
||||||
|
static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||||||
|
u16 selector, struct desc_struct *desc,
|
||||||
|
ulong *desc_addr_p)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = get_descriptor_ptr(ctxt, selector, desc_addr_p);
|
||||||
|
if (rc != X86EMUL_CONTINUE)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return ctxt->ops->read_std(ctxt, *desc_addr_p, desc, sizeof(*desc),
|
||||||
|
&ctxt->exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allowed just for 8 bytes segments */
|
||||||
|
static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
|
||||||
|
u16 selector, struct desc_struct *desc)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
ulong addr;
|
||||||
|
|
||||||
|
rc = get_descriptor_ptr(ctxt, selector, &addr);
|
||||||
|
if (rc != X86EMUL_CONTINUE)
|
||||||
|
return rc;
|
||||||
|
|
||||||
return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc,
|
return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc,
|
||||||
&ctxt->exception);
|
&ctxt->exception);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue