Bug 479997 - Segmentation fault on 32bit arm checking programs built with -fstack-clash-protection or -fstack-check
Summary: Segmentation fault on 32bit arm checking programs built with -fstack-clash-pr...
Status: REPORTED
Alias: None
Product: valgrind
Classification: Developer tools
Component: memcheck (show other bugs)
Version: 3.20.0
Platform: Other Linux
: NOR crash
Target Milestone: ---
Assignee: Julian Seward
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-01-18 15:24 UTC by Emanuele Rocca
Modified: 2024-01-26 14:03 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Emanuele Rocca 2024-01-18 15:24:08 UTC
Hi,
I found a small reproducer for the segmentation fault mentioned in https://bugs.kde.org/show_bug.cgi?id=479699.

Please note that the error can be reproduced with either -fstack-clash-protection or -fstack-check. This issue is similar to https://bugs.kde.org/show_bug.cgi?id=479996 - but you need a larger buffer on 64 bit.

  // example.c
  void a_function() { char buf[8192]; }
  int main() { a_function(); }

gcc -fstack-clash-protection example.c -o example && valgrind ./example
==2743356== Memcheck, a memory error detector
==2743356== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==2743356== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==2743356== Command: ./example
==2743356== 
==2743356== 
==2743356== Process terminating with default action of signal 11 (SIGSEGV)
==2743356==  Access not within mapped region at address 0xFEF0CB04
==2743356==    at 0x1084EA: a_function (in /tmp/example)
==2743356==  If you believe this happened as a result of a stack
==2743356==  overflow in your program's main thread (unlikely but
==2743356==  possible), you can try to increase the size of the
==2743356==  main thread stack using the --main-stacksize= flag.
==2743356==  The main thread stack size used in this run was 8388608.
==2743356== 
==2743356== HEAP SUMMARY:
==2743356==     in use at exit: 0 bytes in 0 blocks
==2743356==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2743356== 
==2743356== All heap blocks were freed -- no leaks are possible
==2743356== 
==2743356== For lists of detected and suppressed errors, rerun with: -s
==2743356== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 3 from 3)
Segmentation fault
Comment 1 Adhemerval Zanella 2024-01-26 14:03:48 UTC
This is issue is similar to https://bugs.kde.org/show_bug.cgi?id=479996 , where gcc does not really support arm32 -fstack-clash-support. Its own testsuite defines:

gcc/testsuite/lib/target-supports.exp
---
12587 # Return 1 if the target has support for stack probing designed
12588 # to avoid stack-clash style attacks.
12589 #
12590 # This is used to restrict the stack-clash mitigation tests to
12591 # just those targets that have been explicitly supported.
12592 #
12593 # In addition to the prologue work on those targets, each target's
12594 # properties should be described in the functions below so that
12595 # tests do not become a mess of unreadable target conditions.
12596 #
12597 proc check_effective_target_supports_stack_clash_protection { } {
12598
12599     if { [istarget x86_64-*-*] || [istarget i?86-*-*]
12600           || [istarget powerpc*-*-*] || [istarget rs6000*-*-*]
12601           || [istarget aarch64*-**] || [istarget s390*-*-*]
12602           || [istarget loongarch64*-**] } {
12603         return 1
12604     }
12605   return 0
12606 }
----

Although the option does not throw any frontend error, gcc uses the -fstack-check support by just changing the probing size from 8192 to 4096. Using the provided example:

With -fstack-check:
---
[...]
main:
        push    {r7, lr}
        mov     ip, #8192
        sub     ip, sp, ip
        str     r0, [ip, #4088]
        add     r7, sp, #0
        bl      a_function
        movs    r3, #0
        mov     r0, r3
        pop     {r7, pc}
---

And with '-fstack-clash-protection':
---
main:
        push    {r7, lr}
        mov     ip, #4096
        sub     ip, sp, ip
        str     r0, [ip, #4088]
        add     r7, sp, #0
        bl      a_function
        movs    r3, #0
        mov     r0, r3
        pop     {r7, pc}
---

So the stack pointer is not really updated while doing the probing, which generates an invalid memory access by valgrind. So one option to fix would be to either adjust arm32 code generation to always update and rollback SP, as x86_64; or proper implement -fstack-clash-protection.