Skip to content

Commit a358505

Browse files
committed
Merge tag 'x86_entry_for_5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 entry fixes from Borislav Petkov: "This is the x86/entry urgent pile which has accumulated since the merge window. It is not the smallest but considering the almost complete entry core rewrite, the amount of fixes to follow is somewhat higher than usual, which is to be expected. Peter Zijlstra says: 'These patches address a number of instrumentation issues that were found after the x86/entry overhaul. When combined with rcu/urgent and objtool/urgent, these patches make UBSAN/KASAN/KCSAN happy again. Part of making this all work is bumping the minimum GCC version for KASAN builds to gcc-8.3, the reason for this is that the __no_sanitize_address function attribute is broken in GCC releases before that. No known GCC version has a working __no_sanitize_undefined, however because the only noinstr violation that results from this happens when an UB is found, we treat it like WARN. That is, we allow it to violate the noinstr rules in order to get the warning out'" * tag 'x86_entry_for_5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/entry: Fix #UD vs WARN more x86/entry: Increase entry_stack size to a full page x86/entry: Fixup bad_iret vs noinstr objtool: Don't consider vmlinux a C-file kasan: Fix required compiler version compiler_attributes.h: Support no_sanitize_undefined check with GCC 4 x86/entry, bug: Comment the instrumentation_begin() usage for WARN() x86/entry, ubsan, objtool: Whitelist __ubsan_handle_*() x86/entry, cpumask: Provide non-instrumented variant of cpu_is_offline() compiler_types.h: Add __no_sanitize_{address,undefined} to noinstr kasan: Bump required compiler version x86, kcsan: Add __no_kcsan to noinstr kcsan: Remove __no_kcsan_or_inline x86, kcsan: Remove __no_kcsan_or_inline usage
2 parents 719fdd3 + 2c92d78 commit a358505

File tree

15 files changed

+126
-61
lines changed

15 files changed

+126
-61
lines changed

Documentation/dev-tools/kcsan.rst

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,6 @@ the below options are available:
114114
To dynamically limit for which functions to generate reports, see the
115115
`DebugFS interface`_ blacklist/whitelist feature.
116116

117-
For ``__always_inline`` functions, replace ``__always_inline`` with
118-
``__no_kcsan_or_inline`` (which implies ``__always_inline``)::
119-
120-
static __no_kcsan_or_inline void foo(void) {
121-
...
122-
123117
* To disable data race detection for a particular compilation unit, add to the
124118
``Makefile``::
125119

arch/x86/include/asm/bitops.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,8 @@ arch_test_and_change_bit(long nr, volatile unsigned long *addr)
201201
return GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btc), *addr, c, "Ir", nr);
202202
}
203203

204-
static __no_kcsan_or_inline bool constant_test_bit(long nr, const volatile unsigned long *addr)
204+
static __always_inline bool constant_test_bit(long nr, const volatile unsigned long *addr)
205205
{
206-
/*
207-
* Because this is a plain access, we need to disable KCSAN here to
208-
* avoid double instrumentation via instrumented bitops.
209-
*/
210206
return ((1UL << (nr & (BITS_PER_LONG-1))) &
211207
(addr[nr >> _BITOPS_LONG_SHIFT])) != 0;
212208
}

arch/x86/include/asm/bug.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ do { \
7575
unreachable(); \
7676
} while (0)
7777

78+
/*
79+
* This instrumentation_begin() is strictly speaking incorrect; but it
80+
* suppresses the complaints from WARN()s in noinstr code. If such a WARN()
81+
* were to trigger, we'd rather wreck the machine in an attempt to get the
82+
* message out than not know about it.
83+
*/
7884
#define __WARN_FLAGS(flags) \
7985
do { \
8086
instrumentation_begin(); \

arch/x86/include/asm/cpumask.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,23 @@ extern cpumask_var_t cpu_sibling_setup_mask;
1111

1212
extern void setup_cpu_local_masks(void);
1313

14+
/*
15+
* NMI and MCE exceptions need cpu_is_offline() _really_ early,
16+
* provide an arch_ special for them to avoid instrumentation.
17+
*/
18+
#if NR_CPUS > 1
19+
static __always_inline bool arch_cpu_online(int cpu)
20+
{
21+
return arch_test_bit(cpu, cpumask_bits(cpu_online_mask));
22+
}
23+
#else
24+
static __always_inline bool arch_cpu_online(int cpu)
25+
{
26+
return cpu == 0;
27+
}
28+
#endif
29+
30+
#define arch_cpu_is_offline(cpu) unlikely(!arch_cpu_online(cpu))
31+
1432
#endif /* __ASSEMBLY__ */
1533
#endif /* _ASM_X86_CPUMASK_H */

arch/x86/include/asm/processor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ struct x86_hw_tss {
370370
#define IO_BITMAP_OFFSET_INVALID (__KERNEL_TSS_LIMIT + 1)
371371

372372
struct entry_stack {
373-
unsigned long words[64];
373+
char stack[PAGE_SIZE];
374374
};
375375

376376
struct entry_stack_page {

arch/x86/kernel/cpu/mce/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@ static noinstr bool mce_check_crashing_cpu(void)
10831083
{
10841084
unsigned int cpu = smp_processor_id();
10851085

1086-
if (cpu_is_offline(cpu) ||
1086+
if (arch_cpu_is_offline(cpu) ||
10871087
(crashing_cpu != -1 && crashing_cpu != cpu)) {
10881088
u64 mcgstatus;
10891089

arch/x86/kernel/nmi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ static DEFINE_PER_CPU(unsigned long, nmi_dr7);
478478

479479
DEFINE_IDTENTRY_RAW(exc_nmi)
480480
{
481-
if (IS_ENABLED(CONFIG_SMP) && cpu_is_offline(smp_processor_id()))
481+
if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id()))
482482
return;
483483

484484
if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) {

arch/x86/kernel/traps.c

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,16 @@ static inline void cond_local_irq_disable(struct pt_regs *regs)
8484
local_irq_disable();
8585
}
8686

87-
int is_valid_bugaddr(unsigned long addr)
87+
__always_inline int is_valid_bugaddr(unsigned long addr)
8888
{
89-
unsigned short ud;
90-
9189
if (addr < TASK_SIZE_MAX)
9290
return 0;
9391

94-
if (get_kernel_nofault(ud, (unsigned short *)addr))
95-
return 0;
96-
97-
return ud == INSN_UD0 || ud == INSN_UD2;
92+
/*
93+
* We got #UD, if the text isn't readable we'd have gotten
94+
* a different exception.
95+
*/
96+
return *(unsigned short *)addr == INSN_UD2;
9897
}
9998

10099
static nokprobe_inline int
@@ -216,40 +215,45 @@ static inline void handle_invalid_op(struct pt_regs *regs)
216215
ILL_ILLOPN, error_get_trap_addr(regs));
217216
}
218217

219-
DEFINE_IDTENTRY_RAW(exc_invalid_op)
218+
static noinstr bool handle_bug(struct pt_regs *regs)
220219
{
221-
bool rcu_exit;
220+
bool handled = false;
221+
222+
if (!is_valid_bugaddr(regs->ip))
223+
return handled;
222224

223225
/*
224-
* Handle BUG/WARN like NMIs instead of like normal idtentries:
225-
* if we bugged/warned in a bad RCU context, for example, the last
226-
* thing we want is to BUG/WARN again in the idtentry code, ad
227-
* infinitum.
226+
* All lies, just get the WARN/BUG out.
228227
*/
229-
if (!user_mode(regs) && is_valid_bugaddr(regs->ip)) {
230-
enum bug_trap_type type;
228+
instrumentation_begin();
229+
/*
230+
* Since we're emulating a CALL with exceptions, restore the interrupt
231+
* state to what it was at the exception site.
232+
*/
233+
if (regs->flags & X86_EFLAGS_IF)
234+
raw_local_irq_enable();
235+
if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
236+
regs->ip += LEN_UD2;
237+
handled = true;
238+
}
239+
if (regs->flags & X86_EFLAGS_IF)
240+
raw_local_irq_disable();
241+
instrumentation_end();
231242

232-
nmi_enter();
233-
instrumentation_begin();
234-
trace_hardirqs_off_finish();
235-
type = report_bug(regs->ip, regs);
236-
if (regs->flags & X86_EFLAGS_IF)
237-
trace_hardirqs_on_prepare();
238-
instrumentation_end();
239-
nmi_exit();
243+
return handled;
244+
}
240245

241-
if (type == BUG_TRAP_TYPE_WARN) {
242-
/* Skip the ud2. */
243-
regs->ip += LEN_UD2;
244-
return;
245-
}
246+
DEFINE_IDTENTRY_RAW(exc_invalid_op)
247+
{
248+
bool rcu_exit;
246249

247-
/*
248-
* Else, if this was a BUG and report_bug returns or if this
249-
* was just a normal #UD, we want to continue onward and
250-
* crash.
251-
*/
252-
}
250+
/*
251+
* We use UD2 as a short encoding for 'CALL __WARN', as such
252+
* handle it before exception entry to avoid recursive WARN
253+
* in case exception entry is the one triggering WARNs.
254+
*/
255+
if (!user_mode(regs) && handle_bug(regs))
256+
return;
253257

254258
rcu_exit = idtentry_enter_cond_rcu(regs);
255259
instrumentation_begin();
@@ -691,13 +695,13 @@ struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s)
691695
(struct bad_iret_stack *)__this_cpu_read(cpu_tss_rw.x86_tss.sp0) - 1;
692696

693697
/* Copy the IRET target to the temporary storage. */
694-
memcpy(&tmp.regs.ip, (void *)s->regs.sp, 5*8);
698+
__memcpy(&tmp.regs.ip, (void *)s->regs.sp, 5*8);
695699

696700
/* Copy the remainder of the stack from the current stack. */
697-
memcpy(&tmp, s, offsetof(struct bad_iret_stack, regs.ip));
701+
__memcpy(&tmp, s, offsetof(struct bad_iret_stack, regs.ip));
698702

699703
/* Update the entry stack */
700-
memcpy(new_stack, &tmp, sizeof(tmp));
704+
__memcpy(new_stack, &tmp, sizeof(tmp));
701705

702706
BUG_ON(!user_mode(&new_stack->regs));
703707
return new_stack;

arch/x86/lib/memcpy_64.S

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <asm/alternative-asm.h>
99
#include <asm/export.h>
1010

11+
.pushsection .noinstr.text, "ax"
12+
1113
/*
1214
* We build a jump to memcpy_orig by default which gets NOPped out on
1315
* the majority of x86 CPUs which set REP_GOOD. In addition, CPUs which
@@ -184,6 +186,8 @@ SYM_FUNC_START_LOCAL(memcpy_orig)
184186
retq
185187
SYM_FUNC_END(memcpy_orig)
186188

189+
.popsection
190+
187191
#ifndef CONFIG_UML
188192

189193
MCSAFE_TEST_CTL

include/linux/compiler-clang.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@
3333
#define __no_sanitize_thread
3434
#endif
3535

36+
#if __has_feature(undefined_behavior_sanitizer)
37+
/* GCC does not have __SANITIZE_UNDEFINED__ */
38+
#define __no_sanitize_undefined \
39+
__attribute__((no_sanitize("undefined")))
40+
#else
41+
#define __no_sanitize_undefined
42+
#endif
43+
3644
/*
3745
* Not all versions of clang implement the the type-generic versions
3846
* of the builtin overflow checkers. Fortunately, clang implements

0 commit comments

Comments
 (0)