0

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

prd
  • 2,272
  • 2
  • 17
  • 32
  • Perhaps this can help: https://stackoverflow.com/questions/24465014/gcc-generate-canary-or-not – Support Ukraine May 26 '21 at 09:45
  • @4386427 `-fstack-protector-all` should force GCC to add the check to any function, also the buffer in `main()` is larger than 8 bytes, thus there is no reason to omit the check from an optimization standpoint. – prd May 26 '21 at 09:51
  • 1
    [This](https://godbolt.org/z/bnd6ehxEY) seems to be emitting the canary checks correctly. – Hasturkun May 26 '21 at 12:48
  • @Hasturkun thanks for pointing this out. I have now verified that the code indeed works when using a VM and a different GCC installation. What could be the issue here? When compiling on Manjaro, the canary checks are nowhere to be found. – prd May 26 '21 at 20:36
  • Perhaps allocated frame size is too large, have you tried increasing the overflow from 32 to 64? – yugr May 27 '21 at 01:29
  • @yugr shouldn't the frame size be irrelevant when providing `-fstack-protector-all`? Nonetheless, I have also tried the same buffer size with a 128 and 256 byte overflow - same result. – prd May 27 '21 at 07:46
  • 1
    Assuming the GCC package you're using in Manjaro is based on the one from Arch, [this patch](https://github.com/archlinux/svntogit-packages/blob/f5e1c54220db0c659a8db7f6d62be86356ec8aca/trunk/fs64270.patch) looks relevant (forces `-fno-stack-protector` when disabling standard libraries). Does adding an explicit `-fstack-protector` do anything? – Hasturkun May 27 '21 at 08:23
  • @Hasturkun explicitly stating `-fstack-protector` does not work either, but I think your guess is correct and the Arch flavored GCC does not like custom SSPs! – prd May 27 '21 at 08:30

1 Answers1

3

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.

Hasturkun
  • 35,395
  • 6
  • 71
  • 104