summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJulien Thierry <jthierry@redhat.com>2020-10-14 08:38:00 +0100
committerJosh Poimboeuf <jpoimboe@redhat.com>2021-01-13 18:13:09 -0600
commitfb084fde0c8106bc86df243411751c3421c07c08 (patch)
tree4fab95754e67178bb0ba365ad92ddc2123cf5842 /tools
parent7c53f6b671f4aba70ff15e1b05148b10d58c2837 (diff)
downloadlinux-fb084fde0c8106bc86df243411751c3421c07c08.tar.gz
linux-fb084fde0c8106bc86df243411751c3421c07c08.tar.bz2
linux-fb084fde0c8106bc86df243411751c3421c07c08.zip
objtool: Fully validate the stack frame
A valid stack frame should contain both the return address and the previous frame pointer value. On x86, the return value is placed on the stack by the calling instructions. On other architectures, the callee needs to explicitly save the return address on the stack. Add the necessary checks to verify a function properly sets up all the elements of the stack frame. Signed-off-by: Julien Thierry <jthierry@redhat.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/objtool/check.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 5f8d3eed78a1..88210b0856f7 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1733,12 +1733,20 @@ static bool has_modified_stack_frame(struct instruction *insn, struct insn_state
return false;
}
+static bool check_reg_frame_pos(const struct cfi_reg *reg,
+ int expected_offset)
+{
+ return reg->base == CFI_CFA &&
+ reg->offset == expected_offset;
+}
+
static bool has_valid_stack_frame(struct insn_state *state)
{
struct cfi_state *cfi = &state->cfi;
- if (cfi->cfa.base == CFI_BP && cfi->regs[CFI_BP].base == CFI_CFA &&
- cfi->regs[CFI_BP].offset == -16)
+ if (cfi->cfa.base == CFI_BP &&
+ check_reg_frame_pos(&cfi->regs[CFI_BP], -cfi->cfa.offset) &&
+ check_reg_frame_pos(&cfi->regs[CFI_RA], -cfi->cfa.offset + 8))
return true;
if (cfi->drap && cfi->regs[CFI_BP].base == CFI_BP)
@@ -1867,8 +1875,7 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
case OP_SRC_REG:
if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP &&
cfa->base == CFI_SP &&
- regs[CFI_BP].base == CFI_CFA &&
- regs[CFI_BP].offset == -cfa->offset) {
+ check_reg_frame_pos(&regs[CFI_BP], -cfa->offset)) {
/* mov %rsp, %rbp */
cfa->base = op->dest.reg;