Linux kernel memory protection mechanisms: aslr and canary
ASLR
The ASLR technique, known as Address space layout randomization, is a feature that comes with most modern general-purpose operating systems and ensures that the memory layout is different every time a process is instantiated.
For some memory segments, random offsets are appended to prevent buffer attacks, etc. This is OS-level protection, but of course it is also compatible with hardware-level redundancy using ECC bits for legitimacy detection.
More precisely, in the process model under Linux, the effect of aslr on memory placement is as follows:
- No change: code segments/BSS/global data areas, etc.
- Changes: code location of loaded dependency libraries (manually linked, most typically glibc, . For example, replaying when using printf will result in a link space address segment error, which can be attacked if aslr is disabled), stack space, heap space, etc. (the latter two may not be appended depending on the aslr's different tiers, depending on the kernel version)
Process Address Space Arrangement (from Code Randomizer, for reference only):
existGDB EnvironmentRunning the program under aslr is closed by default, which also makes it easier for us to debug the program.
Here's a typical practical example:
I need to build a virtualized sandbox for a real requirement at work, the underlying base relies on a uni-kernel bsd system, and the aslr mechanism needs to be turned off manually for snapshot migration replay needs of the sandbox, with additional hardware level memory protection.
Enabling/disabling aslr executes the following code, 1 for enabling and 0 for disabling:
sysctl kern.=0
sysctl kern..pie_enable=0
sysctl kern.=0
sysctl kern.=0
sysctl kern..pie_enable=0
sysctl kern.=0
sysctl -a | grep aslr
If you are using the gcc compiler, you can append the-fPIE
compilation options to support the aslr mechanism.
canary
We usually have a MAGIC NUMBER on our stack to detect if that block of memory space has been modified by other accidents. It has a nice name: canary, canary, beautiful and fragile.
It is usually deployed somewhere near the top-of-stack return address to ensure that the space has not been modified by an external buffer overflow. Although it is a simple mechanism, it can prevent many relatively simple attacks or non-malicious mistakes, and is the first line of defense for memory protection.
It is usually generated when a function is called and the segment is strictly unreadable to the userland, so it can only be handled by probing with fork/privilege/hijacking sys functions and other brute force breaking.
This idea is not limited to kernel scenarios, but can also be used when doing data validation under general purpose requirements, or when there is a need for reliable TCB scenarios. In this case, it's a custom rule check in user space.
In gcc/clang you can use the-fno-stack-protector
Compile options to disable canary, but don't do it if you don't know exactly what you're doing!