Skip to content

Commit b70ed23

Browse files
committed
Merge tag 'objtool_urgent_for_v5.18_rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull objtool fixes from Borislav Petkov: "A bunch of objtool fixes to improve unwinding, sibling call detection, fallthrough detection and relocation handling of weak symbols when the toolchain strips section symbols" * tag 'objtool_urgent_for_v5.18_rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: objtool: Fix code relocs vs weak symbols objtool: Fix type of reloc::addend objtool: Fix function fallthrough detection for vmlinux objtool: Fix sibling call detection in alternatives objtool: Don't set 'jump_dest' for sibling calls x86/uaccess: Don't jump between functions
2 parents d4af0c1 + 4abff6d commit b70ed23

File tree

6 files changed

+265
-99
lines changed

6 files changed

+265
-99
lines changed

arch/x86/lib/copy_user_64.S

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@
5353
SYM_FUNC_START(copy_user_generic_unrolled)
5454
ASM_STAC
5555
cmpl $8,%edx
56-
jb 20f /* less then 8 bytes, go to byte copy loop */
56+
jb .Lcopy_user_short_string_bytes
5757
ALIGN_DESTINATION
5858
movl %edx,%ecx
5959
andl $63,%edx
6060
shrl $6,%ecx
61-
jz .L_copy_short_string
61+
jz copy_user_short_string
6262
1: movq (%rsi),%r8
6363
2: movq 1*8(%rsi),%r9
6464
3: movq 2*8(%rsi),%r10
@@ -79,37 +79,11 @@ SYM_FUNC_START(copy_user_generic_unrolled)
7979
leaq 64(%rdi),%rdi
8080
decl %ecx
8181
jnz 1b
82-
.L_copy_short_string:
83-
movl %edx,%ecx
84-
andl $7,%edx
85-
shrl $3,%ecx
86-
jz 20f
87-
18: movq (%rsi),%r8
88-
19: movq %r8,(%rdi)
89-
leaq 8(%rsi),%rsi
90-
leaq 8(%rdi),%rdi
91-
decl %ecx
92-
jnz 18b
93-
20: andl %edx,%edx
94-
jz 23f
95-
movl %edx,%ecx
96-
21: movb (%rsi),%al
97-
22: movb %al,(%rdi)
98-
incq %rsi
99-
incq %rdi
100-
decl %ecx
101-
jnz 21b
102-
23: xor %eax,%eax
103-
ASM_CLAC
104-
RET
82+
jmp copy_user_short_string
10583

10684
30: shll $6,%ecx
10785
addl %ecx,%edx
108-
jmp 60f
109-
40: leal (%rdx,%rcx,8),%edx
110-
jmp 60f
111-
50: movl %ecx,%edx
112-
60: jmp .Lcopy_user_handle_tail /* ecx is zerorest also */
86+
jmp .Lcopy_user_handle_tail
11387

11488
_ASM_EXTABLE_CPY(1b, 30b)
11589
_ASM_EXTABLE_CPY(2b, 30b)
@@ -127,10 +101,6 @@ SYM_FUNC_START(copy_user_generic_unrolled)
127101
_ASM_EXTABLE_CPY(14b, 30b)
128102
_ASM_EXTABLE_CPY(15b, 30b)
129103
_ASM_EXTABLE_CPY(16b, 30b)
130-
_ASM_EXTABLE_CPY(18b, 40b)
131-
_ASM_EXTABLE_CPY(19b, 40b)
132-
_ASM_EXTABLE_CPY(21b, 50b)
133-
_ASM_EXTABLE_CPY(22b, 50b)
134104
SYM_FUNC_END(copy_user_generic_unrolled)
135105
EXPORT_SYMBOL(copy_user_generic_unrolled)
136106

@@ -191,7 +161,7 @@ EXPORT_SYMBOL(copy_user_generic_string)
191161
SYM_FUNC_START(copy_user_enhanced_fast_string)
192162
ASM_STAC
193163
/* CPUs without FSRM should avoid rep movsb for short copies */
194-
ALTERNATIVE "cmpl $64, %edx; jb .L_copy_short_string", "", X86_FEATURE_FSRM
164+
ALTERNATIVE "cmpl $64, %edx; jb copy_user_short_string", "", X86_FEATURE_FSRM
195165
movl %edx,%ecx
196166
1: rep movsb
197167
xorl %eax,%eax
@@ -243,6 +213,53 @@ SYM_CODE_START_LOCAL(.Lcopy_user_handle_tail)
243213

244214
SYM_CODE_END(.Lcopy_user_handle_tail)
245215

216+
/*
217+
* Finish memcpy of less than 64 bytes. #AC should already be set.
218+
*
219+
* Input:
220+
* rdi destination
221+
* rsi source
222+
* rdx count (< 64)
223+
*
224+
* Output:
225+
* eax uncopied bytes or 0 if successful.
226+
*/
227+
SYM_CODE_START_LOCAL(copy_user_short_string)
228+
movl %edx,%ecx
229+
andl $7,%edx
230+
shrl $3,%ecx
231+
jz .Lcopy_user_short_string_bytes
232+
18: movq (%rsi),%r8
233+
19: movq %r8,(%rdi)
234+
leaq 8(%rsi),%rsi
235+
leaq 8(%rdi),%rdi
236+
decl %ecx
237+
jnz 18b
238+
.Lcopy_user_short_string_bytes:
239+
andl %edx,%edx
240+
jz 23f
241+
movl %edx,%ecx
242+
21: movb (%rsi),%al
243+
22: movb %al,(%rdi)
244+
incq %rsi
245+
incq %rdi
246+
decl %ecx
247+
jnz 21b
248+
23: xor %eax,%eax
249+
ASM_CLAC
250+
RET
251+
252+
40: leal (%rdx,%rcx,8),%edx
253+
jmp 60f
254+
50: movl %ecx,%edx /* ecx is zerorest also */
255+
60: jmp .Lcopy_user_handle_tail
256+
257+
_ASM_EXTABLE_CPY(18b, 40b)
258+
_ASM_EXTABLE_CPY(19b, 40b)
259+
_ASM_EXTABLE_CPY(21b, 50b)
260+
_ASM_EXTABLE_CPY(22b, 50b)
261+
SYM_CODE_END(copy_user_short_string)
262+
246263
/*
247264
* copy_user_nocache - Uncached memory copy with exception handling
248265
* This will force destination out of cache for more performance.

tools/objtool/check.c

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -559,12 +559,12 @@ static int add_dead_ends(struct objtool_file *file)
559559
else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
560560
insn = find_last_insn(file, reloc->sym->sec);
561561
if (!insn) {
562-
WARN("can't find unreachable insn at %s+0x%x",
562+
WARN("can't find unreachable insn at %s+0x%lx",
563563
reloc->sym->sec->name, reloc->addend);
564564
return -1;
565565
}
566566
} else {
567-
WARN("can't find unreachable insn at %s+0x%x",
567+
WARN("can't find unreachable insn at %s+0x%lx",
568568
reloc->sym->sec->name, reloc->addend);
569569
return -1;
570570
}
@@ -594,12 +594,12 @@ static int add_dead_ends(struct objtool_file *file)
594594
else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
595595
insn = find_last_insn(file, reloc->sym->sec);
596596
if (!insn) {
597-
WARN("can't find reachable insn at %s+0x%x",
597+
WARN("can't find reachable insn at %s+0x%lx",
598598
reloc->sym->sec->name, reloc->addend);
599599
return -1;
600600
}
601601
} else {
602-
WARN("can't find reachable insn at %s+0x%x",
602+
WARN("can't find reachable insn at %s+0x%lx",
603603
reloc->sym->sec->name, reloc->addend);
604604
return -1;
605605
}
@@ -1271,12 +1271,19 @@ static bool is_first_func_insn(struct objtool_file *file, struct instruction *in
12711271
*/
12721272
static int add_jump_destinations(struct objtool_file *file)
12731273
{
1274-
struct instruction *insn;
1274+
struct instruction *insn, *jump_dest;
12751275
struct reloc *reloc;
12761276
struct section *dest_sec;
12771277
unsigned long dest_off;
12781278

12791279
for_each_insn(file, insn) {
1280+
if (insn->jump_dest) {
1281+
/*
1282+
* handle_group_alt() may have previously set
1283+
* 'jump_dest' for some alternatives.
1284+
*/
1285+
continue;
1286+
}
12801287
if (!is_static_jump(insn))
12811288
continue;
12821289

@@ -1291,7 +1298,10 @@ static int add_jump_destinations(struct objtool_file *file)
12911298
add_retpoline_call(file, insn);
12921299
continue;
12931300
} else if (insn->func) {
1294-
/* internal or external sibling call (with reloc) */
1301+
/*
1302+
* External sibling call or internal sibling call with
1303+
* STT_FUNC reloc.
1304+
*/
12951305
add_call_dest(file, insn, reloc->sym, true);
12961306
continue;
12971307
} else if (reloc->sym->sec->idx) {
@@ -1303,17 +1313,8 @@ static int add_jump_destinations(struct objtool_file *file)
13031313
continue;
13041314
}
13051315

1306-
insn->jump_dest = find_insn(file, dest_sec, dest_off);
1307-
if (!insn->jump_dest) {
1308-
1309-
/*
1310-
* This is a special case where an alt instruction
1311-
* jumps past the end of the section. These are
1312-
* handled later in handle_group_alt().
1313-
*/
1314-
if (!strcmp(insn->sec->name, ".altinstr_replacement"))
1315-
continue;
1316-
1316+
jump_dest = find_insn(file, dest_sec, dest_off);
1317+
if (!jump_dest) {
13171318
WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
13181319
insn->sec, insn->offset, dest_sec->name,
13191320
dest_off);
@@ -1323,8 +1324,8 @@ static int add_jump_destinations(struct objtool_file *file)
13231324
/*
13241325
* Cross-function jump.
13251326
*/
1326-
if (insn->func && insn->jump_dest->func &&
1327-
insn->func != insn->jump_dest->func) {
1327+
if (insn->func && jump_dest->func &&
1328+
insn->func != jump_dest->func) {
13281329

13291330
/*
13301331
* For GCC 8+, create parent/child links for any cold
@@ -1342,16 +1343,22 @@ static int add_jump_destinations(struct objtool_file *file)
13421343
* subfunction is through a jump table.
13431344
*/
13441345
if (!strstr(insn->func->name, ".cold") &&
1345-
strstr(insn->jump_dest->func->name, ".cold")) {
1346-
insn->func->cfunc = insn->jump_dest->func;
1347-
insn->jump_dest->func->pfunc = insn->func;
1346+
strstr(jump_dest->func->name, ".cold")) {
1347+
insn->func->cfunc = jump_dest->func;
1348+
jump_dest->func->pfunc = insn->func;
13481349

1349-
} else if (!same_function(insn, insn->jump_dest) &&
1350-
is_first_func_insn(file, insn->jump_dest)) {
1351-
/* internal sibling call (without reloc) */
1352-
add_call_dest(file, insn, insn->jump_dest->func, true);
1350+
} else if (!same_function(insn, jump_dest) &&
1351+
is_first_func_insn(file, jump_dest)) {
1352+
/*
1353+
* Internal sibling call without reloc or with
1354+
* STT_SECTION reloc.
1355+
*/
1356+
add_call_dest(file, insn, jump_dest->func, true);
1357+
continue;
13531358
}
13541359
}
1360+
1361+
insn->jump_dest = jump_dest;
13551362
}
13561363

13571364
return 0;
@@ -1540,13 +1547,13 @@ static int handle_group_alt(struct objtool_file *file,
15401547
continue;
15411548

15421549
dest_off = arch_jump_destination(insn);
1543-
if (dest_off == special_alt->new_off + special_alt->new_len)
1550+
if (dest_off == special_alt->new_off + special_alt->new_len) {
15441551
insn->jump_dest = next_insn_same_sec(file, last_orig_insn);
1545-
1546-
if (!insn->jump_dest) {
1547-
WARN_FUNC("can't find alternative jump destination",
1548-
insn->sec, insn->offset);
1549-
return -1;
1552+
if (!insn->jump_dest) {
1553+
WARN_FUNC("can't find alternative jump destination",
1554+
insn->sec, insn->offset);
1555+
return -1;
1556+
}
15501557
}
15511558
}
15521559

@@ -2245,14 +2252,14 @@ static int decode_sections(struct objtool_file *file)
22452252
return ret;
22462253

22472254
/*
2248-
* Must be before add_special_section_alts() as that depends on
2249-
* jump_dest being set.
2255+
* Must be before add_jump_destinations(), which depends on 'func'
2256+
* being set for alternatives, to enable proper sibling call detection.
22502257
*/
2251-
ret = add_jump_destinations(file);
2258+
ret = add_special_section_alts(file);
22522259
if (ret)
22532260
return ret;
22542261

2255-
ret = add_special_section_alts(file);
2262+
ret = add_jump_destinations(file);
22562263
if (ret)
22572264
return ret;
22582265

@@ -3303,7 +3310,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
33033310
while (1) {
33043311
next_insn = next_insn_to_validate(file, insn);
33053312

3306-
if (file->c_file && func && insn->func && func != insn->func->pfunc) {
3313+
if (func && insn->func && func != insn->func->pfunc) {
33073314
WARN("%s() falls through to next function %s()",
33083315
func->name, insn->func->name);
33093316
return 1;

0 commit comments

Comments
 (0)