POSTED BY: Dimitrios Glynos / 21.01.2009

Static SSP canary in Debian libc6

CENSUS ID:CENSUS-2009-0001
Affected Products:All SSP-armoured applications, statically or dynamically linked against the libc6 library (versions ≤ 2.7) provided by the Debian GNU/Linux project.
Class:Degraded performance of security mechanism due to misconfiguration.
Discovered by:Dimitris Glynos

We have found that Debian packages of the GNU libc library (versions prior to and including 2.7) provide a static (i.e. guessable) canary value to all applications armoured with the gcc SSP mechanism.

Details

The gcc compiler provides SSP (propolice) stack protection to applications compiled with the -fstack-protector{,-all} options. The actual canary value used in this stack protection scheme is supplied by the C library.

If GNU libc is built with the —enable-stackguard-randomization option, each application gets a random canary value (at runtime) from /dev/urandom.

If —enable-stackguard-randomization is absent, applications get a static canary value of “0xff0a0000”. This is very unfortunate, because the attacker may be able to bypass the stack protection mechanism, by placing those 4 bytes in the canary word, before the actual canary check is performed (for example in memcpy-based buffer overflows).

A bug report has been sent to Debian concerning this point and new packages addressing the issue have been released. If you are building applications with SSP support in Debian, we advise you to upgrade to version 2.9 (or better) of libc6.

If you want to test if your distribution’s libc is providing a random canary, you may use the following code. It prints the canary value on x86_32, x86_64 and ppc32 systems.

#include <stdio.h>

#if defined(__i386__)

typedef unsigned long reg_t;
#define REG_FMT "%0lx"
#define get_canary(reg) asm volatile("mov %%gs:(0x14), %0" : "=r" (reg));

#elif defined(__x86_64__)

typedef unsigned long long reg_t;
#define REG_FMT "%0llx"
#define get_canary(reg) asm volatile("mov %%fs:(0x28), %0" : "=r" (reg));

#elif defined(__PPC__)

typedef unsigned long reg_t;
#define REG_FMT "%0lx"
#define get_canary(reg) asm volatile("lwz %0, -28680(2)" : "=r" (reg));

#else

#error unsupported platform; aborting...

#endif

int main(int argc, char *argv[]) {
        reg_t reg;

        get_canary(reg);
        printf("canary value: " REG_FMT "\n", reg);

        return 0;
}

Save the above C code as “print-canary.c”, compile and execute it as follows:


$ gcc -o print-canary print-canary.c
$ ./print-canary
canary value: ff0a0000
$

Note: “print-canary” does not require any stack protection flags during compilation, since the canary value is always initialised in libc, even if stack protection is not used.

See here for an update on canary randomisation techniques for the Linux platform.