[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200915081204.9204-2-jthierry@redhat.com>
Date: Tue, 15 Sep 2020 09:12:02 +0100
From: Julien Thierry <jthierry@...hat.com>
To: linux-kernel@...r.kernel.org
Cc: jpoimboe@...hat.com, peterz@...radead.org, mbenes@...e.cz,
raphael.gault@....com, benh@...nel.crashing.org,
Julien Thierry <jthierry@...hat.com>
Subject: [PATCH 1/3] objtool: check: 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 need to explicitly
save the return value on the stack.
Add the necessary checks to verify a function properly sets up the all
the elements of the stack frame.
Signed-off-by: Julien Thierry <jthierry@...hat.com>
---
tools/objtool/arch/x86/include/cfi_regs.h | 4 ++++
tools/objtool/check.c | 17 +++++++++++++----
2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/tools/objtool/arch/x86/include/cfi_regs.h b/tools/objtool/arch/x86/include/cfi_regs.h
index 79bc517efba8..19b75b8b8439 100644
--- a/tools/objtool/arch/x86/include/cfi_regs.h
+++ b/tools/objtool/arch/x86/include/cfi_regs.h
@@ -22,4 +22,8 @@
#define CFI_RA 16
#define CFI_NUM_REGS 17
+#define CFA_SIZE 16
+#define CFA_BP_OFFSET -16
+#define CFA_RA_OFFSET -8
+
#endif /* _OBJTOOL_CFI_REGS_H */
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 500f63b3dcff..7db6761d28c2 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1669,12 +1669,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 cfa_start,
+ int expected_offset)
+{
+ return reg->base == CFI_CFA &&
+ reg->offset == cfa_start + 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 && cfi->cfa.offset >= CFA_SIZE &&
+ check_reg_frame_pos(&cfi->regs[CFI_BP], -cfi->cfa.offset + CFA_SIZE, CFA_BP_OFFSET) &&
+ check_reg_frame_pos(&cfi->regs[CFI_RA], -cfi->cfa.offset + CFA_SIZE, CFA_RA_OFFSET))
return true;
if (cfi->drap && cfi->regs[CFI_BP].base == CFI_BP)
@@ -1803,8 +1811,9 @@ 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(®s[CFI_BP],
+ -cfa->offset + CFA_SIZE,
+ CFA_BP_OFFSET)) {
/* mov %rsp, %rbp */
cfa->base = op->dest.reg;
--
2.21.3
Powered by blists - more mailing lists