5

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) enter image description here

osgx
  • 90,338
  • 53
  • 357
  • 513
Duke Nukem
  • 319
  • 4
  • 15

1 Answers1

3

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 call alloca, 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 the stack_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)

Community
  • 1
  • 1
osgx
  • 90,338
  • 53
  • 357
  • 513
  • Thanks, I need a little time to understand everything in your answer. I thought that `-fstack-protect` was only about adding canary into the stack in order to prevent stack based overflow.by checking if that canary was overwritten. Can you confirm me that with `-fno-stack-protector` the order of the variable declared on the stack is conform at the declaration order in the source file? – Duke Nukem Jul 24 '16 at 10:04
  • `-fstack-protector` / `-fno-stack-protector` may (and will) change order of variables on the stack. You have the test, just compile it with `-fno-stack-protector` and check order. If my answer solves your problem, you may accept it by clicking "v"-shaped Accept button, or you may wait for other answers. – osgx Jul 24 '16 at 18:43
  • Ok. So if I understand well, order of variables on the stack may change even if we set `-fno-stack-protection` right? I can't check it at this moment but as soon as I can I will. Thanks – Duke Nukem Jul 25 '16 at 06:47
  • Order of variables on stack will change with `-fstack-protector`, and probably will not with `-fno-stack-protector`. The default is configured when gcc is build (or installed) into the system. – osgx Jul 25 '16 at 09:45