In our case we have to implement our libc as this is for an embedded multicore device, and this why I need to understand the semantics of the mechanism. What the compiler inserts and what the runtime library support expects have to work together and I do not understand the mechanism in order to implement them.
However, from what you say, the “canary” is just a value (could be anything) that is planted in the function’s own stack frame, and on return if it is altered then the check decides that a stack overflow occurred and aborts.
But this means that a stack overflow that corrupts an adjacent data region which will be visited at another time will not be detected unless by coincidence something writes to that region during the lifetime of the function. It also means that if the function’s own stack is corrupted by overlapping writes, then its own return address may also be clobbered along with the canary, and there is no guarantee it will resume control at all.
This seems like a very error prone approach. Or am I misunderstanding the semantics?
In a simple runtime context like ours, the stack is a simple area of memory. We have a programmer specified stack begin address, and the programmer also determines how much stack to allocate to the program (specified at link-time).
What I would really like to do, is test if there is enough room on the stack before I use the reservation, and abort if there is not. Our stack grows from high address to low, so currently the function prologue does something like:
SP -= #bytes to reserve
execute code
SP += #bytes to reserve
return
I would like:
SP -= #bytes to reserve
OPTIONAL: update SP high-water mark
IF: SP < __top_of_stack THEN abort
execute code
SP += #bytes to reserve
return
The symbol ‘__top_of_stack’ can be provided by the linker when laying out memory for the program. This approach would work well as there is no chance that the function’s stack frame will clobber data as the test and abort happen before the reserved stack is used.
I don’t see how the ‘_stack_chk’ approach can do this, or ensure that the frame does not corrupt adjacent memory.
Thanks,
MartinO