15.3 Stack Smashing Protector (SSP) for Target Devices with an Arm Cortex Core

Background

“Smashing the stack” is a term coined by Elias Levy (a.k.a. Aleph One) in a 1996 article in Phrack Magazine titled “Smashing the Stack for Fun and Profit.” This article is still available from various sources online including duckduckgo.com/?q=Smashing+the+Stack+for+Fun+and+Profit+by+aleph+one&ia=web.

In many applications written in C, attackers can corrupt the execution stack by writing past the end of a local buffer array using the automatic storage class. An attack overwrites or “smashes” critical data on the stack to enable nefarious actions used in a security exploit. The details of a stack-smashing attack are beyond the scope of this document.

The Stack Smashing Protector (SSP) compiler feature helps detect a stack buffer overrun through runtime detection of changes to a secret value, known as the stack canary, located on the stack. The feature helps the application developer to identify such application bugs and vulnerabilities and it also helps mitigate against stack-smashing security attacks. To help detect these types of problems, the compiler instruments the function’s prologue code to store the secret stack-canary value, to the stack before other automatic variables. Then, before returning from the function, the function’s epilogue code checks the stored stack-canary value. If the function’s epilogue code determines that the value has been modified, a stack buffer overflow has occurred and a failure callback, __stack_chk_fail(), is invoked as described in detail below.

Important: The Stack Smashing Protector (SSP) feature merely helps to detect stack buffer overruns. It does not prevent them. In addition, defeating the detection mechanism is possible by preparing the input such that the stack canary is overwritten with the correct secret value and thus does not offer perfect protection. Therefore, your first line of defense must be to fix your application code to eliminate the possibility of buffer overruns. Do not rely on this feature to catch all cases of buffer overruns.

Since this feature adds code to both the function prologue and epilogue, it increases code size and execution time of every affected function. The compiler options listed below allow you to specify which types of functions to instrument.