Skip to content

Commit

Permalink
Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/tip/tip

Pull objtool fixes from Ingo Molnar:
 "A handful of objtool fixes related to unreachable code, plus a build
  fix for out of tree modules"

* 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  objtool: Enclose contents of unreachable() macro in a block
  objtool: Prevent GCC from merging annotate_unreachable()
  objtool: Improve detection of BUG() and other dead ends
  objtool: Fix CONFIG_STACK_VALIDATION=y warning for out-of-tree modules
  • Loading branch information
torvalds committed Feb 28, 2017
2 parents 74e3f63 + 4e4636c commit e72e58f
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 23 deletions.
24 changes: 12 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,18 @@ mod_sign_cmd = true
endif
export mod_sign_cmd

ifdef CONFIG_STACK_VALIDATION
has_libelf := $(call try-run,\
echo "int main() {}" | $(HOSTCC) -xc -o /dev/null -lelf -,1,0)
ifeq ($(has_libelf),1)
objtool_target := tools/objtool FORCE
else
$(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
SKIP_STACK_VALIDATION := 1
export SKIP_STACK_VALIDATION
endif
endif


ifeq ($(KBUILD_EXTMOD),)
core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
Expand Down Expand Up @@ -1037,18 +1049,6 @@ prepare0: archprepare gcc-plugins
# All the preparing..
prepare: prepare0 prepare-objtool

ifdef CONFIG_STACK_VALIDATION
has_libelf := $(call try-run,\
echo "int main() {}" | $(HOSTCC) -xc -o /dev/null -lelf -,1,0)
ifeq ($(has_libelf),1)
objtool_target := tools/objtool FORCE
else
$(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel")
SKIP_STACK_VALIDATION := 1
export SKIP_STACK_VALIDATION
endif
endif

PHONY += prepare-objtool
prepare-objtool: $(objtool_target)

Expand Down
1 change: 1 addition & 0 deletions arch/x86/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ SECTIONS
/DISCARD/ : {
*(.eh_frame)
*(__func_stack_frame_non_standard)
*(__unreachable)
}
}

Expand Down
14 changes: 13 additions & 1 deletion include/linux/compiler-gcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,17 @@
#endif
#endif

#ifdef CONFIG_STACK_VALIDATION
#define annotate_unreachable() ({ \
asm("%c0:\t\n" \
".pushsection __unreachable, \"a\"\t\n" \
".long %c0b\t\n" \
".popsection\t\n" : : "i" (__LINE__)); \
})
#else
#define annotate_unreachable()
#endif

/*
* Mark a position in code as unreachable. This can be used to
* suppress control flow warnings after asm blocks that transfer
Expand All @@ -206,7 +217,8 @@
* this in the preprocessor, but we can live with this because they're
* unreleased. Really, we need to have autoconf for the kernel.
*/
#define unreachable() __builtin_unreachable()
#define unreachable() \
do { annotate_unreachable(); __builtin_unreachable(); } while (0)

/* Mark a function definition as prohibited from being cloned. */
#define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))
Expand Down
5 changes: 2 additions & 3 deletions tools/objtool/arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@
#define INSN_CALL_DYNAMIC 8
#define INSN_RETURN 9
#define INSN_CONTEXT_SWITCH 10
#define INSN_BUG 11
#define INSN_NOP 12
#define INSN_OTHER 13
#define INSN_NOP 11
#define INSN_OTHER 12
#define INSN_LAST INSN_OTHER

int arch_decode_instruction(struct elf *elf, struct section *sec,
Expand Down
3 changes: 0 additions & 3 deletions tools/objtool/arch/x86/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
op2 == 0x35)
/* sysenter, sysret */
*type = INSN_CONTEXT_SWITCH;
else if (op2 == 0x0b || op2 == 0xb9)
/* ud2 */
*type = INSN_BUG;
else if (op2 == 0x0d || op2 == 0x1f)
/* nopl/nopw */
*type = INSN_NOP;
Expand Down
60 changes: 56 additions & 4 deletions tools/objtool/builtin-check.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct instruction {
unsigned int len, state;
unsigned char type;
unsigned long immediate;
bool alt_group, visited;
bool alt_group, visited, dead_end;
struct symbol *call_dest;
struct instruction *jump_dest;
struct list_head alts;
Expand Down Expand Up @@ -329,6 +329,54 @@ static int decode_instructions(struct objtool_file *file)
return 0;
}

/*
* Find all uses of the unreachable() macro, which are code path dead ends.
*/
static int add_dead_ends(struct objtool_file *file)
{
struct section *sec;
struct rela *rela;
struct instruction *insn;
bool found;

sec = find_section_by_name(file->elf, ".rela__unreachable");
if (!sec)
return 0;

list_for_each_entry(rela, &sec->rela_list, list) {
if (rela->sym->type != STT_SECTION) {
WARN("unexpected relocation symbol type in .rela__unreachable");
return -1;
}
insn = find_insn(file, rela->sym->sec, rela->addend);
if (insn)
insn = list_prev_entry(insn, list);
else if (rela->addend == rela->sym->sec->len) {
found = false;
list_for_each_entry_reverse(insn, &file->insn_list, list) {
if (insn->sec == rela->sym->sec) {
found = true;
break;
}
}

if (!found) {
WARN("can't find unreachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
}
} else {
WARN("can't find unreachable insn at %s+0x%x",
rela->sym->sec->name, rela->addend);
return -1;
}

insn->dead_end = true;
}

return 0;
}

/*
* Warnings shouldn't be reported for ignored functions.
*/
Expand Down Expand Up @@ -843,6 +891,10 @@ static int decode_sections(struct objtool_file *file)
if (ret)
return ret;

ret = add_dead_ends(file);
if (ret)
return ret;

add_ignores(file);

ret = add_jump_destinations(file);
Expand Down Expand Up @@ -1037,13 +1089,13 @@ static int validate_branch(struct objtool_file *file,

return 0;

case INSN_BUG:
return 0;

default:
break;
}

if (insn->dead_end)
return 0;

insn = next_insn_same_sec(file, insn);
if (!insn) {
WARN("%s: unexpected end of section", sec->name);
Expand Down

0 comments on commit e72e58f

Please sign in to comment.