Here the piece of code :
int main()
{
char buffer[64];
int check;
...
As you can see, check
is declared AFTER buffer
, so in the stack, we must have check
ABOVE buffer
in the stack right?
However, when I disassembly (x86) it with gdb, this is what I got :
--> check
at 0xbffff4f8
--> buffer
at 0xbffff4b8
My question : is there a specific order in the stack for local variable?
Also, I have to tell you that I tried the same thing on another computer (x86 too, same gcc compilation options, but different gdb version and linux distrib), and the order is not the same...:S
Thanks !
PS: if you want more details, please see the screenshot : (left with computer 1 and right with computer 2)
There is -fstack-protect
in gcc to reorder stack variables, turned on by default in some Linux OS variant for almost 10 years, especially Ubuntu, Redhat, gentoo. Also default since gcc 4.8.3 ("4.9 and later enable -fstack-protector-strong.")
Ubuntu page about gcc defaults: https://wiki.ubuntu.com/ToolChain/CompilerFlags
Ubuntu-specific default compiler flags in the toolchain used to help provide additional security features to Ubuntu. ... Default Flags
-fstack-protector
... First enabled in Ubuntu 6.10.
Ubuntu page about stack protection https://wiki.ubuntu.com/GccSsp
gcc 4.1 comes with SSP now, which is a nice technology to mitigate exploitability of many buffer overflows. ... SSP provides a technology to stop exploitability of this class of vulnerabilities by (1) reordering stack variables ... RedHat and gentoo are using SSP by default for years
This reordering requires several O(n^2)
walks on all local variables of function which will make compilation slower for long functions, for example "Why does compiling over 100,000 lines of std::vector::push_back take a long time?" - https://stackoverflow.com/a/14034393/196561
Deferred allocation is forced when
-fstack-protect
is enabled (sometimes it needs to reorder all stack variables). .. cfgexpand.c
969 /* A subroutine of expand_one_var. VAR is a variable that will be
970 allocated to the local stack frame. Return true if we wish to
971 add VAR to STACK_VARS so that it will be coalesced with other
972 variables. Return false to allocate VAR immediately.
973
974 This function is used to reduce the number of variables considered
975 for coalescing, which reduces the size of the quadratic problem. */
976
977 static bool
978 defer_stack_allocation (tree var, bool toplevel)
980 /* If stack protection is enabled, *all* stack variables must be deferred,
981 so that we can re-order the strings to the top of the frame. */
So, gcc will reorder all stack variables, and strings will be at top of the frame. Try -fno-stack-protector
option to disable.
As usual, gcc's author don't document how -fstack-protect
works in public documentation https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html:
-fstack-protector
Emit extra code to check for buffer overflows, such as stack smashing attacks. This is done by adding a guard variable to functions with vulnerable objects. This includes functions that callalloca
, and functions with buffers larger than 8 bytes. The guards are initialized when a function is entered and then checked when the function exits. If a guard check fails, an error message is printed and the program exits.
-fstack-protector-all
Like-fstack-protector
except that all functions are protected.
-fstack-protector-strong
Like-fstack-protector
but includes additional functions to be protected — those that have local array definitions, or have references to local frame addresses.
-fstack-protector-explicit
Like-fstack-protector
but only protects those functions which have thestack_protect
attribute.
And the only documentation of array-before-locals I see is the real, best documentation: source code
https://gcc.gnu.org/viewcvs/gcc/branches/gcc-4_6-branch/gcc/cfgexpand.c?revision=175029&view=markup#l1526 - expand_used_vars()
1533 if (has_protected_decls)
1534 {
1535 /* Phase 1 contains only character arrays. */
1536 expand_stack_vars (stack_protect_decl_phase_1);
1537
1538 /* Phase 2 contains other kinds of arrays. */
1539 if (flag_stack_protect == 2)
1540 expand_stack_vars (stack_protect_decl_phase_2);
1541 }
1542
1543 expand_stack_vars (NULL);
phase 1 and phase 2 vars are separated by stack_protect_decl_phase()
https://gcc.gnu.org/viewcvs/gcc/branches/gcc-4_6-branch/gcc/cfgexpand.c?revision=175029&view=markup#l1235
1235 /* Return nonzero if DECL should be segregated into the "vulnerable" upper
1236 part of the local stack frame. Remember if we ever return nonzero for
1237 any variable in this function. The return value is the phase number in
1238 which the variable should be allocated. */
1239
1240 static int
1241 stack_protect_decl_phase (tree decl)
...
1243 unsigned int bits = stack_protect_classify_type (TREE_TYPE (decl));
...
1249 if (flag_stack_protect == 2)
1250 {
1251 if ((bits & (SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_LARGE_CHAR_ARRAY))
1252 && !(bits & SPCT_HAS_AGGREGATE))
1253 ret = 1;
1254 else if (bits & SPCT_HAS_ARRAY)
1255 ret = 2;
1256 }
stack_protect_classify_type
will return bits HAS_ARRAY
with HAS_*_CHAR_ARRAY
only for arrays of char (both char, unsigned char and signed char)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With