GCC’s -fstack-protector fails to guard dynamic stack allocations on ARM64 [CVE-2023-4039]

We discussed this vulnerability during Episode 216 on 26 September 2023

A bit of an unexpected fault in GCC’s -fstack-protector implementation that meant that the saved return address wasn’t actually protected by the stack-protector on AArch64 in some cases.

If you’re unfamiliar the way stack protector works is that it’ll inject a local variable at the top of the locals section containing a canary value. Before returning it will check the canary value and if it changed it knows a stack-based corruption happened. With a normal stack-frame the saved return address will be before the canary, so a linear overflow starting at a local address will have to overwrite the canary in order to reach the saved return address for the traditional control-flow hijacking attack.

The problem is that the AArch64 stack-frame is a bit different in two important ways:

  1. The saved registers like the saved return address are placed after the locals instead of before.
  2. Dynamic stack allocations (like those from an alloca call) are stored after the saved registers

This creates a situation where if a linear overflow starts from one of the dynamic stack allocations it can overflow into the saved return address without needing to overflow a canary value