Skip to content

Commit

Permalink
Merge tag 'objtool_urgent_for_v5.18_rc5' of git://git.kernel.org/pub/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
torvalds committed May 1, 2022
2 parents d4af0c1 + 4abff6d commit b70ed23
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 99 deletions.
87 changes: 52 additions & 35 deletions arch/x86/lib/copy_user_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@
SYM_FUNC_START(copy_user_generic_unrolled)
ASM_STAC
cmpl $8,%edx
jb 20f /* less then 8 bytes, go to byte copy loop */
jb .Lcopy_user_short_string_bytes
ALIGN_DESTINATION
movl %edx,%ecx
andl $63,%edx
shrl $6,%ecx
jz .L_copy_short_string
jz copy_user_short_string
1: movq (%rsi),%r8
2: movq 1*8(%rsi),%r9
3: movq 2*8(%rsi),%r10
Expand All @@ -79,37 +79,11 @@ SYM_FUNC_START(copy_user_generic_unrolled)
leaq 64(%rdi),%rdi
decl %ecx
jnz 1b
.L_copy_short_string:
movl %edx,%ecx
andl $7,%edx
shrl $3,%ecx
jz 20f
18: movq (%rsi),%r8
19: movq %r8,(%rdi)
leaq 8(%rsi),%rsi
leaq 8(%rdi),%rdi
decl %ecx
jnz 18b
20: andl %edx,%edx
jz 23f
movl %edx,%ecx
21: movb (%rsi),%al
22: movb %al,(%rdi)
incq %rsi
incq %rdi
decl %ecx
jnz 21b
23: xor %eax,%eax
ASM_CLAC
RET
jmp copy_user_short_string

30: shll $6,%ecx
addl %ecx,%edx
jmp 60f
40: leal (%rdx,%rcx,8),%edx
jmp 60f
50: movl %ecx,%edx
60: jmp .Lcopy_user_handle_tail /* ecx is zerorest also */
jmp .Lcopy_user_handle_tail

_ASM_EXTABLE_CPY(1b, 30b)
_ASM_EXTABLE_CPY(2b, 30b)
Expand All @@ -127,10 +101,6 @@ SYM_FUNC_START(copy_user_generic_unrolled)
_ASM_EXTABLE_CPY(14b, 30b)
_ASM_EXTABLE_CPY(15b, 30b)
_ASM_EXTABLE_CPY(16b, 30b)
_ASM_EXTABLE_CPY(18b, 40b)
_ASM_EXTABLE_CPY(19b, 40b)
_ASM_EXTABLE_CPY(21b, 50b)
_ASM_EXTABLE_CPY(22b, 50b)
SYM_FUNC_END(copy_user_generic_unrolled)
EXPORT_SYMBOL(copy_user_generic_unrolled)

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

SYM_CODE_END(.Lcopy_user_handle_tail)

/*
* Finish memcpy of less than 64 bytes. #AC should already be set.
*
* Input:
* rdi destination
* rsi source
* rdx count (< 64)
*
* Output:
* eax uncopied bytes or 0 if successful.
*/
SYM_CODE_START_LOCAL(copy_user_short_string)
movl %edx,%ecx
andl $7,%edx
shrl $3,%ecx
jz .Lcopy_user_short_string_bytes
18: movq (%rsi),%r8
19: movq %r8,(%rdi)
leaq 8(%rsi),%rsi
leaq 8(%rdi),%rdi
decl %ecx
jnz 18b
.Lcopy_user_short_string_bytes:
andl %edx,%edx
jz 23f
movl %edx,%ecx
21: movb (%rsi),%al
22: movb %al,(%rdi)
incq %rsi
incq %rdi
decl %ecx
jnz 21b
23: xor %eax,%eax
ASM_CLAC
RET

40: leal (%rdx,%rcx,8),%edx
jmp 60f
50: movl %ecx,%edx /* ecx is zerorest also */
60: jmp .Lcopy_user_handle_tail

_ASM_EXTABLE_CPY(18b, 40b)
_ASM_EXTABLE_CPY(19b, 40b)
_ASM_EXTABLE_CPY(21b, 50b)
_ASM_EXTABLE_CPY(22b, 50b)
SYM_CODE_END(copy_user_short_string)

/*
* copy_user_nocache - Uncached memory copy with exception handling
* This will force destination out of cache for more performance.
Expand Down
81 changes: 44 additions & 37 deletions tools/objtool/check.c
Original file line number Diff line number Diff line change
Expand Up @@ -559,12 +559,12 @@ static int add_dead_ends(struct objtool_file *file)
else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
insn = find_last_insn(file, reloc->sym->sec);
if (!insn) {
WARN("can't find unreachable insn at %s+0x%x",
WARN("can't find unreachable insn at %s+0x%lx",
reloc->sym->sec->name, reloc->addend);
return -1;
}
} else {
WARN("can't find unreachable insn at %s+0x%x",
WARN("can't find unreachable insn at %s+0x%lx",
reloc->sym->sec->name, reloc->addend);
return -1;
}
Expand Down Expand Up @@ -594,12 +594,12 @@ static int add_dead_ends(struct objtool_file *file)
else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
insn = find_last_insn(file, reloc->sym->sec);
if (!insn) {
WARN("can't find reachable insn at %s+0x%x",
WARN("can't find reachable insn at %s+0x%lx",
reloc->sym->sec->name, reloc->addend);
return -1;
}
} else {
WARN("can't find reachable insn at %s+0x%x",
WARN("can't find reachable insn at %s+0x%lx",
reloc->sym->sec->name, reloc->addend);
return -1;
}
Expand Down Expand Up @@ -1271,12 +1271,19 @@ static bool is_first_func_insn(struct objtool_file *file, struct instruction *in
*/
static int add_jump_destinations(struct objtool_file *file)
{
struct instruction *insn;
struct instruction *insn, *jump_dest;
struct reloc *reloc;
struct section *dest_sec;
unsigned long dest_off;

for_each_insn(file, insn) {
if (insn->jump_dest) {
/*
* handle_group_alt() may have previously set
* 'jump_dest' for some alternatives.
*/
continue;
}
if (!is_static_jump(insn))
continue;

Expand All @@ -1291,7 +1298,10 @@ static int add_jump_destinations(struct objtool_file *file)
add_retpoline_call(file, insn);
continue;
} else if (insn->func) {
/* internal or external sibling call (with reloc) */
/*
* External sibling call or internal sibling call with
* STT_FUNC reloc.
*/
add_call_dest(file, insn, reloc->sym, true);
continue;
} else if (reloc->sym->sec->idx) {
Expand All @@ -1303,17 +1313,8 @@ static int add_jump_destinations(struct objtool_file *file)
continue;
}

insn->jump_dest = find_insn(file, dest_sec, dest_off);
if (!insn->jump_dest) {

/*
* This is a special case where an alt instruction
* jumps past the end of the section. These are
* handled later in handle_group_alt().
*/
if (!strcmp(insn->sec->name, ".altinstr_replacement"))
continue;

jump_dest = find_insn(file, dest_sec, dest_off);
if (!jump_dest) {
WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
insn->sec, insn->offset, dest_sec->name,
dest_off);
Expand All @@ -1323,8 +1324,8 @@ static int add_jump_destinations(struct objtool_file *file)
/*
* Cross-function jump.
*/
if (insn->func && insn->jump_dest->func &&
insn->func != insn->jump_dest->func) {
if (insn->func && jump_dest->func &&
insn->func != jump_dest->func) {

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

} else if (!same_function(insn, insn->jump_dest) &&
is_first_func_insn(file, insn->jump_dest)) {
/* internal sibling call (without reloc) */
add_call_dest(file, insn, insn->jump_dest->func, true);
} else if (!same_function(insn, jump_dest) &&
is_first_func_insn(file, jump_dest)) {
/*
* Internal sibling call without reloc or with
* STT_SECTION reloc.
*/
add_call_dest(file, insn, jump_dest->func, true);
continue;
}
}

insn->jump_dest = jump_dest;
}

return 0;
Expand Down Expand Up @@ -1540,13 +1547,13 @@ static int handle_group_alt(struct objtool_file *file,
continue;

dest_off = arch_jump_destination(insn);
if (dest_off == special_alt->new_off + special_alt->new_len)
if (dest_off == special_alt->new_off + special_alt->new_len) {
insn->jump_dest = next_insn_same_sec(file, last_orig_insn);

if (!insn->jump_dest) {
WARN_FUNC("can't find alternative jump destination",
insn->sec, insn->offset);
return -1;
if (!insn->jump_dest) {
WARN_FUNC("can't find alternative jump destination",
insn->sec, insn->offset);
return -1;
}
}
}

Expand Down Expand Up @@ -2245,14 +2252,14 @@ static int decode_sections(struct objtool_file *file)
return ret;

/*
* Must be before add_special_section_alts() as that depends on
* jump_dest being set.
* Must be before add_jump_destinations(), which depends on 'func'
* being set for alternatives, to enable proper sibling call detection.
*/
ret = add_jump_destinations(file);
ret = add_special_section_alts(file);
if (ret)
return ret;

ret = add_special_section_alts(file);
ret = add_jump_destinations(file);
if (ret)
return ret;

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

if (file->c_file && func && insn->func && func != insn->func->pfunc) {
if (func && insn->func && func != insn->func->pfunc) {
WARN("%s() falls through to next function %s()",
func->name, insn->func->name);
return 1;
Expand Down
Loading

0 comments on commit b70ed23

Please sign in to comment.