Category Icon
security
|
30.05.2023

Who’s your canary?

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.

Short recap

Canary in the stack

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, i.e. via 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.

Implementing a canary

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

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 0x00, 0x00, 0xff, 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

Running gcc -v on your distro will most likely show --disable-libssp.

Source: gcc/libssp/ssp.c:73

glibc

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 0x00, 0x00, 0xff, 0x0a (see libssp).

To retrieve the value for the current execution, set LD_SHOW_AUXV=1.

$ LD_SHOW_AUXV=1 /bin/true | grep AT_RANDOM
AT_RANDOM:       0x7ffcacfa8c49

Source: glibc/sysdeps/unix/sysv/linux/dl-osinfo.h:26

musl libc

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.

Source: musl/src/env/__stack_chk_fail.c:7

bionic libc

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.

Source: bionic/libc/bionic/__libc_init_main_thread.cpp:109

uclibc-ng

uclibc-ng is a small C library primarily designed for embedded systems. For the random number generation of its stack protector it utilizes /dev/urandom by default. Alternatively, it can also fall back to a pseudo-random approach based on a magic value (0xFF0A0D00UL) xor current time.

Source: uclibc-ng/libc/sysdeps/linux/common/dl-osinfo.h:36

dietlibc

The statically linked C library, developed by fefe, also takes hold of AT_RANDOM for stack canary generation, with an optional fallback to /dev/urandom.

Source: dietlibc/lib/stackgap-common.h

picolibc (not really Linux specific)

picolibc is another C library primarily used on embedded systems, particularly in scenarios with very limited main memory. Per default, it uses the magic value 0x00, 0x00, 0xff, 0x0a (see libssp). If feasible and constructors are available, it utilizes the random number generator of the operating system.

Source: picolibc/newlib/libc/ssp/stack_protector.c:21

Linux kernel (no libc)

The Linux kernel itself incorporates a stack protector mechanism for each kernel stack. It obtains random numbers from its internal random number generator.

Source: linux/include/linux/stackprotector.h:23

OpenBSD libc

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 .openbsd.randomdata, which is an ELF section filled by the kernel on program execution (using its entropy pool).2

Source: openbsd-src/lib/libc/sys/stack_protector.c:47

Con{clusion,fusion}

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.

Publish date

30.05.2023

Category

security

Authors

Aaron Marcher

Richard Weinberger

Icon with a waving hand

Get in touch

+43 5 9980 400 00 (email preferred)

sigma star gmbh
Eduard-Bodem-Gasse 6, 1st floor
6020 Innsbruck | Austria

LinkedIn logo
sigma star gmbh logo