@@ -52,14 +52,16 @@ __hwasan_personality_wrapper(int version, _Unwind_Action actions,
// Here we assume that the frame record appears after any locals. This is not
// required by AAPCS but is a requirement for HWASAN instrumented functions.
if ((actions & _UA_CLEANUP_PHASE) && rc == _URC_CONTINUE_UNWIND) {
+ uptr sp = get_cfa(context);
#if defined(__x86_64__)
uptr fp = get_gr(context, 6); // rbp
#elif defined(__aarch64__)
- uptr fp = get_gr(context, 29); // x29
+ uptr fp = *(uptr *)sp;
+ if (fp == 0)
+ return rc;
#else
#error Unsupported architecture
#endif
- uptr sp = get_cfa(context);
TagMemory(sp, fp - sp, 0);
}
######
gcc/ChangeLog:
2019-11-05 Matthew Malcomson <matthew.malcomson@arm.com>
* asan.c (hwasan_create_personality_thunk): New.
* asan.h (hwasan_create_personality_thunk): New.
* expr.c (get_personality_function): Add special function if
using hwasan.
############### Attachment also inlined for ease of reply ###############
@@ -36,6 +36,7 @@ extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t)
extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
extern bool hwasan_expand_mark_ifn (gimple_stmt_iterator *);
+extern tree hwasan_create_personality_thunk (tree);
extern bool memory_tagging_p (void);
extern bool hwasan_sanitize_stack_p (void);
extern bool gate_hwasan (void);
@@ -260,6 +260,10 @@ hash_set <tree> *asan_used_labels = NULL;
static uint8_t tag_offset = 0;
static rtx hwasan_base_ptr = NULL_RTX;
+static hash_map <uintptr_t, uintptr_t, simple_hashmap_traits<int_hash <uintptr_t, ~0ULL>, uintptr_t> >
+ *hwasan_wrapped_personalities = NULL;
+static tree hwasan_gr_decl = NULL_TREE;
+static tree hwasan_cfa_decl = NULL_TREE;
/* Sets shadow offset to value in string VAL. */
@@ -3951,6 +3955,220 @@ hwasan_tag_init ()
tag_offset = HWASAN_STACK_BACKGROUND + 1;
}
+tree
+hwasan_create_personality_thunk (tree orig_personality_decl)
+{
+ /* Only works with DWARF2 debugging. */
+ /* Create a function called __hwasan_personality_thunk<orig_personality_name>.
+ (should be bare __hwasan_personality_thunk if function has no
+ personality function already).
+ That function should call __hwasan_personality_wrapper with arguments
+ - Same first 5 arguments.
+ - Original personality function argument.
+ - Unwind_GetGR function
+ - Unwind_GetCFA function
+ And then return.
+ TODO the personality_wrapper should be a tail-call. */
+
+ if (! sanitize_flags_p (SANITIZE_HWADDRESS, orig_personality_decl))
+ return orig_personality_decl;
+ if (! hwasan_wrapped_personalities)
+ hwasan_wrapped_personalities = new hash_map<uintptr_t, uintptr_t, simple_hashmap_traits<int_hash <uintptr_t, ~0ULL>, uintptr_t> > (16);
+
+ tree *personality_wrapper
+ = (tree *)hwasan_wrapped_personalities->get
+ ((uintptr_t)orig_personality_decl);
+ if (personality_wrapper)
+ return *personality_wrapper;
+
+
+ const char *name;
+ if (! orig_personality_decl)
+ name = "__hwasan_personality_thunk";
+ else
+ name = ACONCAT (("__hwasan_personality_thunk.",
+ IDENTIFIER_POINTER (DECL_NAME (orig_personality_decl)),
+ NULL));
+
+ /* Create a new function. */
+ tree thunk_type = build_function_type_list (unsigned_type_node,
+ integer_type_node,
+ integer_type_node,
+ long_long_unsigned_type_node,
+ ptr_type_node, ptr_type_node,
+ NULL_TREE);
+ tree thunk_decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+ get_identifier (name), thunk_type);
+ DECL_ARTIFICIAL (thunk_decl) = 1;
+ /* External linkage ??? (NO) */
+ DECL_EXTERNAL (thunk_decl) = 0;
+ /* Visible outside this translation unit??? */
+ TREE_PUBLIC (thunk_decl) = 0;
+ TREE_USED (thunk_decl) = 1;
+ DECL_IGNORED_P (thunk_decl) = 1;
+ DECL_INITIAL (thunk_decl) = make_node (BLOCK);
+ BLOCK_SUPERCONTEXT (DECL_INITIAL (thunk_decl)) = thunk_decl;
+ TREE_USED (DECL_INITIAL (thunk_decl)) = 1;
+ DECL_PRESERVE_P (thunk_decl) = 1;
+ DECL_UNINLINABLE (thunk_decl) = 1;
+ /* Having the `no_sanitize` attribute is partly to ensure the internal
+ function doesn't have a personality attributed to it. */
+ DECL_ATTRIBUTES (thunk_decl)
+ = tree_cons (get_identifier ("no_sanitize"),
+ build_int_cst (unsigned_type_node, SANITIZE_HWADDRESS),
+ DECL_ATTRIBUTES (thunk_decl));
+ /* For arguments:
+ - Create a chain of ..._DECL nodes.
+ - Use DECL_ARGUMENTS (thunk_decl) = that_chain */
+ tree arg[5] = {0};
+ const char* names[5] = {
+ "version",
+ "actions",
+ "exception_class",
+ "unwind_exception",
+ "context"
+ };
+ tree thunk_arg_types = TYPE_ARG_TYPES (thunk_type);
+ for (size_t i = 0; i < 5; i++)
+ {
+ tree type = TREE_VALUE (thunk_arg_types);
+ thunk_arg_types = TREE_CHAIN (thunk_arg_types);
+ arg[i] = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+ get_identifier (names[i]),
+ type);
+ DECL_ARG_TYPE (arg[i]) = type;
+ DECL_CONTEXT (arg[i]) = thunk_decl;
+ DECL_ARTIFICIAL (arg[i]) = 1;
+ TREE_READONLY (arg[i]) = 0;
+ TREE_USED (arg[i]) = 0;
+ }
+
+ tree thunk_decl_chain = NULL_TREE;
+ for (int j = 4; j >= 0; j--)
+ {
+ DECL_CHAIN (arg[j]) = thunk_decl_chain;
+ thunk_decl_chain = arg[j];
+ }
+ DECL_ARGUMENTS (thunk_decl) = thunk_decl_chain;
+
+ tree resdecl
+ = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, unsigned_type_node);
+ DECL_RESULT (thunk_decl) = resdecl;
+ DECL_CONTEXT (resdecl) = thunk_decl;
+
+
+ /* Declaration for the wrapper we want to call (this function is provided in
+ libhwasan). */
+ tree wrap_type = build_function_type_list (unsigned_type_node,
+ integer_type_node,
+ integer_type_node,
+ long_long_unsigned_type_node,
+ ptr_type_node, ptr_type_node,
+ ptr_type_node, ptr_type_node,
+ ptr_type_node, NULL_TREE);
+ tree wrap_decl = build_decl (UNKNOWN_LOCATION,
+ FUNCTION_DECL,
+ get_identifier ("__hwasan_personality_wrapper"),
+ wrap_type);
+ DECL_ARTIFICIAL (wrap_decl) = 1;
+ DECL_EXTERNAL (wrap_decl) = 1;
+ TREE_PUBLIC (wrap_decl) = 1;
+
+ /* Create declarations for the functions we need to provide
+ __hwasan_personality_wrapper. */
+ tree gr_decl;
+ if (hwasan_gr_decl)
+ gr_decl = hwasan_gr_decl;
+ else
+ {
+ gr_decl = build_decl (UNKNOWN_LOCATION,
+ FUNCTION_DECL,
+ get_identifier ("_Unwind_GetGR"),
+ build_function_type_list (unsigned_type_node,
+ ptr_type_node,
+ integer_type_node,
+ NULL_TREE));
+ DECL_ARTIFICIAL (gr_decl) = 1;
+ DECL_EXTERNAL (gr_decl) = 1;
+ TREE_PUBLIC (gr_decl) = 0;
+ hwasan_gr_decl = gr_decl;
+ }
+
+ tree cfa_decl;
+ if (hwasan_cfa_decl)
+ cfa_decl = hwasan_cfa_decl;
+ else
+ {
+ cfa_decl = build_decl (UNKNOWN_LOCATION,
+ FUNCTION_DECL,
+ get_identifier ("_Unwind_GetCFA"),
+ build_function_type_list (unsigned_type_node,
+ ptr_type_node,
+ NULL_TREE));
+ DECL_ARTIFICIAL (cfa_decl) = 1;
+ DECL_EXTERNAL (cfa_decl) = 1;
+ TREE_PUBLIC (cfa_decl) = 0;
+ hwasan_cfa_decl = cfa_decl;
+ }
+
+ /* The below code partly taken from `cgraph_build_static_ctor_1`.
+ The aim is to create a new function using the gimple statements `body`
+ created above. */
+ tree saved_current_decl = current_function_decl;
+ struct function *old_cfun = cfun;
+
+ current_function_decl = thunk_decl;
+ /* Sets `cfun` to the newly allocated function structure. */
+ allocate_struct_function (thunk_decl, false);
+
+ /* Call the personality wrapper with the personality arguments plus pointers
+ to the relevant unwinder functions.
+ Put that call into the `body` tree that we will assign to the `thunk_decl`
+ function. */
+ tree body = NULL_TREE;
+ tree personality_addr;
+ if (orig_personality_decl)
+ personality_addr = build_fold_addr_expr (orig_personality_decl);
+ else
+ {
+ tree ptr_type = build_pointer_type (TREE_TYPE (thunk_decl));
+ personality_addr = build_int_cst (ptr_type, 0);
+ }
+ tree call_expr = build_call_expr (wrap_decl, 8,
+ /* 5 arguments from personality. */
+ arg[0], arg[1], arg[2],
+ arg[3], arg[4],
+ /* 3 arguments from compilers
+ knowledge. */
+ personality_addr,
+ build_fold_addr_expr (gr_decl),
+ build_fold_addr_expr (cfa_decl));
+ tree ret_assign = build2 (INIT_EXPR, TREE_TYPE (resdecl), resdecl, call_expr);
+ tree return_statement = build1 (RETURN_EXPR, void_type_node, ret_assign);
+ append_to_statement_list (return_statement, &body);
+ DECL_SAVED_TREE (thunk_decl) = body;
+
+ gimplify_function_tree (thunk_decl);
+
+ opt_pass *saved_current_pass = current_pass;
+ cgraph_node::add_new_function (thunk_decl, false);
+ /* We save and restore `current_pass` because the value gets set to NULL
+ somewhere in `add_new_function` and hence we get a segmentation fault
+ later on.
+
+ TODO There"s probably a better way to do this, since I don't see other
+ functions using `cgraph_node::add_new_function` doing this save and
+ restore. */
+ current_pass = saved_current_pass;
+ set_cfun (old_cfun);
+ current_function_decl = saved_current_decl;
+
+ gcc_assert (! hwasan_wrapped_personalities->put
+ ((uintptr_t)orig_personality_decl,
+ (uintptr_t)thunk_decl));
+ return thunk_decl;
+}
+
rtx
hwasan_extract_tag (rtx tagged_pointer)
{
@@ -62,6 +62,7 @@ along with GCC; see the file COPYING3. If not see
#include "ccmp.h"
#include "gimple-fold.h"
#include "rtx-vector-builder.h"
+#include "asan.h"
/* If this is nonzero, we do not bother generating VOLATILE
@@ -12558,10 +12559,35 @@ get_personality_function (tree decl)
tree personality = DECL_FUNCTION_PERSONALITY (decl);
enum eh_personality_kind pk;
- pk = function_needs_eh_personality (DECL_STRUCT_FUNCTION (decl));
+ /* Need to have a personality function on pretty much every function that can
+ allocate stack space for HWASAN. This is because HWASAN needs to clear
+ the shadow stack of every function frame an exception goes through -- no
+ matter whether there is a cleanup to run or not.
+ Hence, if we're compiling with exceptions, and we're sanitizing this
+ function (because if we're not sanitizing this function the frame doesn't
+ have any coloured shadow stack) then we ensure we add a personality
+ function to it. */
+ if (flag_exceptions && sanitize_flags_p (SANITIZE_HWADDRESS, decl))
+ pk = eh_personality_any;
+ else
+ pk = function_needs_eh_personality (DECL_STRUCT_FUNCTION (decl));
+
if (pk == eh_personality_none)
return NULL;
+ /* Want to add a personality routine to every function *except* those that
+ are specially marked. */
+ if (sanitize_flags_p (SANITIZE_HWADDRESS, decl))
+ {
+ /* Set the personality for this function to be a wrapper around whatever
+ the current personality is. If this function has no associated
+ personality then add a personality function to only clear shadow
+ stack. */
+ tree t = DECL_FUNCTION_PERSONALITY (decl);
+ personality = hwasan_create_personality_thunk (t);
+ DECL_FUNCTION_PERSONALITY (decl) = personality;
+ }
+
if (!personality
&& pk == eh_personality_any)
personality = lang_hooks.eh_personality ();