Skip to content

Commit a7b3474

Browse files
KAGA-KOKOsuryasaimadhu
authored andcommitted
x86/irq: Make run_on_irqstack_cond() typesafe
Sami reported that run_on_irqstack_cond() requires the caller to cast functions to mismatching types, which trips indirect call Control-Flow Integrity (CFI) in Clang. Instead of disabling CFI on that function, provide proper helpers for the three call variants. The actual ASM code stays the same as that is out of reach. [ bp: Fix __run_on_irqstack() prototype to match. ] Fixes: 931b941 ("x86/entry: Provide helpers for executing on the irqstack") Reported-by: Nathan Chancellor <[email protected]> Reported-by: Sami Tolvanen <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Borislav Petkov <[email protected]> Tested-by: Sami Tolvanen <[email protected]> Cc: <[email protected]> Link: ClangBuiltLinux#1052 Link: https://lkml.kernel.org/r/[email protected]
1 parent 9847774 commit a7b3474

File tree

6 files changed

+67
-12
lines changed

6 files changed

+67
-12
lines changed

arch/x86/entry/common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ __visible noinstr void xen_pv_evtchn_do_upcall(struct pt_regs *regs)
299299
old_regs = set_irq_regs(regs);
300300

301301
instrumentation_begin();
302-
run_on_irqstack_cond(__xen_pv_evtchn_do_upcall, NULL, regs);
302+
run_on_irqstack_cond(__xen_pv_evtchn_do_upcall, regs);
303303
instrumentation_begin();
304304

305305
set_irq_regs(old_regs);

arch/x86/entry/entry_64.S

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,8 @@ SYM_CODE_END(.Lbad_gs)
682682
* rdx: Function argument (can be NULL if none)
683683
*/
684684
SYM_FUNC_START(asm_call_on_stack)
685+
SYM_INNER_LABEL(asm_call_sysvec_on_stack, SYM_L_GLOBAL)
686+
SYM_INNER_LABEL(asm_call_irq_on_stack, SYM_L_GLOBAL)
685687
/*
686688
* Save the frame pointer unconditionally. This allows the ORC
687689
* unwinder to handle the stack switch.

arch/x86/include/asm/idtentry.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ __visible noinstr void func(struct pt_regs *regs) \
242242
instrumentation_begin(); \
243243
irq_enter_rcu(); \
244244
kvm_set_cpu_l1tf_flush_l1d(); \
245-
run_on_irqstack_cond(__##func, regs, regs); \
245+
run_sysvec_on_irqstack_cond(__##func, regs); \
246246
irq_exit_rcu(); \
247247
instrumentation_end(); \
248248
irqentry_exit(regs, state); \

arch/x86/include/asm/irq_stack.h

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,50 @@ static __always_inline bool irqstack_active(void)
1212
return __this_cpu_read(irq_count) != -1;
1313
}
1414

15-
void asm_call_on_stack(void *sp, void *func, void *arg);
15+
void asm_call_on_stack(void *sp, void (*func)(void), void *arg);
16+
void asm_call_sysvec_on_stack(void *sp, void (*func)(struct pt_regs *regs),
17+
struct pt_regs *regs);
18+
void asm_call_irq_on_stack(void *sp, void (*func)(struct irq_desc *desc),
19+
struct irq_desc *desc);
1620

17-
static __always_inline void __run_on_irqstack(void *func, void *arg)
21+
static __always_inline void __run_on_irqstack(void (*func)(void))
1822
{
1923
void *tos = __this_cpu_read(hardirq_stack_ptr);
2024

2125
__this_cpu_add(irq_count, 1);
22-
asm_call_on_stack(tos - 8, func, arg);
26+
asm_call_on_stack(tos - 8, func, NULL);
27+
__this_cpu_sub(irq_count, 1);
28+
}
29+
30+
static __always_inline void
31+
__run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs),
32+
struct pt_regs *regs)
33+
{
34+
void *tos = __this_cpu_read(hardirq_stack_ptr);
35+
36+
__this_cpu_add(irq_count, 1);
37+
asm_call_sysvec_on_stack(tos - 8, func, regs);
38+
__this_cpu_sub(irq_count, 1);
39+
}
40+
41+
static __always_inline void
42+
__run_irq_on_irqstack(void (*func)(struct irq_desc *desc),
43+
struct irq_desc *desc)
44+
{
45+
void *tos = __this_cpu_read(hardirq_stack_ptr);
46+
47+
__this_cpu_add(irq_count, 1);
48+
asm_call_irq_on_stack(tos - 8, func, desc);
2349
__this_cpu_sub(irq_count, 1);
2450
}
2551

2652
#else /* CONFIG_X86_64 */
2753
static inline bool irqstack_active(void) { return false; }
28-
static inline void __run_on_irqstack(void *func, void *arg) { }
54+
static inline void __run_on_irqstack(void (*func)(void)) { }
55+
static inline void __run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs),
56+
struct pt_regs *regs) { }
57+
static inline void __run_irq_on_irqstack(void (*func)(struct irq_desc *desc),
58+
struct irq_desc *desc) { }
2959
#endif /* !CONFIG_X86_64 */
3060

3161
static __always_inline bool irq_needs_irq_stack(struct pt_regs *regs)
@@ -37,17 +67,40 @@ static __always_inline bool irq_needs_irq_stack(struct pt_regs *regs)
3767
return !user_mode(regs) && !irqstack_active();
3868
}
3969

40-
static __always_inline void run_on_irqstack_cond(void *func, void *arg,
70+
71+
static __always_inline void run_on_irqstack_cond(void (*func)(void),
4172
struct pt_regs *regs)
4273
{
43-
void (*__func)(void *arg) = func;
74+
lockdep_assert_irqs_disabled();
75+
76+
if (irq_needs_irq_stack(regs))
77+
__run_on_irqstack(func);
78+
else
79+
func();
80+
}
81+
82+
static __always_inline void
83+
run_sysvec_on_irqstack_cond(void (*func)(struct pt_regs *regs),
84+
struct pt_regs *regs)
85+
{
86+
lockdep_assert_irqs_disabled();
4487

88+
if (irq_needs_irq_stack(regs))
89+
__run_sysvec_on_irqstack(func, regs);
90+
else
91+
func(regs);
92+
}
93+
94+
static __always_inline void
95+
run_irq_on_irqstack_cond(void (*func)(struct irq_desc *desc), struct irq_desc *desc,
96+
struct pt_regs *regs)
97+
{
4598
lockdep_assert_irqs_disabled();
4699

47100
if (irq_needs_irq_stack(regs))
48-
__run_on_irqstack(__func, arg);
101+
__run_irq_on_irqstack(func, desc);
49102
else
50-
__func(arg);
103+
func(desc);
51104
}
52105

53106
#endif

arch/x86/kernel/irq.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ static __always_inline void handle_irq(struct irq_desc *desc,
227227
struct pt_regs *regs)
228228
{
229229
if (IS_ENABLED(CONFIG_X86_64))
230-
run_on_irqstack_cond(desc->handle_irq, desc, regs);
230+
run_irq_on_irqstack_cond(desc->handle_irq, desc, regs);
231231
else
232232
__handle_irq(desc, regs);
233233
}

arch/x86/kernel/irq_64.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,5 @@ int irq_init_percpu_irqstack(unsigned int cpu)
7474

7575
void do_softirq_own_stack(void)
7676
{
77-
run_on_irqstack_cond(__do_softirq, NULL, NULL);
77+
run_on_irqstack_cond(__do_softirq, NULL);
7878
}

0 commit comments

Comments
 (0)