On 29/09/17 14:53, Anaïs Gantet wrote:
Hi,
I would just like to underline a unusual behaviour I
observed recently
with Xen. Indeed, a test with a Xen HVM x86-32bit guest
pointed out the
x86_emulate function in
xen/arch/x86/x86_emulate/x86_emulate.c seems to
only partially handle far-jmp instruction emulation.
According to Intel documentation, when the processor is
operating in
protected mode, there exists three types of far jumps:
* A far jump to a conforming or non-conforming code segment;
* A far jump through a call gate;
* A task switch - through a task gate or directly with a TSS
segment.
When x86_emulate function emulates a far jmp (case 0xea or
0xff/5), it
does not check what type of descriptor given as far-jmp
parameter. When
performing segment loading (by calling load_seg function),
type segment
parameter is always set to 'x86_seg_cs':
xen/arch/x86/x86_emulate/x86_emulate.c:
4665 far_jmp:
4666 if ( (rc = load_seg(x86_seg_cs, imm2, 0,
&cs, ctxt, ops)) ||
4667 (rc = commit_far_branch(&cs, imm1)) )
4668 goto done;
4669 break;
In protected mode load_seg calls protmode_load_seg. Before
loading
segment, protmode_load_seg checks several properties, in
particular the
consistency of the system flag S of 'x86_seg_cs' and of the
descriptor
'desc' referenced by 'imm2'. If imm2 references a call gate,
a task gate
or a tss segment, flag S is clear and differs from
x86_seg_cs flag. That
lead to a segmentation fault:
xen/arch/x86/x86_emulate/x86_emulate.c:
1434 /* User segments must have S flag == 1. */
1435 if ( is_x86_user_segment(seg) && !(desc.b
& (1u << 12)) )
1436 goto raise_exn;
In a nutshell, x86_emulate always generates a segmentation
fault instead
of performing a legitim task swich or a legitim far jump
through a call
gate.
Is it normal ?
Unfortunately, (lack of) support for far calls/jumps to gates is a
known limitation. It it wasn't explicitly identified before, it did
come to light as part of c/s 653cae72 when trying to reduce the
number of x86 instruction decoders in the hypervisor to just one.
The current architecture of x86_emulate() makes it hard to fix. At
the most recent Xen Dev Summit, I proposed an alteration in
emulation architecture which will allow us to use one single
implementation which works for PV and HVM guests. It will have the
advantage of allowing us to harmonise the task switch logic as well,
which currently only works when initiated from a VT-x/SVM
TASK_SWITCH vmexit, rather than an emulation of `lcall $tss`
In short, its known broken and there is a plan to try and resolve
it.
~Andrew
|