Return-oriented programming

[4][nb 1] Each gadget typically ends in a return instruction and is located in a subroutine within the existing program and/or shared library code.

Generally, these types of attacks arise when an adversary manipulates the call stack by taking advantage of a bug in the program, often a buffer overrun.

[5] Eventually, operating systems began to combat the exploitation of buffer overflow bugs by marking the memory where data is written as non-executable, a technique known as executable-space protection.

With this enabled, the machine would refuse to execute any code located in user-writable areas of memory, preventing the attacker from placing payload on the stack and jumping to it via a return address overwrite.

The widespread implementation of data execution prevention made traditional buffer overflow vulnerabilities difficult or impossible to exploit in the manner described above.

This technique was first presented by Solar Designer in 1997,[6] and was later extended to unlimited chaining of function calls.

[7] The rise of 64-bit x86 processors brought with it a change to the subroutine calling convention that required the first few arguments to a function to be passed in registers instead of on the stack.

Return-oriented programming builds on the borrowed code chunks approach and extends it to provide Turing-complete functionality to the attacker, including loops and conditional branches.

[9][10] Put another way, return-oriented programming provides a fully functional "language" that an attacker can use to make a compromised machine perform any operation desired.

None of the counter-exploitation techniques mentioned above, including removing potentially dangerous functions from shared libraries altogether, are effective against a return-oriented programming attack.

By chaining the small instruction sequences, an attacker is able to produce arbitrary program behavior from pre-existing library code.

[citation needed] In addition to brute force attacks, techniques for removing randomization exist.

Even with perfect randomization, if there is any information leakage of memory contents it would help to calculate the base address of for example a shared library at runtime.

The G-Free technique was developed by Kaan Onarlioglu, Leyla Bilge, Andrea Lanzi, Davide Balzarotti, and Engin Kirda.

Although widely deployed by modern operating systems, ASLR is vulnerable to information leakage attacks and other approaches to determine the address of any known library function in memory.

This prevents gadget chaining, but carries a heavy performance penalty,[clarification needed] and is not effective against jump-oriented programming attacks which alter jumps and other control-flow-modifying instructions instead of returns.

For every updated device, the Cloud-based service introduced variations to code, performs online compilation, and dispatched the binary.

This means that many Binary Randomization techniques are applicable for network interfaces and system programming and are less recommended for complex algorithms.

[23] In 2010, Jinku Li et al. proposed[24] that a suitably modified compiler could eliminate return-oriented "gadgets" by replacing each call f with the instruction sequence pushl $index; jmp f and each ret with the instruction sequence popl %reg; jmp table(%reg), where table represents an immutable tabulation of all "legitimate" return addresses in the program and index represents a specific index into that table.

Li et al. claimed that "our return indirection technique essentially de-generalizes return-oriented programming back to the old style of return-into-libc.

[28] The ARMv8.5-A architecture introduces another new feature at the hardware level that explicitly identifies valid targets of branch instructions.

These identified branch destinations typically include function entry points and switch/case code blocks.

PAC and BTI are complementary mechanisms to prevent rogue code injections using return-oriented and jump-oriented programming attacks.

An example layout of a call stack. The subroutine DrawLine has been called by DrawSquare . Note that the stack is growing upwards in this diagram.