/* * Copyright 2014-2016 by Open Source Security, Inc., Brad Spengler <spender@grsecurity.net> * and PaX Team <pageexec@freemail.hu> * 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 * * Usage: * $ # for 4.5/4.6/C based 4.7 * $ gcc -I`gcc -print-file-name=plugin`/include -I`gcc -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o randomize_layout_plugin.so randomize_layout_plugin.c * $ # for C++ based 4.7/4.8+ * $ g++ -I`g++ -print-file-name=plugin`/include -I`g++ -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o randomize_layout_plugin.so randomize_layout_plugin.c * $ gcc -fplugin=./randomize_layout_plugin.so test.c -O2
*/
/* from old Linux dcache.h */ staticinlineunsignedlong
partial_name_hash(unsignedlong c, unsignedlong prevhash)
{ return (prevhash + (c << 4) + (c >> 4)) * 11;
} staticinlineunsignedint
name_hash(constunsignedchar *name)
{ unsignedlong hash = 0; unsignedint len = strlen((constchar *)name); while (len--)
hash = partial_name_hash(*name++, hash); return (unsignedint)hash;
}
static tree handle_randomize_layout_attr(tree *node, tree name, tree args, int flags, bool*no_add_attrs)
{
tree type;
*no_add_attrs = true; if (TREE_CODE(*node) == FUNCTION_DECL) {
error("%qE attribute does not apply to functions (%qF)", name, *node); return NULL_TREE;
}
if (TREE_CODE(*node) == PARM_DECL) {
error("%qE attribute does not apply to function parameters (%qD)", name, *node); return NULL_TREE;
}
if (TREE_CODE(*node) == VAR_DECL) {
error("%qE attribute does not apply to variables (%qD)", name, *node); return NULL_TREE;
}
if (TYPE_P(*node)) {
type = *node;
} elseif (TREE_CODE(*node) == FIELD_DECL) {
*no_add_attrs = false; return NULL_TREE;
} else {
gcc_assert(TREE_CODE(*node) == TYPE_DECL);
type = TREE_TYPE(*node);
}
if (TREE_CODE(type) != RECORD_TYPE) {
error("%qE attribute used on %qT applies to struct types only", name, type); return NULL_TREE;
}
if (lookup_attribute(IDENTIFIER_POINTER(name), TYPE_ATTRIBUTES(type))) {
error("%qE attribute is already applied to the type %qT", name, type); return NULL_TREE;
}
*no_add_attrs = false;
return NULL_TREE;
}
/* set on complete types that we don't need to inspect further at all */ static tree handle_randomize_considered_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
{
*no_add_attrs = false; return NULL_TREE;
}
/* * set on types that we've performed a shuffle on, to prevent re-shuffling * this does not preclude us from inspecting its fields for potential shuffles
*/ static tree handle_randomize_performed_attr(tree *node, tree name, tree args, int flags, bool *no_add_attrs)
{
*no_add_attrs = false; return NULL_TREE;
}
/* * 64bit variant of Bob Jenkins' public domain PRNG * 256 bits of internal state
*/
/* FIXME: this group shuffle is currently a no-op. */ for (i = num_groups - 1; i > 0; i--) { struct partition_group tmp;
randnum = ranval(prng_state) % (i + 1);
tmp = size_group[i];
size_group[i] = size_group[randnum];
size_group[randnum] = tmp;
}
for (x = 0; x < num_groups; x++) { for (index = size_group[x].length - 1; index > 0; index--) {
tree tmp;
i = size_group[x].start + index; if (DECL_BIT_FIELD_TYPE(newtree[i])) continue;
randnum = ranval(prng_state) % (index + 1);
randnum += size_group[x].start; // we could handle this case differently if desired if (DECL_BIT_FIELD_TYPE(newtree[randnum])) continue;
tmp = newtree[i];
newtree[i] = newtree[randnum];
newtree[randnum] = tmp;
}
}
}
staticint relayout_struct(tree type)
{ unsignedlong num_fields = (unsignedlong)list_length(TYPE_FIELDS(type)); unsignedlong shuffle_length = num_fields;
tree field;
tree newtree[num_fields]; unsignedlong i;
tree list;
tree variant;
tree main_variant;
expanded_location xloc; bool has_flexarray = false;
if (TYPE_FIELDS(type) == NULL_TREE) return 0;
if (num_fields < 2) return 0;
gcc_assert(TREE_CODE(type) == RECORD_TYPE);
gcc_assert(num_fields < INT_MAX);
if (lookup_attribute("randomize_performed", TYPE_ATTRIBUTES(type)) ||
lookup_attribute("no_randomize_layout", TYPE_ATTRIBUTES(TYPE_MAIN_VARIANT(type)))) return 0;
/* Workaround for 3rd-party VirtualBox source that we can't modify ourselves */ if (!strcmp((constchar *)ORIG_TYPE_NAME(type), "INTNETTRUNKFACTORY") ||
!strcmp((constchar *)ORIG_TYPE_NAME(type), "RAWPCIFACTORY")) return 0;
/* throw out any structs in uapi */
xloc = expand_location(DECL_SOURCE_LOCATION(TYPE_FIELDS(type)));
if (strstr(xloc.file, "/uapi/"))
error(G_("attempted to randomize userland API struct %s"), ORIG_TYPE_NAME(type));
for (field = TYPE_FIELDS(type), i = 0; field; field = TREE_CHAIN(field), i++) {
gcc_assert(TREE_CODE(field) == FIELD_DECL);
newtree[i] = field;
}
/* * enforce that we don't randomize the layout of the last * element of a struct if it's a proper flexible array
*/ if (is_flexible_array(newtree[num_fields - 1])) {
has_flexarray = true;
shuffle_length--;
}
shuffle(type, (tree *)newtree, shuffle_length);
for (i = 0; i < num_fields - 1; i++)
TREE_CHAIN(newtree[i]) = newtree[i+1];
TREE_CHAIN(newtree[num_fields - 1]) = NULL_TREE;
/* * force a re-layout of the main variant * the TYPE_SIZE for all variants will be recomputed * by finalize_type_size()
*/
TYPE_SIZE(main_variant) = NULL_TREE;
layout_type(main_variant);
gcc_assert(TYPE_SIZE(main_variant) != NULL_TREE);
/* pipacs' plugin creates franken-arrays that differ from those produced by
normal code which all have valid 'field' trees. work around this */ if (field == NULL_TREE) continue;
field_type = TREE_TYPE(field);
val_type = TREE_TYPE(val);
if (TREE_CODE(field_type) != POINTER_TYPE || TREE_CODE(val_type) != POINTER_TYPE) continue;
dom = get_immediate_dominator(CDI_DOMINATORS, bb); if (!dom) returnfalse;
dom_stmt = last_stmt(dom); if (!dom_stmt) returnfalse;
if (gimple_code(dom_stmt) != GIMPLE_COND) returnfalse;
if (gimple_cond_code(dom_stmt) != NE_EXPR) returnfalse;
if (!integer_zerop(gimple_cond_rhs(dom_stmt))) returnfalse;
poss_is_err_cond = gimple_cond_lhs(dom_stmt);
if (TREE_CODE(poss_is_err_cond) != SSA_NAME) returnfalse;
call_stmt = SSA_NAME_DEF_STMT(poss_is_err_cond);
if (gimple_code(call_stmt) != GIMPLE_CALL) returnfalse;
dom_lhs = gimple_get_lhs(call_stmt);
poss_is_err_func = gimple_call_fndecl(call_stmt); if (!poss_is_err_func) returnfalse; if (dom_lhs != poss_is_err_cond) returnfalse; if (strcmp(DECL_NAME_POINTER(poss_is_err_func), "IS_ERR")) returnfalse;
is_err_arg = gimple_call_arg(call_stmt, 0); if (!is_err_arg) returnfalse;
if (is_err_arg != rhs) returnfalse;
returntrue;
}
staticvoid handle_local_var_initializers(void)
{
tree var; unsignedint i;
FOR_EACH_LOCAL_DECL(cfun, i, var) {
tree init = DECL_INITIAL(var); if (!init) continue; if (TREE_CODE(init) != CONSTRUCTOR) continue;
check_bad_casts_in_constructor(var, init);
}
}
/* * iterate over all statements to find "bad" casts: * those where the address of the start of a structure is cast * to a pointer of a structure of a different type, or a * structure pointer type is cast to a different structure pointer type
*/ staticunsignedint find_bad_casts_execute(void)
{
basic_block bb;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.