GNU C Compiler Internals/Stackguard 4 1
Stackguard is implemented in the following files.
These files translates GIMPLE to RTL.They take advantage of the CFG to instrument function prolog and epilog.
1) cfgexpand.c
Stackguard is created in function expand_used_vars(). Depending on stackguard flag either all arrays or character arrays only are allocated first.
tree_expand_cfg() takes care of prolog when it calls stack_protect_prologue(). The corresponding function stack_protect_epilogue() is called from calls.c to take care of tail calls and from tree_expand_cfg();
2) function.c
stack_protect_prologue(), stack_protect_epilogue()
The functions use machine definition targetm.
3) targhooks.c
Contains default initializers of target architecture hooks.
default_stack_protect_guard() builds a VAR_DECL tree node that represents variable __stack_chk_guard.
default_stack_protector_fail() builds a call to function __stack_chk_fail().
These ASTs are converted into RTL trees using expand_expr_stmt(). The prolog and epilog functions add RTL expressions directly as well. For example, to detect a compromise function epilog generates a conditional statement that compares the canary word on the stack with its initial value:
emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label);
where x and y are corresponding declaration RTLs:
x = validize_mem (DECL_RTL (cfun->stack_protect_guard)); y = validize_mem (DECL_RTL (guard_decl));
Stackguard implements a certain amount of static analysis to make sure that suspicious functions with arguments of fixed length do not have vulnerabilities. The underlying mechanism is that of builtins. Stackguard has file strcpy.h that defines functions of interest, for example strcpy(). The new definition uses builtins __ssp_bos() to find out object size and __builtin___strcpy_chk():
- define __ssp_bos(ptr) __builtin_object_size (ptr, __SSP_FORTIFY_LEVEL > 1)
- define strcpy(dest, src) \
((__ssp_bos (dest) != (size_t) -1) \ ? __builtin___strcpy_chk (dest, src, __ssp_bos (dest)) \ : __strcpy_ichk (dest, src))
The builtins are evaluated at compile time. Function warning() called in maybe_emit_chk_warning() prints out a message if the destination buffer is overflown.
In case when Stackguard is unable to find out statically if the buffer is overrun function __strcpy_chk() is called at run-time. Library libssp provides the function. However, the protected program does not require linking with this library explicitly. Instead, GCC instructs the loader to use a shared library.