Skip to content

Commit a706bb0

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
objtool: Fix overlapping alternatives
Things like ALTERNATIVE_{2,3}() generate multiple alternatives on the same place, objtool would override the first orig_alt_group with the second (or third), failing to check the CFI among all the different variants. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Acked-by: Josh Poimboeuf <[email protected]> Tested-by: Nathan Chancellor <[email protected]> # build only Tested-by: Thomas Weißschuh <[email protected]> # compile and run Link: https://lore.kernel.org/r/[email protected]
1 parent c6f5dc2 commit a706bb0

File tree

1 file changed

+43
-26
lines changed

1 file changed

+43
-26
lines changed

tools/objtool/check.c

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,36 +1744,49 @@ static int handle_group_alt(struct objtool_file *file,
17441744
struct instruction *orig_insn,
17451745
struct instruction **new_insn)
17461746
{
1747-
struct instruction *last_orig_insn, *last_new_insn = NULL, *insn, *nop = NULL;
1747+
struct instruction *last_new_insn = NULL, *insn, *nop = NULL;
17481748
struct alt_group *orig_alt_group, *new_alt_group;
17491749
unsigned long dest_off;
17501750

1751-
1752-
orig_alt_group = malloc(sizeof(*orig_alt_group));
1751+
orig_alt_group = orig_insn->alt_group;
17531752
if (!orig_alt_group) {
1754-
WARN("malloc failed");
1755-
return -1;
1756-
}
1757-
orig_alt_group->cfi = calloc(special_alt->orig_len,
1758-
sizeof(struct cfi_state *));
1759-
if (!orig_alt_group->cfi) {
1760-
WARN("calloc failed");
1761-
return -1;
1762-
}
1753+
struct instruction *last_orig_insn = NULL;
17631754

1764-
last_orig_insn = NULL;
1765-
insn = orig_insn;
1766-
sec_for_each_insn_from(file, insn) {
1767-
if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
1768-
break;
1755+
orig_alt_group = malloc(sizeof(*orig_alt_group));
1756+
if (!orig_alt_group) {
1757+
WARN("malloc failed");
1758+
return -1;
1759+
}
1760+
orig_alt_group->cfi = calloc(special_alt->orig_len,
1761+
sizeof(struct cfi_state *));
1762+
if (!orig_alt_group->cfi) {
1763+
WARN("calloc failed");
1764+
return -1;
1765+
}
17691766

1770-
insn->alt_group = orig_alt_group;
1771-
last_orig_insn = insn;
1772-
}
1773-
orig_alt_group->orig_group = NULL;
1774-
orig_alt_group->first_insn = orig_insn;
1775-
orig_alt_group->last_insn = last_orig_insn;
1767+
insn = orig_insn;
1768+
sec_for_each_insn_from(file, insn) {
1769+
if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
1770+
break;
17761771

1772+
insn->alt_group = orig_alt_group;
1773+
last_orig_insn = insn;
1774+
}
1775+
orig_alt_group->orig_group = NULL;
1776+
orig_alt_group->first_insn = orig_insn;
1777+
orig_alt_group->last_insn = last_orig_insn;
1778+
} else {
1779+
if (orig_alt_group->last_insn->offset + orig_alt_group->last_insn->len -
1780+
orig_alt_group->first_insn->offset != special_alt->orig_len) {
1781+
WARN_FUNC("weirdly overlapping alternative! %ld != %d",
1782+
orig_insn->sec, orig_insn->offset,
1783+
orig_alt_group->last_insn->offset +
1784+
orig_alt_group->last_insn->len -
1785+
orig_alt_group->first_insn->offset,
1786+
special_alt->orig_len);
1787+
return -1;
1788+
}
1789+
}
17771790

17781791
new_alt_group = malloc(sizeof(*new_alt_group));
17791792
if (!new_alt_group) {
@@ -1848,7 +1861,7 @@ static int handle_group_alt(struct objtool_file *file,
18481861

18491862
dest_off = arch_jump_destination(insn);
18501863
if (dest_off == special_alt->new_off + special_alt->new_len) {
1851-
insn->jump_dest = next_insn_same_sec(file, last_orig_insn);
1864+
insn->jump_dest = next_insn_same_sec(file, orig_alt_group->last_insn);
18521865
if (!insn->jump_dest) {
18531866
WARN_FUNC("can't find alternative jump destination",
18541867
insn->sec, insn->offset);
@@ -3226,8 +3239,12 @@ static int propagate_alt_cfi(struct objtool_file *file, struct instruction *insn
32263239
alt_cfi[group_off] = insn->cfi;
32273240
} else {
32283241
if (cficmp(alt_cfi[group_off], insn->cfi)) {
3229-
WARN_FUNC("stack layout conflict in alternatives",
3230-
insn->sec, insn->offset);
3242+
struct alt_group *orig_group = insn->alt_group->orig_group ?: insn->alt_group;
3243+
struct instruction *orig = orig_group->first_insn;
3244+
char *where = offstr(insn->sec, insn->offset);
3245+
WARN_FUNC("stack layout conflict in alternatives: %s",
3246+
orig->sec, orig->offset, where);
3247+
free(where);
32313248
return -1;
32323249
}
32333250
}

0 commit comments

Comments
 (0)