GCC's stack protection feature (enabled with the flag -fstack-protector) aims to detect buffer overflows in C/C++ function local variables that might allow an attacker to overwrite saved registers on the stack. If an attacker can modify saved register values then it might be possible for them to subvert program flow control. The feature operates by placing a canary value between local variables and saved registers on the stack on function entry, and triggers an error handler on function exit if the canary value has been unexpectedly modified.
When targeting AArch64, this feature did not protect the saved registers from overflows in dynamically-sized local variables, these being C99-style variable length arrays and alloca() objects. Other local variables, including statically-sized local arrays, are not affected because of their different placement on the stack relative to saved registers. This issue affects all GCC releases. Arm has reserved CVE-2023-4039 for this issue.
GCC also has a feature (enabled with the flag -fstack-clash-protection) to protect against the Stack Clash vulnerability identified by the Qualys Research Team in 2017. This GCC feature ensures that all stack allocations are broken down into chunks that are no bigger than the OS's guard page size, with each allocation being probed via a store to memory. While developing the fix for the stack protection vulnerability, Arm also identified a case in which the stack clash protection feature could fail to probe an allocation properly, and so leave an entire guard page unprobed. As it stands, this missed probe can only occur in extreme circumstances: specifically, vulnerable code must have a function call with at least 4096 16-byte arguments or 8192 8-byte arguments, or some other similar combination. However, the fix for the stack protection issue removes this condition. Instead, it would be enough for vulnerable code to have more than 64k of local variables. It is therefore important that both issues are fixed together.
Arm has also examined GCC targeting AArch32 and clang targeting AArch32 and AArch64 and believes none of these are affected by these issues.
What is the fix?
The fix for the stack protection issue is to modify GCC to generate an alternative stack frame that places all local variables below saved registers, with the stack-protector canary between them. Developers worried about this issue will then need to recompile their software using the fixed compiler. Developers should be aware that the fixed compiler will generate slightly different code than before and this may impact code size or performance. The modified stack layout is local to each function and is not expected to introduce any binary compatibility issues.
The fix for the stack clash protection issue is to modify some boundary conditions in generated AArch64 code to ensure that all allocations are probed at the correct offset. This is not expected to have any noticeable effect on code size or performance.
[PATCH 00/19] aarch64: Fix -fstack-protector issue
Quoting from that message:
This series of patches fixes deficiencies in GCC's -fstack-protector implementation for AArch64 when using dynamically allocated stack space. This is CVE-2023-4039. See:
for more details.
The fix is to put the saved registers above the locals area when -fstack-protector is used.
The series also fixes a stack-clash problem that I found while working on the CVE. In unpatched sources, the stack-clash problem would only trigger for unrealistic numbers of arguments (8K 64-bit arguments, or an equivalent). But it would be a more significant issue with the new -fstack-protector frame layout. It's therefore important that both problems are fixed together.
Created gcc tracking bugs for this issue:
Affects: fedora-all [bug 2238670]
Created mingw-gcc tracking bugs for this issue:
Affects: fedora-all [bug 2238671]