From patchwork Tue Oct 16 14:58:48 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 191821 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 4E5542C0098 for ; Wed, 17 Oct 2012 02:27:49 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1351006070; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Received:Resent-From:Resent-Date:Resent-Message-ID: Resent-To:Date:From:To:Cc:Subject:Message-ID:Reply-To: MIME-Version:Content-Type:Content-Disposition:User-Agent: Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:Sender:Delivered-To; bh=uydXYYWJ5fBEMmb/I6e1 DOuIRYI=; b=GCoKiRpM94glENcbLKE/8/yqwRbEBzGJd0vPJ4LxqhCvOsj7kOWs Vv2QTljZF59VuMGyD55+UQD0yEu7dMW2PFUnIptkEHQPP9UV74w4ouy9fZcCFQqz 4klw9B8I8sbD9oyCCDd06TXLh8KodbL5SWJorxyE3YQqTGOPeXjQS9E= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:Received:Resent-From:Resent-Date:Resent-Message-ID:Resent-To:Date:From:To:Cc:Subject:Message-ID:Reply-To:MIME-Version:Content-Type:Content-Disposition:User-Agent:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=TkzamBLRQU2m/ko8NxKqY4TDAp/Tb3AN/5XTtwJ3fztDITXUgU8Je1NMkEFJYQ vyzIo52mDdOluoLz/BK5+lpDO69oCxyiIx6m2cC44S9u7Gte7KpIqN+uWDxQSAoP RcyiQkdydoG6wgxZ4jX0Eo+NsNwZUjMsbMxzMyN64/Wr0=; Received: (qmail 32109 invoked by alias); 16 Oct 2012 15:27:44 -0000 Received: (qmail 32101 invoked by uid 22791); 16 Oct 2012 15:27:44 -0000 X-SWARE-Spam-Status: No, hits=-5.8 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, KHOP_RCVD_UNTRUST, RCVD_IN_DNSWL_HI, RCVD_IN_HOSTKARMA_W, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 16 Oct 2012 15:27:38 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q9GFRcKK004217 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 16 Oct 2012 11:27:38 -0400 Received: from zalov.redhat.com (vpn1-7-73.ams2.redhat.com [10.36.7.73]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q9GFRaKN011622 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 16 Oct 2012 11:27:37 -0400 Received: from zalov.cz (localhost [127.0.0.1]) by zalov.redhat.com (8.14.5/8.14.5) with ESMTP id q9GFRZUP006024; Tue, 16 Oct 2012 17:27:35 +0200 Received: (from jakub@localhost) by zalov.cz (8.14.5/8.14.5/Submit) id q9GFRZ1s006023; Tue, 16 Oct 2012 17:27:35 +0200 Resent-From: Jakub Jelinek Resent-Date: Tue, 16 Oct 2012 17:27:35 +0200 Resent-Message-ID: <20121016152735.GQ1727@tucnak.redhat.com> Resent-To: Diego Novillo , Dodji Seketeli , Xinliang David Li , gcc-patches@gcc.gnu.org, Wei Mi Date: Tue, 16 Oct 2012 16:58:48 +0200 From: Jakub Jelinek To: Diego Novillo , Dodji Seketeli , Xinliang David Li Cc: gcc-patches@gcc.gnu.org, Wei Mi Subject: [asan] WIP protection of globals Message-ID: <20121016145848.GH584@tucnak.redhat.com> Reply-To: Jakub Jelinek MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.21 (2010-09-15) X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org 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). Jakub --- 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) + || (DECL_SECTION_NAME (decl) != NULL_TREE + && !DECL_HAS_IMPLICIT_SECTION_NAME_P (decl)) + || 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. */ + +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) +{ + 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); +} + /* 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 */