[asan] WIP protection of globals
Xinliang David Li
davidxl@google.com
Tue Oct 16 22:03:00 GMT 2012
On Tue, Oct 16, 2012 at 7:58 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> This is a WIP patch for globals protection.
> I'm not filling names yet and has_dynamic_init is always
> false (wonder how to figure it has_dynamic_init out, especially
> with LTO, TYPE_ADDRESSABLE (TREE_TYPE (decl)) probably isn't it,
> and for more I'm afraid we need a langhook).
>
> --- gcc/varasm.c.jj 2012-10-11 19:10:39.000000000 +0200
> +++ gcc/varasm.c 2012-10-16 15:40:37.075662625 +0200
> @@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.
> #include "tree-mudflap.h"
> #include "cgraph.h"
> #include "pointer-set.h"
> +#include "asan.h"
>
> #ifdef XCOFF_DEBUGGING_INFO
> #include "xcoffout.h" /* Needed for external data
> @@ -1831,6 +1832,9 @@ assemble_noswitch_variable (tree decl, c
> size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
> rounded = size;
>
> + if (flag_asan && asan_protect_global (decl))
> + size += asan_red_zone_size (size);
> +
> /* Don't allocate zero bytes of common,
> since that means "undefined external" in the linker. */
> if (size == 0)
> @@ -1897,6 +1901,7 @@ assemble_variable (tree decl, int top_le
> const char *name;
> rtx decl_rtl, symbol;
> section *sect;
> + bool asan_protected = false;
>
> /* This function is supposed to handle VARIABLES. Ensure we have one. */
> gcc_assert (TREE_CODE (decl) == VAR_DECL);
> @@ -1984,6 +1989,15 @@ assemble_variable (tree decl, int top_le
> /* Compute the alignment of this data. */
>
> align_variable (decl, dont_output_data);
> +
> + if (flag_asan
> + && asan_protect_global (decl)
> + && DECL_ALIGN (decl) < ASAN_RED_ZONE_SIZE * BITS_PER_UNIT)
> + {
> + asan_protected = true;
> + DECL_ALIGN (decl) = ASAN_RED_ZONE_SIZE * BITS_PER_UNIT;
> + }
> +
> set_mem_align (decl_rtl, DECL_ALIGN (decl));
>
> if (TREE_PUBLIC (decl))
> @@ -2022,6 +2036,12 @@ assemble_variable (tree decl, int top_le
> if (DECL_ALIGN (decl) > BITS_PER_UNIT)
> ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
> assemble_variable_contents (decl, name, dont_output_data);
> + if (asan_protected)
> + {
> + unsigned HOST_WIDE_INT int size
> + = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
> + assemble_zeros (asan_red_zone_size (size));
> + }
> }
> }
>
> @@ -6926,6 +6946,8 @@ place_block_symbol (rtx symbol)
> decl = SYMBOL_REF_DECL (symbol);
> alignment = DECL_ALIGN (decl);
> size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
> + if (flag_asan && asan_protect_global (decl))
> + size += asan_red_zone_size (size);
> }
>
> /* Calculate the object's offset from the start of the block. */
> --- gcc/Makefile.in.jj 2012-10-15 09:40:40.000000000 +0200
> +++ gcc/Makefile.in 2012-10-16 16:54:12.463712014 +0200
> @@ -2712,7 +2712,7 @@ varasm.o : varasm.c $(CONFIG_H) $(SYSTEM
> output.h $(DIAGNOSTIC_CORE_H) xcoffout.h debug.h $(GGC_H) $(TM_P_H) \
> $(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h $(BASIC_BLOCK_H) \
> $(CGRAPH_H) $(TARGET_DEF_H) tree-mudflap.h \
> - pointer-set.h $(COMMON_TARGET_H)
> + pointer-set.h $(COMMON_TARGET_H) asan.h
> function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ERROR_H) \
> $(TREE_H) $(GIMPLE_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) \
> $(OPTABS_H) $(LIBFUNCS_H) $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \
> --- gcc/asan.c.jj 2012-10-16 12:18:41.000000000 +0200
> +++ gcc/asan.c 2012-10-16 16:52:24.266434151 +0200
> @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.
> #include "target.h"
> #include "expr.h"
> #include "optabs.h"
> +#include "output.h"
>
> /*
> AddressSanitizer finds out-of-bounds and use-after-free bugs
> @@ -270,6 +271,48 @@ asan_emit_stack_protection (rtx base, HO
> return ret;
> }
>
> +/* Return true if DECL is a VAR_DECL that should be protected
> + by Address Sanitizer, by appending a red zone with protected
> + shadow memory after it and aligning it to at least
> + ASAN_RED_ZONE_SIZE bytes. */
> +
> +bool
> +asan_protect_global (tree decl)
> +{
> + rtx rtl, symbol;
> + section *sect;
> +
> + if (TREE_CODE (decl) != VAR_DECL
> + || DECL_THREAD_LOCAL_P (decl)
> + || DECL_EXTERNAL (decl)
> + || !TREE_ASM_WRITTEN (decl)
> + || !DECL_RTL_SET_P (decl)
> + || DECL_ONE_ONLY (decl)
> + || DECL_COMMON (decl)
Why the above two condition? If the linker picks the larger size one,
it is ok to do the instrumentation.
> + || (DECL_SECTION_NAME (decl) != NULL_TREE
> + && !DECL_HAS_IMPLICIT_SECTION_NAME_P (decl))
Why is this condition? Is it related to -fdata-sections ?
> + || DECL_SIZE (decl) == 0
> + || ASAN_RED_ZONE_SIZE * BITS_PER_UNIT > MAX_OFILE_ALIGNMENT
> + || !valid_constant_size_p (DECL_SIZE_UNIT (decl))
> + || DECL_ALIGN_UNIT (decl) > 2 * ASAN_RED_ZONE_SIZE)
> + return false;
> +
> + rtl = DECL_RTL (decl);
> + if (!MEM_P (rtl) || GET_CODE (XEXP (rtl, 0)) != SYMBOL_REF)
> + return false;
> + symbol = XEXP (rtl, 0);
> +
> + if (CONSTANT_POOL_ADDRESS_P (symbol)
> + || TREE_CONSTANT_POOL_ADDRESS_P (symbol))
> + return false;
> +
> + sect = get_variable_section (decl, false);
> + if (sect->common.flags & SECTION_COMMON)
> + return false;
> +
> + return true;
> +}
> +
> /* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16}.
> IS_STORE is either 1 (for a store) or 0 (for a load).
> SIZE_IN_BYTES is one of 1, 2, 4, 8, 16. */
> @@ -568,6 +611,55 @@ transform_statements (void)
> }
> }
>
> +/* Build __asan_global type. */
> +
More description of the global type.
> +static tree
> +asan_global_struct (void)
> +{
> + static const char *field_names[5]
> + = { "__beg", "__size", "__size_with_redzone",
> + "__name", "__has_dynamic_init" };
> + tree fields[5], ret;
> + int i;
> +
> + ret = make_node (RECORD_TYPE);
> + for (i = 0; i < 5; i++)
> + {
> + fields[i]
> + = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
> + get_identifier (field_names[i]),
> + (i == 0 || i == 3) ? const_ptr_type_node
> + : build_nonstandard_integer_type (POINTER_SIZE, 1));
> + DECL_CONTEXT (fields[i]) = ret;
> + if (i)
> + DECL_CHAIN (fields[i - 1]) = fields[i];
> + }
> + TYPE_FIELDS (ret) = fields[0];
> + TYPE_NAME (ret) = get_identifier ("__asan_global");
> + layout_type (ret);
> + return ret;
> +}
> +
> +static void
> +asan_add_global (tree decl, tree type, VEC(constructor_elt, gc) *v)
> +{
Missing comments.
> + tree init, uptr = TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (type)));
> + unsigned HOST_WIDE_INT size;
> + VEC(constructor_elt, gc) *vinner = NULL;
> + CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
> + fold_convert (const_ptr_type_node,
> + build_fold_addr_expr (decl)));
> + size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
> + CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
> + size += asan_red_zone_size (size);
> + CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, size));
> + CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE,
> + build_int_cst (const_ptr_type_node, 0));
> + CONSTRUCTOR_APPEND_ELT (vinner, NULL_TREE, build_int_cst (uptr, 0));
> + init = build_constructor (type, vinner);
> + CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, init);
> +}
> +
David
> /* Module-level instrumentation.
> - Insert __asan_init() into the list of CTORs.
> - TODO: insert redzones around globals.
> @@ -577,8 +669,59 @@ void
> asan_finish_file (void)
> {
> tree ctor_statements = NULL_TREE;
> + struct varpool_node *vnode;
> + unsigned HOST_WIDE_INT gcount = 0;
> +
> append_to_statement_list (build_call_expr (asan_init_func (), 0),
> &ctor_statements);
> + FOR_EACH_DEFINED_VARIABLE (vnode)
> + if (asan_protect_global (vnode->symbol.decl))
> + ++gcount;
> + if (gcount)
> + {
> + tree type = asan_global_struct (), var, ctor, decl;
> + tree uptr = build_nonstandard_integer_type (POINTER_SIZE, 1);
> + tree dtor_statements = NULL_TREE;
> + VEC(constructor_elt, gc) *v;
> + char buf[20];
> +
> + type = build_array_type_nelts (type, gcount);
> + ASM_GENERATE_INTERNAL_LABEL (buf, "LASAN", 0);
> + var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (buf),
> + type);
> + TREE_STATIC (var) = 1;
> + TREE_PUBLIC (var) = 0;
> + DECL_ARTIFICIAL (var) = 1;
> + DECL_IGNORED_P (var) = 1;
> + v = VEC_alloc (constructor_elt, gc, gcount);
> + FOR_EACH_DEFINED_VARIABLE (vnode)
> + if (asan_protect_global (vnode->symbol.decl))
> + asan_add_global (vnode->symbol.decl, TREE_TYPE (type), v);
> + ctor = build_constructor (type, v);
> + TREE_CONSTANT (ctor) = 1;
> + TREE_STATIC (ctor) = 1;
> + DECL_INITIAL (var) = ctor;
> + varpool_assemble_decl (varpool_node (var));
> +
> + type = build_function_type_list (void_type_node,
> + build_pointer_type (TREE_TYPE (type)),
> + uptr, NULL_TREE);
> + decl = build_fn_decl ("__asan_register_globals", type);
> + TREE_NOTHROW (decl) = 1;
> + append_to_statement_list (build_call_expr (decl, 2,
> + build_fold_addr_expr (var),
> + build_int_cst (uptr, gcount)),
> + &ctor_statements);
> +
> + decl = build_fn_decl ("__asan_unregister_globals", type);
> + TREE_NOTHROW (decl) = 1;
> + append_to_statement_list (build_call_expr (decl, 2,
> + build_fold_addr_expr (var),
> + build_int_cst (uptr, gcount)),
> + &dtor_statements);
> + cgraph_build_static_cdtor ('D', dtor_statements,
> + MAX_RESERVED_INIT_PRIORITY - 1);
> + }
> cgraph_build_static_cdtor ('I', ctor_statements,
> MAX_RESERVED_INIT_PRIORITY - 1);
> }
> --- gcc/asan.h.jj 2012-10-15 09:40:03.000000000 +0200
> +++ gcc/asan.h 2012-10-16 15:38:30.850358396 +0200
> @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.
>
> extern void asan_finish_file (void);
> extern rtx asan_emit_stack_protection (rtx, HOST_WIDE_INT *, tree *, int);
> +extern bool asan_protect_global (tree);
>
> /* Alias set for accessing the shadow memory. */
> extern alias_set_type asan_shadow_set;
> @@ -48,4 +49,11 @@ extern alias_set_type asan_shadow_set;
>
> #define ASAN_STACK_FRAME_MAGIC 0x41b58ab3
>
> +static inline unsigned int
> +asan_red_zone_size (unsigned int size)
> +{
> + unsigned int c = size & (ASAN_RED_ZONE_SIZE - 1);
> + return c ? 2 * ASAN_RED_ZONE_SIZE - c : ASAN_RED_ZONE_SIZE;
> +}
> +
> #endif /* TREE_ASAN */
>
> Jakub
More information about the Gcc-patches
mailing list