Skip to content

Commit 0594c58

Browse files
jbeulichjgross1
authored andcommitted
xen/x86: fix PV trap handling on secondary processors
The initial observation was that in PV mode under Xen 32-bit user space didn't work anymore. Attempts of system calls ended in #GP(0x402). All of the sudden the vector 0x80 handler was not in place anymore. As it turns out up to 5.13 redundant initialization did occur: Once from cpu_initialize_context() (through its VCPUOP_initialise hypercall) and a 2nd time while each CPU was brought fully up. This 2nd initialization is now gone, uncovering that the 1st one was flawed: Unlike for the set_trap_table hypercall, a full virtual IDT needs to be specified here; the "vector" fields of the individual entries are of no interest. With many (kernel) IDT entries still(?) (i.e. at that point at least) empty, the syscall vector 0x80 ended up in slot 0x20 of the virtual IDT, thus becoming the domain's handler for vector 0x20. Make xen_convert_trap_info() fit for either purpose, leveraging the fact that on the xen_copy_trap_info() path the table starts out zero-filled. This includes moving out the writing of the sentinel, which would also have lead to a buffer overrun in the xen_copy_trap_info() case if all (kernel) IDT entries were populated. Convert the writing of the sentinel to clearing of the entire table entry rather than just the address field. (I didn't bother trying to identify the commit which uncovered the issue in 5.14; the commit named below is the one which actually introduced the bad code.) Fixes: f87e4ca ("xen: SMP guest support") Cc: [email protected] Signed-off-by: Jan Beulich <[email protected]> Reviewed-by: Boris Ostrovsky <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Juergen Gross <[email protected]>
1 parent 96f5bd0 commit 0594c58

File tree

1 file changed

+9
-6
lines changed

1 file changed

+9
-6
lines changed

arch/x86/xen/enlighten_pv.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,8 @@ static void xen_write_idt_entry(gate_desc *dt, int entrynum, const gate_desc *g)
755755
preempt_enable();
756756
}
757757

758-
static void xen_convert_trap_info(const struct desc_ptr *desc,
759-
struct trap_info *traps)
758+
static unsigned xen_convert_trap_info(const struct desc_ptr *desc,
759+
struct trap_info *traps, bool full)
760760
{
761761
unsigned in, out, count;
762762

@@ -766,17 +766,18 @@ static void xen_convert_trap_info(const struct desc_ptr *desc,
766766
for (in = out = 0; in < count; in++) {
767767
gate_desc *entry = (gate_desc *)(desc->address) + in;
768768

769-
if (cvt_gate_to_trap(in, entry, &traps[out]))
769+
if (cvt_gate_to_trap(in, entry, &traps[out]) || full)
770770
out++;
771771
}
772-
traps[out].address = 0;
772+
773+
return out;
773774
}
774775

775776
void xen_copy_trap_info(struct trap_info *traps)
776777
{
777778
const struct desc_ptr *desc = this_cpu_ptr(&idt_desc);
778779

779-
xen_convert_trap_info(desc, traps);
780+
xen_convert_trap_info(desc, traps, true);
780781
}
781782

782783
/* Load a new IDT into Xen. In principle this can be per-CPU, so we
@@ -786,14 +787,16 @@ static void xen_load_idt(const struct desc_ptr *desc)
786787
{
787788
static DEFINE_SPINLOCK(lock);
788789
static struct trap_info traps[257];
790+
unsigned out;
789791

790792
trace_xen_cpu_load_idt(desc);
791793

792794
spin_lock(&lock);
793795

794796
memcpy(this_cpu_ptr(&idt_desc), desc, sizeof(idt_desc));
795797

796-
xen_convert_trap_info(desc, traps);
798+
out = xen_convert_trap_info(desc, traps, false);
799+
memset(&traps[out], 0, sizeof(traps[0]));
797800

798801
xen_mc_flush();
799802
if (HYPERVISOR_set_trap_table(traps))

0 commit comments

Comments
 (0)