https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103009

            Bug ID: 103009
           Summary: Weakness in stack-protector with no-pie active on ARM.
           Product: gcc
           Version: 9.4.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: sylw.bar at gmail dot com
  Target Milestone: ---

Created attachment 51710
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=51710&action=edit
Test program

During development for very space restricted Cortex-A5 based environment I
found potential weakness in stack-protector functionality in GCC 9.4.0.
Fortunatelly, I was able to reproduce problem using 32-bit Ubuntu Server 21.10
for Raspberry Pi (I used RPi4).
https://ubuntu.com/download/raspberry-pi

The problem: Not appropriate content of canary value put on the stack when
stack-protector is enabled and -fno-pie active.

In theory, for security reasons, the canary value should be randomly generated. 
During my development I realized that in my system the canary is constant and
holds address of __stack_chk_guard hidden variable.
The __stack_chk_guard variable is internal stack-protector variable that holds
random value that should be copied to tested function stack.
I prepared simple program that extracts real value of canary copied on test()
function stack.
The canary is hidden but it is located right after 12-byte buffer. I'm using
out of bound index in main() to extract canary which type is uintptr_t.

Important fact is that problem occurs when -fno-pie is set.
Here is test.c program:

#include <stdio.h>
#include <stdint.h>
#define BUF_LEN 12
extern uintptr_t __stack_chk_guard;

uintptr_t test(int idx)
{
   unsigned char buffer[BUF_LEN];
   return *((uintptr_t*)&buffer[idx]);
}

int main()
{
   printf("__stack_chk_guard: &%x = %x\n", (int)&__stack_chk_guard,
__stack_chk_guard);
   uintptr_t canary = test(BUF_LEN);
   printf("canary: %x\n", canary);
   return 0;
}

System: 32-bit Ubuntu Server 21.10 for Raspberry Pi on RPI4 with additional
packets: gcc-9 gcc-10 gcc-11:

GCC 10&11 show correct result:
ubuntu@ubuntu:~/work$ gcc-11 -Os -fno-pie -fstack-protector-all test.c  -o test
ubuntu@ubuntu:~/work$ ./test
__stack_chk_guard: &b6f72298 = 90148100
canary: 90148100

ubuntu@ubuntu:~/work$ gcc-10 -Os -fno-pie -fstack-protector-all test.c  -o test
ubuntu@ubuntu:~/work$ ./test
__stack_chk_guard: &b6fa5298 = 1642cf00
canary: 1642cf00

GCC 9.4 reveals that address of __stack_chk_guard was copied to canary:
ubuntu@ubuntu:~/work$ gcc-9 -Os -fno-pie -fstack-protector-all test.c  -o test
ubuntu@ubuntu:~/work$ ./test
__stack_chk_guard: &b6f85298 = 69229c00
canary: b6f85298

ubuntu@ubuntu:~/work$ gcc-9 -v
Using built-in specs.
COLLECT_GCC=gcc-9
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/9/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.4.0-3ubuntu1'
--with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs
--enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,gm2 --prefix=/usr
--with-gcc-major-version-only --program-suffix=-9
--program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id
--libexecdir=/usr/lib --without-included-gettext --enable-threads=posix
--libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new
--enable-gnu-unique-object --disable-libitm --disable-libquadmath
--disable-libquadmath-support --enable-plugin --enable-default-pie
--with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto
--enable-multiarch --disable-sjlj-exceptions --with-arch=armv7-a
--with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --disable-werror
--enable-checking=release --build=arm-linux-gnueabihf
--host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
gcc version 9.4.0 (Ubuntu 9.4.0-3ubuntu1)

Summary.
1. Problem (potential) is reproducible on 9.3.0 and 9.4.0 with -fno-pie.
2. Problem not visible on: 10.3.0, 11.2.0
3. stack-protector functionality is working fine, but lack of randomness of
canary is security risk.

Attaching function test() assemblies compiled on 9.4 and 10.3.
There are visible differences between addressing __stack_chk_guard using r3
register.

10.3:

test:
        @ args = 0, pretend = 0, frame = 16
        @ frame_needed = 0, uses_anonymous_args = 0
        push    {r0, r1, r2, r3, r4, lr}
        ldr     r3, .L3
        ldr     r3, [r3]
        str     r3, [sp, #12]
        ...

.L3:
        .word   __stack_chk_guard


9.4:

test:
        @ args = 0, pretend = 0, frame = 16
        @ frame_needed = 0, uses_anonymous_args = 0
        push    {r0, r1, r2, r3, r4, lr}
        ldr     r3, .L3
        ldr     r3, [r3]
        str     r3, [sp, #12]
        ...

.L3:
        .word   .LC0
.LC0:
        .word   __stack_chk_guard

Reply via email to