Skip to content

Commit 1154bbd

Browse files
jpoimboeingomolnar
authored andcommitted
objtool: Fix X86_FEATURE_SMAP alternative handling
For X86_FEATURE_SMAP alternatives which replace NOP with STAC or CLAC, uaccess validation skips the NOP branch to avoid following impossible code paths, e.g. where a STAC would be patched but a CLAC wouldn't. However, it's not safe to assume an X86_FEATURE_SMAP alternative is patching STAC/CLAC. There can be other alternatives, like static_cpu_has(), where both branches need to be validated. Fix that by repurposing ANNOTATE_IGNORE_ALTERNATIVE for skipping either original instructions or new ones. This is a more generic approach which enables the removal of the feature checking hacks and the insn->ignore bit. Fixes the following warnings: arch/x86/mm/fault.o: warning: objtool: do_user_addr_fault+0x8ec: __stack_chk_fail() missing __noreturn in .c/.h or NORETURN() in noreturns.h arch/x86/mm/fault.o: warning: objtool: do_user_addr_fault+0x8f1: unreachable instruction [ mingo: Fix up conflicts with recent x86 changes. ] Fixes: ea24213 ("objtool: Add UACCESS validation") Reported-by: kernel test robot <lkp@intel.com> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: https://lore.kernel.org/r/de0621ca242130156a55d5d74fed86994dfa4c9c.1742852846.git.jpoimboe@kernel.org Closes: https://lore.kernel.org/oe-kbuild-all/202503181736.zkZUBv4N-lkp@intel.com/
1 parent c84301d commit 1154bbd

8 files changed

Lines changed: 37 additions & 89 deletions

File tree

arch/x86/include/asm/arch_hweight.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ static __always_inline unsigned int __arch_hweight32(unsigned int w)
1616
{
1717
unsigned int res;
1818

19-
asm_inline (ALTERNATIVE("call __sw_hweight32",
19+
asm_inline (ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
20+
"call __sw_hweight32",
2021
"popcntl %[val], %[cnt]", X86_FEATURE_POPCNT)
2122
: [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
2223
: [val] REG_IN (w));
@@ -45,7 +46,8 @@ static __always_inline unsigned long __arch_hweight64(__u64 w)
4546
{
4647
unsigned long res;
4748

48-
asm_inline (ALTERNATIVE("call __sw_hweight64",
49+
asm_inline (ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
50+
"call __sw_hweight64",
4951
"popcntq %[val], %[cnt]", X86_FEATURE_POPCNT)
5052
: [cnt] "=" REG_OUT (res), ASM_CALL_CONSTRAINT
5153
: [val] REG_IN (w));

arch/x86/include/asm/smap.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,32 @@
1616
#ifdef __ASSEMBLER__
1717

1818
#define ASM_CLAC \
19-
ALTERNATIVE "", "clac", X86_FEATURE_SMAP
19+
ALTERNATIVE __stringify(ANNOTATE_IGNORE_ALTERNATIVE), "clac", X86_FEATURE_SMAP
2020

2121
#define ASM_STAC \
22-
ALTERNATIVE "", "stac", X86_FEATURE_SMAP
22+
ALTERNATIVE __stringify(ANNOTATE_IGNORE_ALTERNATIVE), "stac", X86_FEATURE_SMAP
2323

2424
#else /* __ASSEMBLER__ */
2525

2626
static __always_inline void clac(void)
2727
{
2828
/* Note: a barrier is implicit in alternative() */
29-
alternative("", "clac", X86_FEATURE_SMAP);
29+
alternative(ANNOTATE_IGNORE_ALTERNATIVE "", "clac", X86_FEATURE_SMAP);
3030
}
3131

3232
static __always_inline void stac(void)
3333
{
3434
/* Note: a barrier is implicit in alternative() */
35-
alternative("", "stac", X86_FEATURE_SMAP);
35+
alternative(ANNOTATE_IGNORE_ALTERNATIVE "", "stac", X86_FEATURE_SMAP);
3636
}
3737

3838
static __always_inline unsigned long smap_save(void)
3939
{
4040
unsigned long flags;
4141

4242
asm volatile ("# smap_save\n\t"
43-
ALTERNATIVE("", "pushf; pop %0; " "clac" "\n\t",
43+
ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
44+
"", "pushf; pop %0; clac",
4445
X86_FEATURE_SMAP)
4546
: "=rm" (flags) : : "memory", "cc");
4647

@@ -50,16 +51,22 @@ static __always_inline unsigned long smap_save(void)
5051
static __always_inline void smap_restore(unsigned long flags)
5152
{
5253
asm volatile ("# smap_restore\n\t"
53-
ALTERNATIVE("", "push %0; popf\n\t",
54+
ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE
55+
"", "push %0; popf",
5456
X86_FEATURE_SMAP)
5557
: : "g" (flags) : "memory", "cc");
5658
}
5759

5860
/* These macros can be used in asm() statements */
5961
#define ASM_CLAC \
60-
ALTERNATIVE("", "clac", X86_FEATURE_SMAP)
62+
ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "", "clac", X86_FEATURE_SMAP)
6163
#define ASM_STAC \
62-
ALTERNATIVE("", "stac", X86_FEATURE_SMAP)
64+
ALTERNATIVE(ANNOTATE_IGNORE_ALTERNATIVE "", "stac", X86_FEATURE_SMAP)
65+
66+
#define ASM_CLAC_UNSAFE \
67+
ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "clac", X86_FEATURE_SMAP)
68+
#define ASM_STAC_UNSAFE \
69+
ALTERNATIVE("", ANNOTATE_IGNORE_ALTERNATIVE "stac", X86_FEATURE_SMAP)
6370

6471
#endif /* __ASSEMBLER__ */
6572

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,14 +231,12 @@ static __always_inline void __xen_stac(void)
231231
* Suppress objtool seeing the STAC/CLAC and getting confused about it
232232
* calling random code with AC=1.
233233
*/
234-
asm volatile(ANNOTATE_IGNORE_ALTERNATIVE
235-
ASM_STAC ::: "memory", "flags");
234+
asm volatile(ASM_STAC_UNSAFE ::: "memory", "flags");
236235
}
237236

238237
static __always_inline void __xen_clac(void)
239238
{
240-
asm volatile(ANNOTATE_IGNORE_ALTERNATIVE
241-
ASM_CLAC ::: "memory", "flags");
239+
asm volatile(ASM_CLAC_UNSAFE ::: "memory", "flags");
242240
}
243241

244242
static inline long

tools/objtool/arch/x86/special.c

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@
55
#include <objtool/builtin.h>
66
#include <objtool/warn.h>
77

8-
#define X86_FEATURE_POPCNT (4 * 32 + 23)
9-
#define X86_FEATURE_SMAP (9 * 32 + 20)
10-
11-
void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
8+
void arch_handle_alternative(struct special_alt *alt)
129
{
1310
static struct special_alt *group, *prev;
1411

@@ -32,34 +29,6 @@ void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
3229
} else group = alt;
3330

3431
prev = alt;
35-
36-
switch (feature) {
37-
case X86_FEATURE_SMAP:
38-
/*
39-
* If UACCESS validation is enabled; force that alternative;
40-
* otherwise force it the other way.
41-
*
42-
* What we want to avoid is having both the original and the
43-
* alternative code flow at the same time, in that case we can
44-
* find paths that see the STAC but take the NOP instead of
45-
* CLAC and the other way around.
46-
*/
47-
if (opts.uaccess)
48-
alt->skip_orig = true;
49-
else
50-
alt->skip_alt = true;
51-
break;
52-
case X86_FEATURE_POPCNT:
53-
/*
54-
* It has been requested that we don't validate the !POPCNT
55-
* feature path which is a "very very small percentage of
56-
* machines".
57-
*/
58-
alt->skip_orig = true;
59-
break;
60-
default:
61-
break;
62-
}
6332
}
6433

6534
bool arch_support_alt_relocation(struct special_alt *special_alt,

tools/objtool/check.c

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
struct alternative {
2626
struct alternative *next;
2727
struct instruction *insn;
28-
bool skip_orig;
2928
};
3029

3130
static unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache;
@@ -1696,6 +1695,7 @@ static int handle_group_alt(struct objtool_file *file,
16961695
orig_alt_group->first_insn = orig_insn;
16971696
orig_alt_group->last_insn = last_orig_insn;
16981697
orig_alt_group->nop = NULL;
1698+
orig_alt_group->ignore = orig_insn->ignore_alts;
16991699
} else {
17001700
if (orig_alt_group->last_insn->offset + orig_alt_group->last_insn->len -
17011701
orig_alt_group->first_insn->offset != special_alt->orig_len) {
@@ -1735,7 +1735,6 @@ static int handle_group_alt(struct objtool_file *file,
17351735
nop->type = INSN_NOP;
17361736
nop->sym = orig_insn->sym;
17371737
nop->alt_group = new_alt_group;
1738-
nop->ignore = orig_insn->ignore_alts;
17391738
}
17401739

17411740
if (!special_alt->new_len) {
@@ -1752,7 +1751,6 @@ static int handle_group_alt(struct objtool_file *file,
17521751

17531752
last_new_insn = insn;
17541753

1755-
insn->ignore = orig_insn->ignore_alts;
17561754
insn->sym = orig_insn->sym;
17571755
insn->alt_group = new_alt_group;
17581756

@@ -1799,6 +1797,7 @@ static int handle_group_alt(struct objtool_file *file,
17991797
new_alt_group->first_insn = *new_insn;
18001798
new_alt_group->last_insn = last_new_insn;
18011799
new_alt_group->nop = nop;
1800+
new_alt_group->ignore = (*new_insn)->ignore_alts;
18021801
new_alt_group->cfi = orig_alt_group->cfi;
18031802
return 0;
18041803
}
@@ -1916,8 +1915,6 @@ static int add_special_section_alts(struct objtool_file *file)
19161915
}
19171916

19181917
alt->insn = new_insn;
1919-
alt->skip_orig = special_alt->skip_orig;
1920-
orig_insn->ignore_alts |= special_alt->skip_alt;
19211918
alt->next = orig_insn->alts;
19221919
orig_insn->alts = alt;
19231920

@@ -2295,6 +2292,8 @@ static int read_annotate(struct objtool_file *file,
22952292
static int __annotate_early(struct objtool_file *file, int type, struct instruction *insn)
22962293
{
22972294
switch (type) {
2295+
2296+
/* Must be before add_special_section_alts() */
22982297
case ANNOTYPE_IGNORE_ALTS:
22992298
insn->ignore_alts = true;
23002299
break;
@@ -3488,11 +3487,6 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
34883487
return 1;
34893488
}
34903489

3491-
if (func && insn->ignore) {
3492-
WARN_INSN(insn, "BUG: why am I validating an ignored function?");
3493-
return 1;
3494-
}
3495-
34963490
visited = VISITED_BRANCH << state.uaccess;
34973491
if (insn->visited & VISITED_BRANCH_MASK) {
34983492
if (!insn->hint && !insn_cfi_match(insn, &state.cfi))
@@ -3564,24 +3558,19 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
35643558
if (propagate_alt_cfi(file, insn))
35653559
return 1;
35663560

3567-
if (!insn->ignore_alts && insn->alts) {
3568-
bool skip_orig = false;
3569-
3561+
if (insn->alts) {
35703562
for (alt = insn->alts; alt; alt = alt->next) {
3571-
if (alt->skip_orig)
3572-
skip_orig = true;
3573-
35743563
ret = validate_branch(file, func, alt->insn, state);
35753564
if (ret) {
35763565
BT_INSN(insn, "(alt)");
35773566
return ret;
35783567
}
35793568
}
3580-
3581-
if (skip_orig)
3582-
return 0;
35833569
}
35843570

3571+
if (insn->alt_group && insn->alt_group->ignore)
3572+
return 0;
3573+
35853574
if (handle_insn_ops(insn, next_insn, &state))
35863575
return 1;
35873576

@@ -3768,23 +3757,15 @@ static int validate_unret(struct objtool_file *file, struct instruction *insn)
37683757

37693758
insn->visited |= VISITED_UNRET;
37703759

3771-
if (!insn->ignore_alts && insn->alts) {
3760+
if (insn->alts) {
37723761
struct alternative *alt;
3773-
bool skip_orig = false;
3774-
37753762
for (alt = insn->alts; alt; alt = alt->next) {
3776-
if (alt->skip_orig)
3777-
skip_orig = true;
3778-
37793763
ret = validate_unret(file, alt->insn);
37803764
if (ret) {
37813765
BT_INSN(insn, "(alt)");
37823766
return ret;
37833767
}
37843768
}
3785-
3786-
if (skip_orig)
3787-
return 0;
37883769
}
37893770

37903771
switch (insn->type) {
@@ -3935,7 +3916,7 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio
39353916
struct instruction *prev_insn;
39363917
int i;
39373918

3938-
if (insn->ignore || insn->type == INSN_NOP || insn->type == INSN_TRAP || (func && func->ignore))
3919+
if (insn->type == INSN_NOP || insn->type == INSN_TRAP || (func && func->ignore))
39393920
return true;
39403921

39413922
/*

tools/objtool/include/objtool/check.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ struct alt_group {
3434
* This is shared with the other alt_groups in the same alternative.
3535
*/
3636
struct cfi_state **cfi;
37+
38+
bool ignore;
3739
};
3840

3941
#define INSN_CHUNK_BITS 8
@@ -54,7 +56,6 @@ struct instruction {
5456

5557
u32 idx : INSN_CHUNK_BITS,
5658
dead_end : 1,
57-
ignore : 1,
5859
ignore_alts : 1,
5960
hint : 1,
6061
save : 1,

tools/objtool/include/objtool/special.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ struct special_alt {
1616
struct list_head list;
1717

1818
bool group;
19-
bool skip_orig;
20-
bool skip_alt;
2119
bool jump_or_nop;
2220
u8 key_addend;
2321

@@ -32,7 +30,7 @@ struct special_alt {
3230

3331
int special_get_alts(struct elf *elf, struct list_head *alts);
3432

35-
void arch_handle_alternative(unsigned short feature, struct special_alt *alt);
33+
void arch_handle_alternative(struct special_alt *alt);
3634

3735
bool arch_support_alt_relocation(struct special_alt *special_alt,
3836
struct instruction *insn,

tools/objtool/special.c

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static const struct special_entry entries[] = {
5454
{},
5555
};
5656

57-
void __weak arch_handle_alternative(unsigned short feature, struct special_alt *alt)
57+
void __weak arch_handle_alternative(struct special_alt *alt)
5858
{
5959
}
6060

@@ -92,15 +92,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
9292

9393
reloc_to_sec_off(orig_reloc, &alt->orig_sec, &alt->orig_off);
9494

95-
if (entry->feature) {
96-
unsigned short feature;
97-
98-
feature = bswap_if_needed(elf,
99-
*(unsigned short *)(sec->data->d_buf +
100-
offset +
101-
entry->feature));
102-
arch_handle_alternative(feature, alt);
103-
}
95+
arch_handle_alternative(alt);
10496

10597
if (!entry->group || alt->new_len) {
10698
new_reloc = find_reloc_by_dest(elf, sec, offset + entry->new);

0 commit comments

Comments
 (0)