All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] objtool: Extend CFA updating/checking
@ 2020-09-15  8:12 Julien Thierry
  2020-09-15  8:12 ` [PATCH 1/3] objtool: check: Fully validate the stack frame Julien Thierry
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Julien Thierry @ 2020-09-15  8:12 UTC (permalink / raw)
  To: linux-kernel
  Cc: jpoimboe, peterz, mbenes, raphael.gault, benh, Julien Thierry

Hi,

The following patches are the result of limitation found on the CFA
management code when trying to validate arm64 frames. I tried to keep
things simple and not contradict current CFA management logic nor
introduce too many corner cases.

The patches apply on top of the cleanup series[1] I sent previously.

[1] https://lkml.org/lkml/2020/9/15/199

Thanks,

Julien

-->

Julien Thierry (3):
  objtool: check: Fully validate the stack frame
  objtool: check: Support addition to set CFA base
  objtool: check: Make SP memory operation match PUSH/POP semantics

 tools/objtool/arch/x86/include/cfi_regs.h |  4 ++
 tools/objtool/check.c                     | 47 +++++++++++++++++++++--
 2 files changed, 47 insertions(+), 4 deletions(-)

--
2.21.3


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/3] objtool: check: Fully validate the stack frame
  2020-09-15  8:12 [PATCH 0/3] objtool: Extend CFA updating/checking Julien Thierry
@ 2020-09-15  8:12 ` Julien Thierry
  2020-09-18 20:56   ` Josh Poimboeuf
  2020-09-15  8:12 ` [PATCH 2/3] objtool: check: Support addition to set CFA base Julien Thierry
  2020-09-15  8:12 ` [PATCH 3/3] objtool: check: Make SP memory operation match PUSH/POP semantics Julien Thierry
  2 siblings, 1 reply; 11+ messages in thread
From: Julien Thierry @ 2020-09-15  8:12 UTC (permalink / raw)
  To: linux-kernel
  Cc: jpoimboe, peterz, mbenes, raphael.gault, benh, Julien Thierry

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@redhat.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(&regs[CFI_BP],
+						-cfa->offset + CFA_SIZE,
+						CFA_BP_OFFSET)) {
 
 				/* mov %rsp, %rbp */
 				cfa->base = op->dest.reg;
-- 
2.21.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/3] objtool: check: Support addition to set CFA base
  2020-09-15  8:12 [PATCH 0/3] objtool: Extend CFA updating/checking Julien Thierry
  2020-09-15  8:12 ` [PATCH 1/3] objtool: check: Fully validate the stack frame Julien Thierry
@ 2020-09-15  8:12 ` Julien Thierry
  2020-09-18 21:09   ` Josh Poimboeuf
  2020-09-15  8:12 ` [PATCH 3/3] objtool: check: Make SP memory operation match PUSH/POP semantics Julien Thierry
  2 siblings, 1 reply; 11+ messages in thread
From: Julien Thierry @ 2020-09-15  8:12 UTC (permalink / raw)
  To: linux-kernel
  Cc: jpoimboe, peterz, mbenes, raphael.gault, benh, Julien Thierry

Instead of "mov SP, BP", a compiler could simply set BP
to SP + constant. Handle changing the CFA base in such cases.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 7db6761d28c2..f45991c2db41 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1898,6 +1898,19 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
 				break;
 			}
 
+			if (!cfi->drap && op->src.reg == CFI_SP &&
+			    op->dest.reg == CFI_BP && cfa->base == CFI_SP &&
+			    check_reg_frame_pos(&regs[CFI_BP],
+						-cfa->offset + op->src.offset + CFA_SIZE,
+						CFA_BP_OFFSET)) {
+
+				/* lea disp(%rsp), %rbp */
+				cfa->base = CFI_BP;
+				cfa->offset -= op->src.offset;
+				cfi->bp_scratch = false;
+				break;
+			}
+
 			if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
 
 				/* drap: lea disp(%rsp), %drap */
-- 
2.21.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/3] objtool: check: Make SP memory operation match PUSH/POP semantics
  2020-09-15  8:12 [PATCH 0/3] objtool: Extend CFA updating/checking Julien Thierry
  2020-09-15  8:12 ` [PATCH 1/3] objtool: check: Fully validate the stack frame Julien Thierry
  2020-09-15  8:12 ` [PATCH 2/3] objtool: check: Support addition to set CFA base Julien Thierry
@ 2020-09-15  8:12 ` Julien Thierry
  2020-09-18 21:43   ` Josh Poimboeuf
  2 siblings, 1 reply; 11+ messages in thread
From: Julien Thierry @ 2020-09-15  8:12 UTC (permalink / raw)
  To: linux-kernel
  Cc: jpoimboe, peterz, mbenes, raphael.gault, benh, Julien Thierry

Architectures without PUSH/POP instructions will always access the stack
though memory operations (SRC/DEST_INDIRECT). Make those operations have
the same effect on the CFA as PUSH/POP, with no stack pointer
modification.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index f45991c2db41..7ff87fa3caec 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2005,6 +2005,13 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
 			break;
 
 		case OP_SRC_REG_INDIRECT:
+			if (!cfi->drap && op->dest.reg == cfa->base) {
+
+				/* mov disp(%rsp), %rbp */
+				cfa->base = CFI_SP;
+				cfa->offset = cfi->stack_size;
+			}
+
 			if (cfi->drap && op->src.reg == CFI_BP &&
 			    op->src.offset == cfi->drap_offset) {
 
@@ -2026,6 +2033,11 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
 				/* mov disp(%rbp), %reg */
 				/* mov disp(%rsp), %reg */
 				restore_reg(cfi, op->dest.reg);
+			} else if (op->src.reg == CFI_SP &&
+				   op->src.offset == regs[op->dest.reg].offset + cfi->stack_size) {
+
+				/* mov disp(%rsp), %reg */
+				restore_reg(cfi, op->dest.reg);
 			}
 
 			break;
@@ -2103,6 +2115,11 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
 			/* mov reg, disp(%rsp) */
 			save_reg(cfi, op->src.reg, CFI_CFA,
 				 op->dest.offset - cfi->cfa.offset);
+		} else if (op->dest.reg == CFI_SP) {
+
+			/* mov reg, disp(%rsp) */
+			save_reg(cfi, op->src.reg, CFI_CFA,
+				 op->dest.offset - cfi->stack_size);
 		}
 
 		break;
-- 
2.21.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/3] objtool: check: Fully validate the stack frame
  2020-09-15  8:12 ` [PATCH 1/3] objtool: check: Fully validate the stack frame Julien Thierry
@ 2020-09-18 20:56   ` Josh Poimboeuf
  2020-09-21 10:31     ` Julien Thierry
  0 siblings, 1 reply; 11+ messages in thread
From: Josh Poimboeuf @ 2020-09-18 20:56 UTC (permalink / raw)
  To: Julien Thierry; +Cc: linux-kernel, peterz, mbenes, raphael.gault, benh

On Tue, Sep 15, 2020 at 09:12:02AM +0100, Julien Thierry wrote:
> 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.

s/return value/return address/g

> 
> Add the necessary checks to verify a function properly sets up the all

s/the all/all the/

> the elements of the stack frame.
> 
> Signed-off-by: Julien Thierry <jthierry@redhat.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

If I remember correctly, CFA (stolen from DWARF) is "Caller Frame
Address".  It's the stack address of the caller, before the call.

I get the feeling CFA_SIZE is the wrong name, because CFA is an address,
and its size isn't 16 bytes.  But I'm not quite sure what this is
supposed to represent.  Is it supposed to be the size of the frame
pointer + return address?  Isn't that always going to be 16 bytes for
both arches?

> +#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 &&

Why '>=' rather than '=='?

> +	    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))

Isn't '-cfi->cfa.offset + CFA_SIZE' always going to be zero?

-- 
Josh


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/3] objtool: check: Support addition to set CFA base
  2020-09-15  8:12 ` [PATCH 2/3] objtool: check: Support addition to set CFA base Julien Thierry
@ 2020-09-18 21:09   ` Josh Poimboeuf
  0 siblings, 0 replies; 11+ messages in thread
From: Josh Poimboeuf @ 2020-09-18 21:09 UTC (permalink / raw)
  To: Julien Thierry; +Cc: linux-kernel, peterz, mbenes, raphael.gault, benh

On Tue, Sep 15, 2020 at 09:12:03AM +0100, Julien Thierry wrote:
> Instead of "mov SP, BP", a compiler could simply set BP
> to SP + constant. Handle changing the CFA base in such cases.

Rather than what a compiler _could_ do, it would be good to be specific
about when this can happen (presumably arm64).

-- 
Josh


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3] objtool: check: Make SP memory operation match PUSH/POP semantics
  2020-09-15  8:12 ` [PATCH 3/3] objtool: check: Make SP memory operation match PUSH/POP semantics Julien Thierry
@ 2020-09-18 21:43   ` Josh Poimboeuf
  2020-09-21 10:31     ` Julien Thierry
  0 siblings, 1 reply; 11+ messages in thread
From: Josh Poimboeuf @ 2020-09-18 21:43 UTC (permalink / raw)
  To: Julien Thierry; +Cc: linux-kernel, peterz, mbenes, raphael.gault, benh

On Tue, Sep 15, 2020 at 09:12:04AM +0100, Julien Thierry wrote:
> Architectures without PUSH/POP instructions will always access the stack
> though memory operations (SRC/DEST_INDIRECT). Make those operations have
> the same effect on the CFA as PUSH/POP, with no stack pointer
> modification.
> 
> Signed-off-by: Julien Thierry <jthierry@redhat.com>
> ---
>  tools/objtool/check.c | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
> 
> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index f45991c2db41..7ff87fa3caec 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -2005,6 +2005,13 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
>  			break;
>  
>  		case OP_SRC_REG_INDIRECT:
> +			if (!cfi->drap && op->dest.reg == cfa->base) {

&& op->dest.reg == CFI_BP ?

> +
> +				/* mov disp(%rsp), %rbp */
> +				cfa->base = CFI_SP;
> +				cfa->offset = cfi->stack_size;
> +			}
> +
>  			if (cfi->drap && op->src.reg == CFI_BP &&
>  			    op->src.offset == cfi->drap_offset) {
>  
> @@ -2026,6 +2033,11 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
>  				/* mov disp(%rbp), %reg */
>  				/* mov disp(%rsp), %reg */
>  				restore_reg(cfi, op->dest.reg);
> +			} else if (op->src.reg == CFI_SP &&

An empty line above the else would help readability.

> +				   op->src.offset == regs[op->dest.reg].offset + cfi->stack_size) {
> +
> +				/* mov disp(%rsp), %reg */
> +				restore_reg(cfi, op->dest.reg);

>  			}
>  
>  			break;
> @@ -2103,6 +2115,11 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
>  			/* mov reg, disp(%rsp) */
>  			save_reg(cfi, op->src.reg, CFI_CFA,
>  				 op->dest.offset - cfi->cfa.offset);
> +		} else if (op->dest.reg == CFI_SP) {

Same here.

> +
> +			/* mov reg, disp(%rsp) */
> +			save_reg(cfi, op->src.reg, CFI_CFA,
> +				 op->dest.offset - cfi->stack_size);
>  		}
>  
>  		break;
> -- 
> 2.21.3
> 

-- 
Josh


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/3] objtool: check: Fully validate the stack frame
  2020-09-18 20:56   ` Josh Poimboeuf
@ 2020-09-21 10:31     ` Julien Thierry
  2020-09-21 15:03       ` Josh Poimboeuf
  0 siblings, 1 reply; 11+ messages in thread
From: Julien Thierry @ 2020-09-21 10:31 UTC (permalink / raw)
  To: Josh Poimboeuf; +Cc: linux-kernel, peterz, mbenes, raphael.gault, benh



On 9/18/20 9:56 PM, Josh Poimboeuf wrote:
> On Tue, Sep 15, 2020 at 09:12:02AM +0100, Julien Thierry wrote:
>> 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.
> 
> s/return value/return address/g
> 
>>
>> Add the necessary checks to verify a function properly sets up the all
> 
> s/the all/all the/
> 
>> the elements of the stack frame.
>>
>> Signed-off-by: Julien Thierry <jthierry@redhat.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
> 
> If I remember correctly, CFA (stolen from DWARF) is "Caller Frame
> Address".  It's the stack address of the caller, before the call.
> 

Ok, so maybe I'm mixing Call Frame and Stack Frame (frame pointer + 
return address).

> I get the feeling CFA_SIZE is the wrong name, because CFA is an address,
> and its size isn't 16 bytes.  But I'm not quite sure what this is
> supposed to represent.  Is it supposed to be the size of the frame
> pointer + return address?  Isn't that always going to be 16 bytes for
> both arches?
> 

For arm64 and x86_64 it is. Maybe it is a bit early to consider it might 
differ for other arches (e.g. 32bit arches?).

>> +#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 &&
> 
> Why '>=' rather than '=='?
> 

Because on arm64 the stack frame is not necessarily the first thing put 
on the stack by the callee. The callee is free to create the stack frame 
where it wants (on its part of the stack of course) as long as it 
appropriately sets the frame pointer before making a call.

You could have something like:

+------------+
|            |
|            |
+------------+----> f1() called
|            |
| some callee|
| saved regs |
|            |
+------------+
|     RA     |
+------------+
|     BP/FP  |
+------------+----> Set new BP/FP value


>> +	    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))
> 
> Isn't '-cfi->cfa.offset + CFA_SIZE' always going to be zero?
> 

For x86 yes, for arm64 it cfa.offset can be > 16.

-- 
Julien Thierry


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3] objtool: check: Make SP memory operation match PUSH/POP semantics
  2020-09-18 21:43   ` Josh Poimboeuf
@ 2020-09-21 10:31     ` Julien Thierry
  2020-09-21 15:12       ` Josh Poimboeuf
  0 siblings, 1 reply; 11+ messages in thread
From: Julien Thierry @ 2020-09-21 10:31 UTC (permalink / raw)
  To: Josh Poimboeuf; +Cc: linux-kernel, peterz, mbenes, raphael.gault, benh



On 9/18/20 10:43 PM, Josh Poimboeuf wrote:
> On Tue, Sep 15, 2020 at 09:12:04AM +0100, Julien Thierry wrote:
>> Architectures without PUSH/POP instructions will always access the stack
>> though memory operations (SRC/DEST_INDIRECT). Make those operations have
>> the same effect on the CFA as PUSH/POP, with no stack pointer
>> modification.
>>
>> Signed-off-by: Julien Thierry <jthierry@redhat.com>
>> ---
>>   tools/objtool/check.c | 17 +++++++++++++++++
>>   1 file changed, 17 insertions(+)
>>
>> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
>> index f45991c2db41..7ff87fa3caec 100644
>> --- a/tools/objtool/check.c
>> +++ b/tools/objtool/check.c
>> @@ -2005,6 +2005,13 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
>>   			break;
>>   
>>   		case OP_SRC_REG_INDIRECT:
>> +			if (!cfi->drap && op->dest.reg == cfa->base) {
> 
> && op->dest.reg == CFI_BP ?
> 

Does it matter? My unstandig was that the register used to point to the 
CFA is getting overwritten, so we need to fallback to something known 
which is the offset from the stack pointer.

Was that not the case?

>> +
>> +				/* mov disp(%rsp), %rbp */
>> +				cfa->base = CFI_SP;
>> +				cfa->offset = cfi->stack_size;
>> +			}
>> +
>>   			if (cfi->drap && op->src.reg == CFI_BP &&
>>   			    op->src.offset == cfi->drap_offset) {
>>   
>> @@ -2026,6 +2033,11 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
>>   				/* mov disp(%rbp), %reg */
>>   				/* mov disp(%rsp), %reg */
>>   				restore_reg(cfi, op->dest.reg);
>> +			} else if (op->src.reg == CFI_SP &&
> 
> An empty line above the else would help readability.
> 
>> +				   op->src.offset == regs[op->dest.reg].offset + cfi->stack_size) {
>> +
>> +				/* mov disp(%rsp), %reg */
>> +				restore_reg(cfi, op->dest.reg);
> 
>>   			}
>>   
>>   			break;
>> @@ -2103,6 +2115,11 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
>>   			/* mov reg, disp(%rsp) */
>>   			save_reg(cfi, op->src.reg, CFI_CFA,
>>   				 op->dest.offset - cfi->cfa.offset);
>> +		} else if (op->dest.reg == CFI_SP) {
> 
> Same here.
> 

I'll add those.

>> +
>> +			/* mov reg, disp(%rsp) */
>> +			save_reg(cfi, op->src.reg, CFI_CFA,
>> +				 op->dest.offset - cfi->stack_size);
>>   		}
>>   
>>   		break;
>> -- 
>> 2.21.3
>>
> 

-- 
Julien Thierry


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/3] objtool: check: Fully validate the stack frame
  2020-09-21 10:31     ` Julien Thierry
@ 2020-09-21 15:03       ` Josh Poimboeuf
  0 siblings, 0 replies; 11+ messages in thread
From: Josh Poimboeuf @ 2020-09-21 15:03 UTC (permalink / raw)
  To: Julien Thierry; +Cc: linux-kernel, peterz, mbenes, raphael.gault, benh

On Mon, Sep 21, 2020 at 11:31:23AM +0100, Julien Thierry wrote:
> > > +++ 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
> > 
> > If I remember correctly, CFA (stolen from DWARF) is "Caller Frame
> > Address".  It's the stack address of the caller, before the call.
> > 
> 
> Ok, so maybe I'm mixing Call Frame and Stack Frame (frame pointer + return
> address).
> 
> > I get the feeling CFA_SIZE is the wrong name, because CFA is an address,
> > and its size isn't 16 bytes.  But I'm not quite sure what this is
> > supposed to represent.  Is it supposed to be the size of the frame
> > pointer + return address?  Isn't that always going to be 16 bytes for
> > both arches?
> > 
> 
> For arm64 and x86_64 it is. Maybe it is a bit early to consider it might
> differ for other arches (e.g. 32bit arches?).

I'd rather not consider other arches yet.  Even in the 32-bit case it
wouldn't necessarily have to be an arch-specific value since it would
presumably be 'size(long) * 2'.

> 
> > >   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 &&
> > 
> > Why '>=' rather than '=='?
> > 
> 
> Because on arm64 the stack frame is not necessarily the first thing put on
> the stack by the callee. The callee is free to create the stack frame where
> it wants (on its part of the stack of course) as long as it appropriately
> sets the frame pointer before making a call.
> 
> You could have something like:
> 
> +------------+
> |            |
> |            |
> +------------+----> f1() called
> |            |
> | some callee|
> | saved regs |
> |            |
> +------------+
> |     RA     |
> +------------+
> |     BP/FP  |
> +------------+----> Set new BP/FP value

I see, thanks.

-- 
Josh


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3] objtool: check: Make SP memory operation match PUSH/POP semantics
  2020-09-21 10:31     ` Julien Thierry
@ 2020-09-21 15:12       ` Josh Poimboeuf
  0 siblings, 0 replies; 11+ messages in thread
From: Josh Poimboeuf @ 2020-09-21 15:12 UTC (permalink / raw)
  To: Julien Thierry; +Cc: linux-kernel, peterz, mbenes, raphael.gault, benh

On Mon, Sep 21, 2020 at 11:31:28AM +0100, Julien Thierry wrote:
> > > diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> > > index f45991c2db41..7ff87fa3caec 100644
> > > --- a/tools/objtool/check.c
> > > +++ b/tools/objtool/check.c
> > > @@ -2005,6 +2005,13 @@ static int update_cfi_state(struct instruction *insn, struct cfi_state *cfi,
> > >   			break;
> > >   		case OP_SRC_REG_INDIRECT:
> > > +			if (!cfi->drap && op->dest.reg == cfa->base) {
> > 
> > && op->dest.reg == CFI_BP ?
> > 
> 
> Does it matter? My unstandig was that the register used to point to the CFA
> is getting overwritten, so we need to fallback to something known which is
> the offset from the stack pointer.
> 
> Was that not the case?

Maybe.  I was wondering if it would be possible to overwrite the stack
pointer, like 'mov disp(%rsp), %rsp', which could be possible in asm.

Though I suppose the below code would be harmless, since the CFA
base/offset would already be CFI_SP/cfi->stack_size respectively.

Still, no harm in making the condition more precise.

> > > +
> > > +				/* mov disp(%rsp), %rbp */
> > > +				cfa->base = CFI_SP;
> > > +				cfa->offset = cfi->stack_size;
> > > +			}

-- 
Josh


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2020-09-21 15:12 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-15  8:12 [PATCH 0/3] objtool: Extend CFA updating/checking Julien Thierry
2020-09-15  8:12 ` [PATCH 1/3] objtool: check: Fully validate the stack frame Julien Thierry
2020-09-18 20:56   ` Josh Poimboeuf
2020-09-21 10:31     ` Julien Thierry
2020-09-21 15:03       ` Josh Poimboeuf
2020-09-15  8:12 ` [PATCH 2/3] objtool: check: Support addition to set CFA base Julien Thierry
2020-09-18 21:09   ` Josh Poimboeuf
2020-09-15  8:12 ` [PATCH 3/3] objtool: check: Make SP memory operation match PUSH/POP semantics Julien Thierry
2020-09-18 21:43   ` Josh Poimboeuf
2020-09-21 10:31     ` Julien Thierry
2020-09-21 15:12       ` Josh Poimboeuf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.