Skip to content

Commit 59dbb9d

Browse files
committed
Merge tag 'xsa465+xsa466-6.13-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen fixes from Juergen Gross: "Fix xen netfront crash (XSA-465) and avoid using the hypercall page that doesn't do speculation mitigations (XSA-466)" * tag 'xsa465+xsa466-6.13-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: x86/xen: remove hypercall page x86/xen: use new hypercall functions instead of hypercall page x86/xen: add central hypercall functions x86/xen: don't do PV iret hypercall through hypercall page x86/static-call: provide a way to do very early static-call updates objtool/x86: allow syscall instruction x86: make get_cpu_vendor() accessible from Xen code xen/netfront: fix crash when removing device
2 parents f44d154 + 7fa0da5 commit 59dbb9d

File tree

20 files changed

+316
-108
lines changed

20 files changed

+316
-108
lines changed

arch/x86/include/asm/processor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,8 @@ static inline unsigned long long l1tf_pfn_limit(void)
230230
return BIT_ULL(boot_cpu_data.x86_cache_bits - 1 - PAGE_SHIFT);
231231
}
232232

233+
void init_cpu_devs(void);
234+
void get_cpu_vendor(struct cpuinfo_x86 *c);
233235
extern void early_cpu_init(void);
234236
extern void identify_secondary_cpu(struct cpuinfo_x86 *);
235237
extern void print_cpu_info(struct cpuinfo_x86 *);

arch/x86/include/asm/static_call.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,19 @@
6565

6666
extern bool __static_call_fixup(void *tramp, u8 op, void *dest);
6767

68+
extern void __static_call_update_early(void *tramp, void *func);
69+
70+
#define static_call_update_early(name, _func) \
71+
({ \
72+
typeof(&STATIC_CALL_TRAMP(name)) __F = (_func); \
73+
if (static_call_initialized) { \
74+
__static_call_update(&STATIC_CALL_KEY(name), \
75+
STATIC_CALL_TRAMP_ADDR(name), __F);\
76+
} else { \
77+
WRITE_ONCE(STATIC_CALL_KEY(name).func, _func); \
78+
__static_call_update_early(STATIC_CALL_TRAMP_ADDR(name),\
79+
__F); \
80+
} \
81+
})
82+
6883
#endif /* _ASM_STATIC_CALL_H */

arch/x86/include/asm/sync_core.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include <asm/special_insns.h>
99

1010
#ifdef CONFIG_X86_32
11-
static inline void iret_to_self(void)
11+
static __always_inline void iret_to_self(void)
1212
{
1313
asm volatile (
1414
"pushfl\n\t"
@@ -19,7 +19,7 @@ static inline void iret_to_self(void)
1919
: ASM_CALL_CONSTRAINT : : "memory");
2020
}
2121
#else
22-
static inline void iret_to_self(void)
22+
static __always_inline void iret_to_self(void)
2323
{
2424
unsigned int tmp;
2525

@@ -55,7 +55,7 @@ static inline void iret_to_self(void)
5555
* Like all of Linux's memory ordering operations, this is a
5656
* compiler barrier as well.
5757
*/
58-
static inline void sync_core(void)
58+
static __always_inline void sync_core(void)
5959
{
6060
/*
6161
* The SERIALIZE instruction is the most straightforward way to

arch/x86/include/asm/xen/hypercall.h

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@
3939
#include <linux/string.h>
4040
#include <linux/types.h>
4141
#include <linux/pgtable.h>
42+
#include <linux/instrumentation.h>
4243

4344
#include <trace/events/xen.h>
4445

46+
#include <asm/alternative.h>
4547
#include <asm/page.h>
4648
#include <asm/smap.h>
4749
#include <asm/nospec-branch.h>
@@ -86,11 +88,20 @@ struct xen_dm_op_buf;
8688
* there aren't more than 5 arguments...)
8789
*/
8890

89-
extern struct { char _entry[32]; } hypercall_page[];
91+
void xen_hypercall_func(void);
92+
DECLARE_STATIC_CALL(xen_hypercall, xen_hypercall_func);
9093

91-
#define __HYPERCALL "call hypercall_page+%c[offset]"
92-
#define __HYPERCALL_ENTRY(x) \
93-
[offset] "i" (__HYPERVISOR_##x * sizeof(hypercall_page[0]))
94+
#ifdef MODULE
95+
#define __ADDRESSABLE_xen_hypercall
96+
#else
97+
#define __ADDRESSABLE_xen_hypercall __ADDRESSABLE_ASM_STR(__SCK__xen_hypercall)
98+
#endif
99+
100+
#define __HYPERCALL \
101+
__ADDRESSABLE_xen_hypercall \
102+
"call __SCT__xen_hypercall"
103+
104+
#define __HYPERCALL_ENTRY(x) "a" (x)
94105

95106
#ifdef CONFIG_X86_32
96107
#define __HYPERCALL_RETREG "eax"
@@ -148,7 +159,7 @@ extern struct { char _entry[32]; } hypercall_page[];
148159
__HYPERCALL_0ARG(); \
149160
asm volatile (__HYPERCALL \
150161
: __HYPERCALL_0PARAM \
151-
: __HYPERCALL_ENTRY(name) \
162+
: __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
152163
: __HYPERCALL_CLOBBER0); \
153164
(type)__res; \
154165
})
@@ -159,7 +170,7 @@ extern struct { char _entry[32]; } hypercall_page[];
159170
__HYPERCALL_1ARG(a1); \
160171
asm volatile (__HYPERCALL \
161172
: __HYPERCALL_1PARAM \
162-
: __HYPERCALL_ENTRY(name) \
173+
: __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
163174
: __HYPERCALL_CLOBBER1); \
164175
(type)__res; \
165176
})
@@ -170,7 +181,7 @@ extern struct { char _entry[32]; } hypercall_page[];
170181
__HYPERCALL_2ARG(a1, a2); \
171182
asm volatile (__HYPERCALL \
172183
: __HYPERCALL_2PARAM \
173-
: __HYPERCALL_ENTRY(name) \
184+
: __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
174185
: __HYPERCALL_CLOBBER2); \
175186
(type)__res; \
176187
})
@@ -181,7 +192,7 @@ extern struct { char _entry[32]; } hypercall_page[];
181192
__HYPERCALL_3ARG(a1, a2, a3); \
182193
asm volatile (__HYPERCALL \
183194
: __HYPERCALL_3PARAM \
184-
: __HYPERCALL_ENTRY(name) \
195+
: __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
185196
: __HYPERCALL_CLOBBER3); \
186197
(type)__res; \
187198
})
@@ -192,7 +203,7 @@ extern struct { char _entry[32]; } hypercall_page[];
192203
__HYPERCALL_4ARG(a1, a2, a3, a4); \
193204
asm volatile (__HYPERCALL \
194205
: __HYPERCALL_4PARAM \
195-
: __HYPERCALL_ENTRY(name) \
206+
: __HYPERCALL_ENTRY(__HYPERVISOR_ ## name) \
196207
: __HYPERCALL_CLOBBER4); \
197208
(type)__res; \
198209
})
@@ -206,12 +217,9 @@ xen_single_call(unsigned int call,
206217
__HYPERCALL_DECLS;
207218
__HYPERCALL_5ARG(a1, a2, a3, a4, a5);
208219

209-
if (call >= PAGE_SIZE / sizeof(hypercall_page[0]))
210-
return -EINVAL;
211-
212-
asm volatile(CALL_NOSPEC
220+
asm volatile(__HYPERCALL
213221
: __HYPERCALL_5PARAM
214-
: [thunk_target] "a" (&hypercall_page[call])
222+
: __HYPERCALL_ENTRY(call)
215223
: __HYPERCALL_CLOBBER5);
216224

217225
return (long)__res;

arch/x86/kernel/callthunks.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,6 @@ static bool skip_addr(void *dest)
142142
if (dest >= (void *)relocate_kernel &&
143143
dest < (void*)relocate_kernel + KEXEC_CONTROL_CODE_MAX_SIZE)
144144
return true;
145-
#endif
146-
#ifdef CONFIG_XEN
147-
if (dest >= (void *)hypercall_page &&
148-
dest < (void*)hypercall_page + PAGE_SIZE)
149-
return true;
150145
#endif
151146
return false;
152147
}

arch/x86/kernel/cpu/common.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ static void cpu_detect_tlb(struct cpuinfo_x86 *c)
867867
tlb_lld_4m[ENTRIES], tlb_lld_1g[ENTRIES]);
868868
}
869869

870-
static void get_cpu_vendor(struct cpuinfo_x86 *c)
870+
void get_cpu_vendor(struct cpuinfo_x86 *c)
871871
{
872872
char *v = c->x86_vendor_id;
873873
int i;
@@ -1649,36 +1649,42 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
16491649
detect_nopl();
16501650
}
16511651

1652-
void __init early_cpu_init(void)
1652+
void __init init_cpu_devs(void)
16531653
{
16541654
const struct cpu_dev *const *cdev;
16551655
int count = 0;
16561656

1657-
#ifdef CONFIG_PROCESSOR_SELECT
1658-
pr_info("KERNEL supported cpus:\n");
1659-
#endif
1660-
16611657
for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
16621658
const struct cpu_dev *cpudev = *cdev;
16631659

16641660
if (count >= X86_VENDOR_NUM)
16651661
break;
16661662
cpu_devs[count] = cpudev;
16671663
count++;
1664+
}
1665+
}
16681666

1667+
void __init early_cpu_init(void)
1668+
{
16691669
#ifdef CONFIG_PROCESSOR_SELECT
1670-
{
1671-
unsigned int j;
1672-
1673-
for (j = 0; j < 2; j++) {
1674-
if (!cpudev->c_ident[j])
1675-
continue;
1676-
pr_info(" %s %s\n", cpudev->c_vendor,
1677-
cpudev->c_ident[j]);
1678-
}
1679-
}
1670+
unsigned int i, j;
1671+
1672+
pr_info("KERNEL supported cpus:\n");
16801673
#endif
1674+
1675+
init_cpu_devs();
1676+
1677+
#ifdef CONFIG_PROCESSOR_SELECT
1678+
for (i = 0; i < X86_VENDOR_NUM && cpu_devs[i]; i++) {
1679+
for (j = 0; j < 2; j++) {
1680+
if (!cpu_devs[i]->c_ident[j])
1681+
continue;
1682+
pr_info(" %s %s\n", cpu_devs[i]->c_vendor,
1683+
cpu_devs[i]->c_ident[j]);
1684+
}
16811685
}
1686+
#endif
1687+
16821688
early_identify_cpu(&boot_cpu_data);
16831689
}
16841690

arch/x86/kernel/static_call.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,15 @@ void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
172172
}
173173
EXPORT_SYMBOL_GPL(arch_static_call_transform);
174174

175+
noinstr void __static_call_update_early(void *tramp, void *func)
176+
{
177+
BUG_ON(system_state != SYSTEM_BOOTING);
178+
BUG_ON(!early_boot_irqs_disabled);
179+
BUG_ON(static_call_initialized);
180+
__text_gen_insn(tramp, JMP32_INSN_OPCODE, tramp, func, JMP32_INSN_SIZE);
181+
sync_core();
182+
}
183+
175184
#ifdef CONFIG_MITIGATION_RETHUNK
176185
/*
177186
* This is called by apply_returns() to fix up static call trampolines,

arch/x86/kernel/vmlinux.lds.S

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -519,14 +519,10 @@ INIT_PER_CPU(irq_stack_backing_store);
519519
* linker will never mark as relocatable. (Using just ABSOLUTE() is not
520520
* sufficient for that).
521521
*/
522-
#ifdef CONFIG_XEN
523522
#ifdef CONFIG_XEN_PV
524523
xen_elfnote_entry_value =
525524
ABSOLUTE(xen_elfnote_entry) + ABSOLUTE(startup_xen);
526525
#endif
527-
xen_elfnote_hypercall_page_value =
528-
ABSOLUTE(xen_elfnote_hypercall_page) + ABSOLUTE(hypercall_page);
529-
#endif
530526
#ifdef CONFIG_PVH
531527
xen_elfnote_phys32_entry_value =
532528
ABSOLUTE(xen_elfnote_phys32_entry) + ABSOLUTE(pvh_start_xen - LOAD_OFFSET);

arch/x86/xen/enlighten.c

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <linux/console.h>
44
#include <linux/cpu.h>
5+
#include <linux/instrumentation.h>
56
#include <linux/kexec.h>
67
#include <linux/memblock.h>
78
#include <linux/slab.h>
@@ -21,7 +22,8 @@
2122

2223
#include "xen-ops.h"
2324

24-
EXPORT_SYMBOL_GPL(hypercall_page);
25+
DEFINE_STATIC_CALL(xen_hypercall, xen_hypercall_hvm);
26+
EXPORT_STATIC_CALL_TRAMP(xen_hypercall);
2527

2628
/*
2729
* Pointer to the xen_vcpu_info structure or
@@ -68,6 +70,67 @@ EXPORT_SYMBOL(xen_start_flags);
6870
*/
6971
struct shared_info *HYPERVISOR_shared_info = &xen_dummy_shared_info;
7072

73+
static __ref void xen_get_vendor(void)
74+
{
75+
init_cpu_devs();
76+
cpu_detect(&boot_cpu_data);
77+
get_cpu_vendor(&boot_cpu_data);
78+
}
79+
80+
void xen_hypercall_setfunc(void)
81+
{
82+
if (static_call_query(xen_hypercall) != xen_hypercall_hvm)
83+
return;
84+
85+
if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
86+
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON))
87+
static_call_update(xen_hypercall, xen_hypercall_amd);
88+
else
89+
static_call_update(xen_hypercall, xen_hypercall_intel);
90+
}
91+
92+
/*
93+
* Evaluate processor vendor in order to select the correct hypercall
94+
* function for HVM/PVH guests.
95+
* Might be called very early in boot before vendor has been set by
96+
* early_cpu_init().
97+
*/
98+
noinstr void *__xen_hypercall_setfunc(void)
99+
{
100+
void (*func)(void);
101+
102+
/*
103+
* Xen is supported only on CPUs with CPUID, so testing for
104+
* X86_FEATURE_CPUID is a test for early_cpu_init() having been
105+
* run.
106+
*
107+
* Note that __xen_hypercall_setfunc() is noinstr only due to a nasty
108+
* dependency chain: it is being called via the xen_hypercall static
109+
* call when running as a PVH or HVM guest. Hypercalls need to be
110+
* noinstr due to PV guests using hypercalls in noinstr code. So we
111+
* can safely tag the function body as "instrumentation ok", since
112+
* the PV guest requirement is not of interest here (xen_get_vendor()
113+
* calls noinstr functions, and static_call_update_early() might do
114+
* so, too).
115+
*/
116+
instrumentation_begin();
117+
118+
if (!boot_cpu_has(X86_FEATURE_CPUID))
119+
xen_get_vendor();
120+
121+
if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
122+
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON))
123+
func = xen_hypercall_amd;
124+
else
125+
func = xen_hypercall_intel;
126+
127+
static_call_update_early(xen_hypercall, func);
128+
129+
instrumentation_end();
130+
131+
return func;
132+
}
133+
71134
static int xen_cpu_up_online(unsigned int cpu)
72135
{
73136
xen_init_lock_cpu(cpu);

arch/x86/xen/enlighten_hvm.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,8 @@ static void __init init_hvm_pv_info(void)
106106
/* PVH set up hypercall page in xen_prepare_pvh(). */
107107
if (xen_pvh_domain())
108108
pv_info.name = "Xen PVH";
109-
else {
110-
u64 pfn;
111-
uint32_t msr;
112-
109+
else
113110
pv_info.name = "Xen HVM";
114-
msr = cpuid_ebx(base + 2);
115-
pfn = __pa(hypercall_page);
116-
wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
117-
}
118111

119112
xen_setup_features();
120113

@@ -300,6 +293,10 @@ static uint32_t __init xen_platform_hvm(void)
300293
if (xen_pv_domain())
301294
return 0;
302295

296+
/* Set correct hypercall function. */
297+
if (xen_domain)
298+
xen_hypercall_setfunc();
299+
303300
if (xen_pvh_domain() && nopv) {
304301
/* Guest booting via the Xen-PVH boot entry goes here */
305302
pr_info("\"nopv\" parameter is ignored in PVH guest\n");

0 commit comments

Comments
 (0)