Select Git revision
stackleak_plugin.c
stackleak_plugin.c 12.61 KiB
/*
* Copyright 2011-2017 by the PaX Team <pageexec@freemail.hu>
* Modified by Alexander Popov <alex.popov@linux.com>
* Licensed under the GPL v2
*
* Note: the choice of the license means that the compilation process is
* NOT 'eligible' as defined by gcc's library exception to the GPL v3,
* but for the kernel it doesn't matter since it doesn't link against
* any of the gcc libraries
*
* This gcc plugin is needed for tracking the lowest border of the kernel stack.
* It instruments the kernel code inserting stackleak_track_stack() calls:
* - after alloca();
* - for the functions with a stack frame size greater than or equal
* to the "track-min-size" plugin parameter.
*
* This plugin is ported from grsecurity/PaX. For more information see:
* https://grsecurity.net/
* https://pax.grsecurity.net/
*
* Debugging:
* - use fprintf() to stderr, debug_generic_expr(), debug_gimple_stmt(),
* print_rtl() and print_simple_rtl();
* - add "-fdump-tree-all -fdump-rtl-all" to the plugin CFLAGS in
* Makefile.gcc-plugins to see the verbose dumps of the gcc passes;
* - use gcc -E to understand the preprocessing shenanigans;
* - use gcc with enabled CFG/GIMPLE/SSA verification (--enable-checking).
*/
#include "gcc-common.h"
__visible int plugin_is_GPL_compatible;
static int track_frame_size = -1;
static const char track_function[] = "stackleak_track_stack";
/*
* Mark these global variables (roots) for gcc garbage collector since
* they point to the garbage-collected memory.
*/
static GTY(()) tree track_function_decl;
static struct plugin_info stackleak_plugin_info = {
.version = "201707101337",
.help = "track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n"
"disable\t\tdo not activate the plugin\n"
};
static void stackleak_add_track_stack(gimple_stmt_iterator *gsi, bool after)
{
gimple stmt;
gcall *stackleak_track_stack;
cgraph_node_ptr node;
basic_block bb;
/* Insert call to void stackleak_track_stack(void) */
stmt = gimple_build_call(track_function_decl, 0);
stackleak_track_stack = as_a_gcall(stmt);
if (after) {
gsi_insert_after(gsi, stackleak_track_stack,
GSI_CONTINUE_LINKING);
} else {
gsi_insert_before(gsi, stackleak_track_stack, GSI_SAME_STMT);
}
/* Update the cgraph */
bb = gimple_bb(stackleak_track_stack);
node = cgraph_get_create_node(track_function_decl);
gcc_assert(node);
cgraph_create_edge(cgraph_get_node(current_function_decl), node,