Search code examples
cgccbuffer-overflow

Implement custom stack canary handling without the standard library


I am trying to implement stack canaries manually and without the standard library. Therefore I have created a simple PoC with the help of this guide from the OSDev wiki. The article suggests that a simple implementation must provide the __stack_chk_guard variable and the __stack_chk_fail() handler.

However, when I compile using GCC and provide the -fstack-protector-all flag, the executable does not contain any stack canary check at all. What am I missing to get GCC to include the stack canary logic?

gcc -Wall -nostdlib -nodefaultlibs -fstack-protector-all -g -m64 -o poc main.c customlib.h

main.c

#include "customlib.h"

#define STACK_CHK_GUARD (0xDEADBEEFFFFFFFF & ~0xFF)
uintptr_t __stack_chk_guard = STACK_CHK_GUARD;

__attribute__((noreturn)) void __stack_chk_fail()
{
    __exit(123);
    while(1);
}

int main()
{
    __attribute__((unused)) char buffer[16];

    for (size_t index = 0; index < 32; index++)
    {
        buffer[index] = 'A';
    }

    return 0;
}

customlib.h

This code is mostly irrelevant and is just necessary so that the program can be compiled and linked correctly.

typedef unsigned long int size_t;
typedef unsigned long int uintptr_t;

size_t __syscall(size_t arg1, size_t arg2, size_t arg3, size_t arg4, size_t arg5, size_t arg6)
{
    asm("int $0x80\n"
        : "=a"(arg1)
        : "a"(arg1), "b"(arg2), "c"(arg3), "d"(arg4), "S"(arg5), "D"(arg6));
    return arg1;
}

void _exit(int exit_code)
{
    __syscall(1, exit_code, 0, 0, 0, 0);
    while(1);
}

extern int main();

void _start()
{
    main();
    _exit(0);
}

GCC version 10.2.0, Linux 5.10.36-2-MANJARO GNU/Linux


Solution

  • It looks like the Arch gcc package (which the Manjaro package is based on) is turning off -fstack-protector when building without the standard library (Done for Arch bug 64270).

    This behavior is apparently also present in Gentoo.

    I haven't tried this, but I believe you should be able to dump the GCC specs using gcc -dumpspecs into a file, keeping only the section *cc1_options, removing %{nostdlib|nodefaultlibs|ffreestanding:-fno-stack-protector} from it, and passing it to gcc with gcc -specs=your_spec_file.

    Alternately, you can rebuild the gcc package with this patch removed.