Stack smashing and execution permissions

One of the oldest forms of attack is stack smashing. There are many types of stack smashing. The basic form of stack smashing involves malicious software writing new opcodes into memory and then attempting to execute the written memory. This process is illustrated here:

Typically, the memory that is used to launch the attack is stack memory. This is where the name stack smashing comes from. To protect against stack smashing, modern processor architectures, like the Arm architecture, have execution permissions. In Armv8-A, the main controls are execution permission bits in the translation tables. If we focus only on EL0 and EL1:

User (EL0) Execute-never
Privileged Execute-never

Setting one of these bits marks the page as not executable. This means that any attempt to branch to an address within that page triggers an exception, in the form of a Permission fault. There are separate Privileged and Unprivileged bits. This is because application code needs to be executable in user space (EL0) but should never be executed with kernel permissions (EL1/EL2). Another form of attack involves abusing system calls to try to get privileged code to call code from user memory.

The following diagram shows a simplified, but typical, virtual address space for an application that is running under an Operating System (OS), with the expected execution permissions:

Note: By convention, kernel space is at the top of memory and user space is at the bottom of memory. Although this is not required by the architecture, it is the most common layout and the examples in this guide follow this convention.

The architecture also provides control bits in the system control register, SCTLR_ELx, to make all writable addresses non-executable. Enabling this control makes locations like the stack non-executable.

A location that is writable at EL0 is never executable at EL1, regardless of how the PXN and SCTLR_ELx controls are configured.

Together, these controls can provide robust protection against the kinds of attack that we have described. The translation table attributes and write controls can block execution from any location that the malicious code could write to, as you can see in the following diagram:

Previous Next