A few weeks ago we gave a training on secure coding and talked about the stack protector on Linux. While roughly explaining how it works and how it can be utilized with GCC, an attendee asked where the stack canary comes from. The question was quickly resolved by answering that it’s a random value provided by the kernel upon process startup.
But where does the value really come from? This question turned out to be more interesting than expected. In this blog post we will give you a rough overview where the stack canary comes from with different libc implementations.
Stack canaries are a security feature implemented in many software programs to
help mitigate buffer overflow attacks. The stack protector places a
randomized canary value at a specific position on the function stack.
It is crucial that the value is not known to the attacker, not can be easily guessed.
This is why the canary value is randomly selected for each newly executed program.
Please note that the value is not unique per process, if a process is copied,
fork(), then also the canary value stays the same.
Before function returns the value is compared to the initial one. If it changed, the
stack is corrupted and execution aborts to prevent an attacker from executing their malicious code.
For example, in GCC the stack protector can be enabled using the
-fstack-protector compiler option.
Let’s take a look at how various stack protector implementations select the canary value.
In most implementations, the symbol
__stack_chk_guard holds the canary value,
and the function
__stack_chk_fail() is called upon failure.
libssp is a standalone library included in GCC, if enabled, providing stack protection mechanisms. Per default, it is disabled on most Linux systems, but it has proven to be useful on bare metal (embedded) systems without a libc.
To generate its canaries, it tries to read from
/dev/urandom if present. Otherwise, the canary is hard-coded to the values
0x0a. These values are chosen to stop string functions and prevent stack overflow:
0x00 is the NULL character, terminating a string
0xff is invalid according to the UTF-8 specification
0x0a is a newline character
gcc -v on your distro will most likely show
When there is no
libssp support is available, glibc can handle canaries on its own.
For each newly started program, the kernel generates a random
value and passes it to the program using the auxiliary vector1
AT_RANDOM from the userspace’s
auxiliary vector. On non-Linux systems, glibc falls back to using the value
0x0a (see libssp).
To retrieve the value for the current execution, set
$ LD_SHOW_AUXV=1 /bin/true | grep AT_RANDOM
The lightweight alternative C library musl uses
AT_RANDOM for its stack
canaries, just like glibc. As a fallback on non-Linux it uses the address of
__stack_chk_guard multiplied by a magic value (
0x41C64E6D), which may
seem suboptimal at first glance.
However, if ASLR is available, it can serve as a source of randomness. ASLR randomizes memory addresses, making it challenging for attackers to exploit memory-related vulnerabilities. By relying on ASLR to randomize the stack canary value in the fallback scenario, it ensures that the canary is not easily guessable.
The bionic libc, utilized by Google on Android, uses an arc4 random
number generator if the
/dev/urandom pseudo-device is available. If not, it
falls back to using
AT_RANDOM through the auxiliary vector.
uclibc-ng is a small C library primarily designed for embedded systems. For the
random number generation of its stack protector it utilizes
default. Alternatively, it can also fall back to a pseudo-random approach based on
a magic value (
0xFF0A0D00UL) xor current time.
The statically linked C library, developed by fefe, also
takes hold of
AT_RANDOM for stack canary generation, with an optional
picolibc is another C library primarily used on embedded systems, particularly in scenarios with very limited main memory. Per default, it uses the
0x0a (see libssp). If feasible and constructors are available, it utilizes the random number generator of the operating system.
The Linux kernel itself incorporates a stack protector mechanism for each kernel stack. It obtains random numbers from its internal random number generator.
OpenBSD’s libc previously used the
getentropy() system call to obtain random values
in its stack canaries, which recevied its bytes directly from the kernel’s
entropy pool. However, starting from the 5.3 release, they transitioned to
which is an ELF section filled by the kernel on program execution (using its
The variations in the implementation details of stack protectors and the generation of its stack canaries across diverse C libraries are remarkably diverse. Some C libraries utilize the (pseudo) random number generator of the OS, while others have their own implementations.
Generally, C libraries follow quite sane defaults. However, the main concern lies in the fallbacks: They are often questionable. One possible attack vector would be to ensure that the C library falls back to a (less secure) source of random numbers.