[PATCH v1 2/4] aarch64 SFrame: use preferred CFI directive for AArch64 PAC

Matthieu Longo matthieu.longo@arm.com
Wed Dec 11 11:11:35 GMT 2024


On 2024-12-10 18:00, Richard Earnshaw (lists) wrote:
> On 10/12/2024 11:13, Matthieu Longo wrote:
>> On 2024-12-01 03:23, Indu Bhagat wrote:
>>> On 11/25/24 8:28 AM, Matthieu Longo wrote:
>>>> ARMv8.3 addded support for a new security feature named Pointer
>>>> Authentication. Support for this feature in SFrame already exists,
>>>> but is relying on the deprecated "AArch64" (actually Sparc) CFI
>>>> directive .cfi_gnu_window_save. .cfi_negate_ra_state CFI directive
>>>> should be used instead to convey this information.
>>>>
>>>> In GCC 14 and older, the Sparc DWARF extension .cfi_gnu_window_save
>>>> is emitted instead of .cfi_negate_ra_state.
>>>> GCC 15 fixed this issue, but this behavior is preserved for backward
>>>> compatibility.
>>>>
>>>> The existing sframe test for AArch64 PAC was 
>>>> using .cfi_gnu_window_save.
>>>> This patch replaces this CFI in the existing test by the preferred one,
>>>> and adds a new test to check for backward compatibility when using
>>>> .cfi_gnu_window_save.
>>>
>>> Hi Matthieu,
>>>
>>> See one comment inlined below.
>>>
>>> Thanks
>>> Indu
>>>
>>>> ---
>>>>   .../gas/cfi-sframe/cfi-sframe-aarch64-3.d     | 20 ++++++++++++++++++
>>>>   .../gas/cfi-sframe/cfi-sframe-aarch64-3.s     | 21 +++++++++++++++ 
>>>> ++++
>>>>   .../cfi-sframe-aarch64-pac-ab-key-1.s         |  8 +++----
>>>>   gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   |  1 +
>>>>   4 files changed, 46 insertions(+), 4 deletions(-)
>>>>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe- 
>>>> aarch64-3.d
>>>>   create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe- 
>>>> aarch64-3.s
>>>>
>>>> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-3.d b/ 
>>>> gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-3.d
>>>> new file mode 100644
>>>> index 00000000000..f72b70a970a
>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-3.d
>>>> @@ -0,0 +1,20 @@
>>>> +#as: --gsframe
>>>> +#objdump: --sframe=.sframe
>>>> +#name: SFrame cfi_negate_ra_state test (using cfi_window_save)
>>>> +#...
>>>> +Contents of the SFrame section .sframe:
>>>> +
>>>> +  Header :
>>>> +
>>>> +    Version: SFRAME_VERSION_2
>>>> +    Flags: NONE
>>>> +    Num FDEs: 1
>>>> +    Num FREs: 2
>>>> +
>>>> +  Function Index :
>>>> +    func idx \[0\]: pc = 0x0, size = 8 bytes
>>>> +    STARTPC + CFA + FP + RA +
>>>> +#...
>>>> +    0+0004 +sp\+16 +u +u\[s\] +
>>>> +
>>>> +#pass
>>>> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-3.s b/ 
>>>> gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-3.s
>>>> new file mode 100644
>>>> index 00000000000..df6ff6e8c8f
>>>> --- /dev/null
>>>> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-3.s
>>>> @@ -0,0 +1,21 @@
>>>> +## ARMv8.3 addded support a new security feature named Pointer 
>>>> Authentication. The
>>>> +## main idea behind this is to use the unused bits in the pointer 
>>>> values.
>>>> +## Each pointer is patched with a PAC before writing to memory, and 
>>>> is verified
>>>> +## before using it.
>>>> +## When the pointers are mangled, the stack trace generator needs 
>>>> to know so it
>>>> +## can mask off the PAC from the pointer value to recover the 
>>>> return address,
>>>> +## and conversely, skip doing so if the pointers are not mangled.
>>>> +##
>>>> +## .cfi_negate_ra_state CFI directive is usually used to convey 
>>>> this information.
>>>> +## In GCC 14 and older, the Sparc DWARF extension .cfi_window_save 
>>>> is emitted
>>>> +## instead of .cfi_negate_ra_state.  GCC 15 fixed this issue, but 
>>>> this behavior
>>>> +## is preserved in binutils for backward compatibility.
>>>> +##
>>>> +## SFrame has support for this. This testcase ensures that the 
>>>> directive
>>>> +## is interpreted successfully.
>>>> +    .cfi_startproc
>>>> +    .long 0
>>>> +    .cfi_def_cfa_offset 16
>>>> +    .cfi_window_save
>>>> +    .long 0
>>>> +    .cfi_endproc
>>>
>>> Since the purpose is to ensure that the old behavior is maintained, I 
>>> am wondering if it is not better to keep the old test as is (which 
>>> also tests the .cfi_window_save *together with* the .cfi_b_key_frame 
>>> directives). WDYT ?
>>>
>>
>> The old behavior is not going to be maintained with GCC 15 and newer.
>>  From my perspective, the purpose of this test is to test the behavior 
>> of A and B keys with the *correct* AArch64 CFI directives. That's the 
>> reason why I added a separate test cfi-sframe-aarch64-3.s to ensure 
>> that the old directive is still correctly parsed and processed.
> 
> We do need to ensure that a new version of gas works with old versions 
> of GCC, so if GCC-14 or earlier emit the wrong directive we will need to 
> continue to accept it until such versions are truly obsolete (a long time).
> 
> R. 

The new test cfi-sframe-aarch64-3.s is introduced to ensure that GCC-14 
or earlier continue to accept .cfi_window_save as it used to be. This is 
the backward compatibility test.

.cfi_window_save can be tested separately from the A and B keys. The 
.cfi_b_key_frame directive was not changed, so it is working as it 
always has worked.

The test cfi-sframe-aarch64-pac-ab-key-1.s was updated to use the new 
directive. I chose to replace it because we are supposed to use 
.cfi_negate_ra_state instead. If someone looks at the tests, he will see
.cfi_negate_ra_state which is used everywhere except in a backward 
compatibility test, so it is clearly *the recommended way*.

In the same way, in the previous commit, pac_ab_key.s was updated to use 
.cfi_negate_ra_state and a new test pac_compat_cfi_window_save.s was 
added to ensure the backward compatibility.

I hope the situation is clearer now. I probably should have explained it 
better in the commit message.

Matthieu

>>
>> Matthieu.
>>
>>>> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-pac-ab- 
>>>> key-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-pac-ab- 
>>>> key-1.s
>>>> index d9a408c668c..84230a99e3c 100644
>>>> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-pac-ab-key-1.s
>>>> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-aarch64-pac-ab-key-1.s
>>>> @@ -8,12 +8,12 @@ _Z5foo_av:
>>>>   .LFB0:
>>>>       .cfi_startproc
>>>>       hint    25 // paciasp
>>>> -    .cfi_window_save
>>>> +    .cfi_negate_ra_state
>>>>       stp    x29, x30, [sp, -16]!
>>>>       .cfi_def_cfa_offset 16
>>>>       .cfi_offset 29, -16
>>>>       .cfi_offset 30, -8
>>>> -        ret
>>>> +    ret
>>>>       .cfi_endproc
>>>>   .LFE0:
>>>>       .size    _Z5foo_av, .-_Z5foo_av
>>>> @@ -25,12 +25,12 @@ _Z5foo_bv:
>>>>       .cfi_startproc
>>>>       .cfi_b_key_frame
>>>>       hint    27 // pacibsp
>>>> -    .cfi_window_save
>>>> +    .cfi_negate_ra_state
>>>>       stp    x29, x30, [sp, -16]!
>>>>       .cfi_def_cfa_offset 16
>>>>       .cfi_offset 29, -16
>>>>       .cfi_offset 30, -8
>>>>       nop
>>>>       nop
>>>> -        ret
>>>> +    ret
>>>>       .cfi_endproc
>>>> diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/ 
>>>> testsuite/gas/cfi-sframe/cfi-sframe.exp
>>>> index cfae28d39aa..c646b109895 100644
>>>> --- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
>>>> +++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
>>>> @@ -97,5 +97,6 @@ if { [istarget "x86_64-*-*"] && 
>>>> [gas_sframe_check] } then {
>>>>   if { [istarget "aarch64*-*-*"] && [gas_sframe_check] } then {
>>>>       run_dump_test "cfi-sframe-aarch64-1"
>>>>       run_dump_test "cfi-sframe-aarch64-2"
>>>> +    run_dump_test "cfi-sframe-aarch64-3"
>>>>       run_dump_test "cfi-sframe-aarch64-pac-ab-key-1"
>>>>   }
>>>
>>
> 



More information about the Binutils mailing list