Customizable `__stack_chk_fail` implementation

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Customizable `__stack_chk_fail` implementation

Łukasz Żak
Dear list,

I am using new lib for C/C++ development on arm devices (cortex-m3 and such) using gnu arm embedded toolchain (https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm) which does include recent new lib version at the time of its release. Just recently I have tried to enable gcc built-in stack protection mechanism (-fstack-protector flag). The new lib implementation of `__stack_chk_fail` does work great in an environment where semihosting is available - i.e. under the Qemu. I get nice message saying the stack corruption has been detected and execution terminates. When however I build and run the same sources for real hardware the problems are detected - I can observe the calls to `__stack_chk_fail` with the gdb but as there is no semihosting available the write/_exit procedures used by the `__stack_chk_fail` handler are basically noops as they should be as on real hardware there is no standard output (at least in my case) and there is nothing to exit to. So what happens is problem is detected but not reported anywhere and program execution continues as if there were never a problem at all.

I tried replacing this handler with my own custom handler but as it is not marked as weak the only thing that I can do is to try and use ld's `--wrap` argument to replace this handler at the link time. This does work as long as link time optimization (-flto) is not enabled (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88643) which is unfortunately requirement for me in release builds.  

Would you consider making stack protection handler overridable by i.e. making it weak function and/or proving a hook that someone can intercept?

Cheers,
Łukasz Żak

Reply | Threaded
Open this post in threaded view
|

Re: Customizable `__stack_chk_fail` implementation

Freddie Chopin
On Tue, 2019-10-15 at 10:25 +0000, Łukasz Żak wrote:
> When however I build and run the same sources
> for real hardware the problems are detected - I can observe the calls
> to `__stack_chk_fail` with the gdb but as there is no semihosting
> available the write/_exit procedures used by the `__stack_chk_fail`
> handler are basically noops as they should be as on real hardware
> there is no standard output (at least in my case) and there is
> nothing to exit to.

While this is true for _write(), it's wrong for _exit(), which should
_NOT_ return.

This is how a stub for _exit() should look like (code from my C++ RTOS
for ARM microcontrollers):
https://github.com/DISTORTEC/distortos/blob/6c1e232f777284f6ecb935b7f2e94faba6174860/source/newlib/syscallsStubs.cpp#L57

It may reset your chip, it may print/log whatever you want, send you an
e-mail or print something on LCD, but it should never ever return.

Regards,
FCh

Reply | Threaded
Open this post in threaded view
|

RE: Customizable `__stack_chk_fail` implementation

Łukasz Żak
Thank you for pointing out such an obvious mistake in my assumptions.  Regarding the hooking
`__stack_chk_fail` the only way to intercept stack check failures is at `_exit` handler level
where the fact of unexpected (and ultimately invalid anyway) call has been made?
If there is no other way it, of course, can be done but I was hoping, that such failures could be
intercepted sooner and handled differently.  

Regards,
Łukasz Żak

-----Original Message-----
From: Freddie Chopin <[hidden email]>
Sent: Tuesday, October 15, 2019 1:44 PM
To: Łukasz Żak <[hidden email]>; [hidden email]
Subject: Re: Customizable `__stack_chk_fail` implementation

On Tue, 2019-10-15 at 10:25 +0000, Łukasz Żak wrote:
> When however I build and run the same sources for real hardware the
> problems are detected - I can observe the calls to `__stack_chk_fail`
> with the gdb but as there is no semihosting available the write/_exit
> procedures used by the `__stack_chk_fail` handler are basically noops
> as they should be as on real hardware there is no standard output (at
> least in my case) and there is nothing to exit to.

While this is true for _write(), it's wrong for _exit(), which should _NOT_ return.

This is how a stub for _exit() should look like (code from my C++ RTOS for ARM microcontrollers):
https://github.com/DISTORTEC/distortos/blob/6c1e232f777284f6ecb935b7f2e94faba6174860/source/newlib/syscallsStubs.cpp#L57

It may reset your chip, it may print/log whatever you want, send you an e-mail or print something on LCD, but it should never ever return.

Regards,
FCh