libsanitizer: mid-end: Introduce stack variable handling for HWASAN
Handling stack variables has three features.
1) Ensure HWASAN required alignment for stack variables
When tagging shadow memory, we need to ensure that each tag granule is
only used by one variable at a time.
This is done by ensuring that each tagged variable is aligned to the tag
granule representation size and also ensure that the end of each
object is aligned to ensure the start of any other data stored on the
stack is in a different granule.
This patch ensures the above by forcing the stack pointer to be aligned
before and after allocating any stack objects. Since we are forcing
alignment we also use `align_local_variable` to ensure this new alignment
is advertised properly through SET_DECL_ALIGN.
2) Put tags into each stack variable pointer
Make sure that every pointer to a stack variable includes a tag of some
sort on it.
The way tagging works is:
1) For every new stack frame, a random tag is generated.
2) A base register is formed from the stack pointer value and this
random tag.
3) References to stack variables are now formed with RTL describing an
offset from this base in both tag and value.
The random tag generation is handled by a backend hook. This hook
decides whether to introduce a random tag or use the stack background
based on the parameter hwasan-random-frame-tag. Using the stack
background is necessary for testing and bootstrap. It is necessary
during bootstrap to avoid breaking the `configure` test program for
determining stack direction.
Using the stack background means that every stack frame has the initial
tag of zero and variables are tagged with incrementing tags from 1,
which also makes debugging a bit easier.
Backend hooks define the size of a tag, the layout of the HWASAN shadow
memory, and handle emitting the code that inserts and extracts tags from a
pointer.
3) For each stack variable, tag and untag the shadow stack on function
prologue and epilogue.
On entry to each function we tag the relevant shadow stack region for
each stack variable. This stack region is tagged to match the tag added to
each pointer to that variable.
This is the first patch where we use the HWASAN shadow space, so we need
to add in the libhwasan initialisation code that creates this shadow
memory region into the binary we produce. This instrumentation is done
in `compile_file`.
When exiting a function we need to ensure the shadow stack for this
function has no remaining tags. Without clearing the shadow stack area
for this stack frame, later function calls could get false positives
when those later function calls check untagged areas (such as parameters
passed on the stack) against a shadow stack area with left-over tag.
Hence we ensure that the entire stack frame is cleared on function exit.
config/ChangeLog:
* bootstrap-hwasan.mk: Disable random frame tags for stack-tagging
during bootstrap.
gcc/ChangeLog:
* asan.c (struct hwasan_stack_var): New.
(hwasan_sanitize_p): New.
(hwasan_sanitize_stack_p): New.
(hwasan_sanitize_allocas_p): New.
(initialize_sanitizer_builtins): Define new builtins.
(ATTR_NOTHROW_LIST): New macro.
(hwasan_current_frame_tag): New.
(hwasan_frame_base): New.
(stack_vars_base_reg_p): New.
(hwasan_maybe_init_frame_base_init): New.
(hwasan_record_stack_var): New.
(hwasan_get_frame_extent): New.
(hwasan_increment_frame_tag): New.
(hwasan_record_frame_init): New.
(hwasan_emit_prologue): New.
(hwasan_emit_untag_frame): New.
(hwasan_finish_file): New.
(hwasan_truncate_to_tag_size): New.
* asan.h (hwasan_record_frame_init): New declaration.
(hwasan_record_stack_var): New declaration.
(hwasan_emit_prologue): New declaration.
(hwasan_emit_untag_frame): New declaration.
(hwasan_get_frame_extent): New declaration.
(hwasan_maybe_enit_frame_base_init): New declaration.
(hwasan_frame_base): New declaration.
(stack_vars_base_reg_p): New declaration.
(hwasan_current_frame_tag): New declaration.
(hwasan_increment_frame_tag): New declaration.
(hwasan_truncate_to_tag_size): New declaration.
(hwasan_finish_file): New declaration.
(hwasan_sanitize_p): New declaration.
(hwasan_sanitize_stack_p): New declaration.
(hwasan_sanitize_allocas_p): New declaration.
(HWASAN_TAG_SIZE): New macro.
(HWASAN_TAG_GRANULE_SIZE): New macro.
(HWASAN_STACK_BACKGROUND): New macro.
* builtin-types.def (BT_FN_VOID_PTR_UINT8_PTRMODE): New.
* builtins.def (DEF_SANITIZER_BUILTIN): Enable for HWASAN.
* cfgexpand.c (align_local_variable): When using hwasan ensure
alignment to tag granule.
(align_frame_offset): New.
(expand_one_stack_var_at): For hwasan use tag offset.
(expand_stack_vars): Record stack objects for hwasan.
(expand_one_stack_var_1): Record stack objects for hwasan.
(init_vars_expansion): Initialise hwasan state.
(expand_used_vars): Emit hwasan prologue and generate hwasan epilogue.
(pass_expand::execute): Emit hwasan base initialization if needed.
* doc/tm.texi (TARGET_MEMTAG_TAG_SIZE,TARGET_MEMTAG_GRANULE_SIZE,
TARGET_MEMTAG_INSERT_RANDOM_TAG,TARGET_MEMTAG_ADD_TAG,
TARGET_MEMTAG_SET_TAG,TARGET_MEMTAG_EXTRACT_TAG,
TARGET_MEMTAG_UNTAGGED_POINTER): Document new hooks.
* doc/tm.texi.in (TARGET_MEMTAG_TAG_SIZE,TARGET_MEMTAG_GRANULE_SIZE,
TARGET_MEMTAG_INSERT_RANDOM_TAG,TARGET_MEMTAG_ADD_TAG,
TARGET_MEMTAG_SET_TAG,TARGET_MEMTAG_EXTRACT_TAG,
TARGET_MEMTAG_UNTAGGED_POINTER): Document new hooks.
* explow.c (get_dynamic_stack_base): Take new `base` argument.
* explow.h (get_dynamic_stack_base): Take new `base` argument.
* sanitizer.def (BUILT_IN_HWASAN_INIT): New.
(BUILT_IN_HWASAN_TAG_MEM): New.
* target.def (target_memtag_tag_size,target_memtag_granule_size,
target_memtag_insert_random_tag,target_memtag_add_tag,
target_memtag_set_tag,target_memtag_extract_tag,
target_memtag_untagged_pointer): New hooks.
* targhooks.c (HWASAN_SHIFT): New.
(HWASAN_SHIFT_RTX): New.
(default_memtag_tag_size): New default hook.
(default_memtag_granule_size): New default hook.
(default_memtag_insert_random_tag): New default hook.
(default_memtag_add_tag): New default hook.
(default_memtag_set_tag): New default hook.
(default_memtag_extract_tag): New default hook.
(default_memtag_untagged_pointer): New default hook.
* targhooks.h (default_memtag_tag_size): New default hook.
(default_memtag_granule_size): New default hook.
(default_memtag_insert_random_tag): New default hook.
(default_memtag_add_tag): New default hook.
(default_memtag_set_tag): New default hook.
(default_memtag_extract_tag): New default hook.
(default_memtag_untagged_pointer): New default hook.
* toplev.c (compile_file): Call hwasan_finish_file when finished.
15 files changed: