From: Matthew Malcomson Date: Wed, 25 Nov 2020 16:31:43 +0000 (+0000) Subject: libsanitizer: options: Add hwasan flags and argument parsing X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3bd8783207760cc805d8a4e64e5ac92ca508a711;p=gcc.git libsanitizer: options: Add hwasan flags and argument parsing These flags can't be used at the same time as any of the other sanitizers. We add an equivalent flag to -static-libasan in -static-libhwasan to ensure static linking. The -fsanitize=kernel-hwaddress option is for compiling targeting the kernel. This flag has defaults to match the LLVM implementation and sets some other behaviors to work in the kernel (e.g. accounting for the fact that the stack pointer will have 0xff in the top byte and to not call the userspace library initialisation routines). The defaults are that we do not sanitize variables on the stack and always recover from a detected bug. Since we are introducing a few more conflicts between sanitizer flags we refactor the checking for such conflicts to use a helper function which makes checking for such conflicts more easy and consistent. We introduce a backend hook `targetm.memtag.can_tag_addresses` that indicates to the mid-end whether a target has a feature like AArch64 TBI where the top byte of an address is ignored. Without this feature hwasan sanitization is not done. gcc/ChangeLog: * common.opt (flag_sanitize_recover): Default for kernel hwaddress. (static-libhwasan): New cli option. * config/aarch64/aarch64.c (aarch64_can_tag_addresses): New. (TARGET_MEMTAG_CAN_TAG_ADDRESSES): New. * config/gnu-user.h (LIBHWASAN_EARLY_SPEC): hwasan equivalent of asan command line flags. * cppbuiltin.c (define_builtin_macros_for_compilation_flags): Add hwasan equivalent of __SANITIZE_ADDRESS__. * doc/invoke.texi: Document hwasan command line flags. * doc/tm.texi: Document new hook. * doc/tm.texi.in: Document new hook. * flag-types.h (enum sanitize_code): New sanitizer values. * gcc.c (STATIC_LIBHWASAN_LIBS): New macro. (LIBHWASAN_SPEC): New macro. (LIBHWASAN_EARLY_SPEC): New macro. (SANITIZER_EARLY_SPEC): Update to include hwasan. (SANITIZER_SPEC): Update to include hwasan. (sanitize_spec_function): Use hwasan options. * opts.c (finish_options): Describe conflicts between address sanitizers. (find_sanitizer_argument): New. (report_conflicting_sanitizer_options): New. (sanitizer_opts): Introduce new sanitizer flags. (common_handle_option): Add defaults for kernel sanitizer. * params.opt (hwasan--instrument-stack): New (hwasan-random-frame-tag): New (hwasan-instrument-allocas): New (hwasan-instrument-reads): New (hwasan-instrument-writes): New (hwasan-instrument-mem-intrinsics): New * target.def (HOOK_PREFIX): Add new hook. (can_tag_addresses): Add new hook under memtag prefix. * targhooks.c (default_memtag_can_tag_addresses): New. * targhooks.h (default_memtag_can_tag_addresses): New decl. * toplev.c (process_options): Ensure hwasan only on architectures that advertise the possibility. --- diff --git a/gcc/common.opt b/gcc/common.opt index ca8a2690799..582e2aa8774 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -218,7 +218,7 @@ unsigned int flag_sanitize ; What sanitizers should recover from errors Variable -unsigned int flag_sanitize_recover = (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT | SANITIZE_KERNEL_ADDRESS) & ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN) +unsigned int flag_sanitize_recover = (SANITIZE_UNDEFINED | SANITIZE_UNDEFINED_NONDEFAULT | SANITIZE_KERNEL_ADDRESS | SANITIZE_KERNEL_HWADDRESS) & ~(SANITIZE_UNREACHABLE | SANITIZE_RETURN) ; What the coverage sanitizers should instrument Variable @@ -3448,6 +3448,9 @@ Driver static-libasan Driver +static-libhwasan +Driver + static-libtsan Driver diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 3189dfb90f9..140ee79679a 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -23321,6 +23321,15 @@ aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1, return NULL; } +/* Implement TARGET_MEMTAG_CAN_TAG_ADDRESSES. Here we tell the rest of the + compiler that we automatically ignore the top byte of our pointers, which + allows using -fsanitize=hwaddress. */ +bool +aarch64_can_tag_addresses () +{ + return !TARGET_ILP32; +} + /* Implement TARGET_ASM_FILE_END for AArch64. This adds the AArch64 GNU NOTE section at the end if needed. */ #define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000 @@ -24140,6 +24149,9 @@ aarch64_libgcc_floating_mode_supported_p #undef TARGET_FNTYPE_ABI #define TARGET_FNTYPE_ABI aarch64_fntype_abi +#undef TARGET_MEMTAG_CAN_TAG_ADDRESSES +#define TARGET_MEMTAG_CAN_TAG_ADDRESSES aarch64_can_tag_addresses + #if CHECKING_P #undef TARGET_RUN_TARGET_SELFTESTS #define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h index ff2e880b1fa..92950245e2b 100644 --- a/gcc/config/gnu-user.h +++ b/gcc/config/gnu-user.h @@ -129,14 +129,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see /* Link -lasan early on the command line. For -static-libasan, don't link it for -shared link, the executable should be compiled with -static-libasan in that case, and for executable link with --{,no-}whole-archive around - it to force everything into the executable. And similarly for -ltsan - and -llsan. */ + it to force everything into the executable. And similarly for -ltsan, + -lhwasan, and -llsan. */ #if defined(HAVE_LD_STATIC_DYNAMIC) #undef LIBASAN_EARLY_SPEC #define LIBASAN_EARLY_SPEC "%{!shared:libasan_preinit%O%s} " \ "%{static-libasan:%{!shared:" \ LD_STATIC_OPTION " --whole-archive -lasan --no-whole-archive " \ LD_DYNAMIC_OPTION "}}%{!static-libasan:-lasan}" +#undef LIBHWASAN_EARLY_SPEC +#define LIBHWASAN_EARLY_SPEC "%{static-libhwasan:%{!shared:" \ + LD_STATIC_OPTION " --whole-archive -lhwasan --no-whole-archive " \ + LD_DYNAMIC_OPTION "}}%{!static-libhwasan:-lhwasan}" #undef LIBTSAN_EARLY_SPEC #define LIBTSAN_EARLY_SPEC "%{!shared:libtsan_preinit%O%s} " \ "%{static-libtsan:%{!shared:" \ diff --git a/gcc/cppbuiltin.c b/gcc/cppbuiltin.c index 61efe9b2b75..fc61c78a993 100644 --- a/gcc/cppbuiltin.c +++ b/gcc/cppbuiltin.c @@ -93,6 +93,9 @@ define_builtin_macros_for_compilation_flags (cpp_reader *pfile) if (flag_sanitize & SANITIZE_ADDRESS) cpp_define (pfile, "__SANITIZE_ADDRESS__"); + if (flag_sanitize & SANITIZE_HWADDRESS) + cpp_define (pfile, "__SANITIZE_HWADDRESS__"); + if (flag_sanitize & SANITIZE_THREAD) cpp_define (pfile, "__SANITIZE_THREAD__"); diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 26372a2435a..0621d47f44a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -13829,6 +13829,53 @@ is greater or equal to this number, use callbacks instead of inline checks. E.g. to disable inline code use @option{--param asan-instrumentation-with-call-threshold=0}. +@item hwasan-instrument-stack +Enable hwasan instrumentation of statically sized stack-allocated variables. +This kind of instrumentation is enabled by default when using +@option{-fsanitize=hwaddress} and disabled by default when using +@option{-fsanitize=kernel-hwaddress}. +To disable stack instrumentation use +@option{--param hwasan-instrument-stack=0}, and to enable it use +@option{--param hwasan-instrument-stack=1}. + +@item hwasan-random-frame-tag +When using stack instrumentation, decide tags for stack variables using a +deterministic sequence beginning at a random tag for each frame. With this +parameter unset tags are chosen using the same sequence but beginning from 1. +This is enabled by default for @option{-fsanitize=hwaddress} and unavailable +for @option{-fsanitize=kernel-hwaddress}. +To disable it use @option{--param hwasan-random-frame-tag=0}. + +@item hwasan-instrument-allocas +Enable hwasan instrumentation of dynamically sized stack-allocated variables. +This kind of instrumentation is enabled by default when using +@option{-fsanitize=hwaddress} and disabled by default when using +@option{-fsanitize=kernel-hwaddress}. +To disable instrumentation of such variables use +@option{--param hwasan-instrument-allocas=0}, and to enable it use +@option{--param hwasan-instrument-allocas=1}. + +@item hwasan-instrument-reads +Enable hwasan checks on memory reads. Instrumentation of reads is enabled by +default for both @option{-fsanitize=hwaddress} and +@option{-fsanitize=kernel-hwaddress}. +To disable checking memory reads use +@option{--param hwasan-instrument-reads=0}. + +@item hwasan-instrument-writes +Enable hwasan checks on memory writes. Instrumentation of writes is enabled by +default for both @option{-fsanitize=hwaddress} and +@option{-fsanitize=kernel-hwaddress}. +To disable checking memory writes use +@option{--param hwasan-instrument-writes=0}. + +@item hwasan-instrument-mem-intrinsics +Enable hwasan instrumentation of builtin functions. Instrumentation of these +builtin functions is enabled by default for both @option{-fsanitize=hwaddress} +and @option{-fsanitize=kernel-hwaddress}. +To disable instrumentation of builtin functions use +@option{--param hwasan-instrument-mem-intrinsics=0}. + @item use-after-scope-direct-emission-threshold If the size of a local variable in bytes is smaller or equal to this number, directly poison (or unpoison) shadow memory instead of using @@ -14391,13 +14438,47 @@ more details. The run-time behavior can be influenced using the the available options are shown at startup of the instrumented program. See @url{https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags} for a list of supported options. -The option cannot be combined with @option{-fsanitize=thread}. +The option cannot be combined with @option{-fsanitize=thread} or +@option{-fsanitize=hwaddress}. Note that the only target this option is +currently supported on is AArch64. @item -fsanitize=kernel-address @opindex fsanitize=kernel-address Enable AddressSanitizer for Linux kernel. See @uref{https://github.com/google/kasan/wiki} for more details. +@item -fsanitize=hwaddress +@opindex fsanitize=hwaddress +Enable Hardware-assisted AddressSanitizer, which uses a hardware ability to +ignore the top byte of a pointer to allow the detection of memory errors with +a low memory overhead. +Memory access instructions are instrumented to detect out-of-bounds and +use-after-free bugs. +The option enables @option{-fsanitize-address-use-after-scope}. +See +@uref{https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html} +for more details. The run-time behavior can be influenced using the +@env{HWASAN_OPTIONS} environment variable. When set to @code{help=1}, +the available options are shown at startup of the instrumented program. +The option cannot be combined with @option{-fsanitize=thread} or +@option{-fsanitize=address}, and is currently only available on AArch64. + +@item -fsanitize=kernel-hwaddress +@opindex fsanitize=kernel-hwaddress +Enable Hardware-assisted AddressSanitizer for compilation of the Linux kernel. +Similar to @option{-fsanitize=kernel-address} but using an alternate +instrumentation method, and similar to @option{-fsanitize=hwaddress} but with +instrumentation differences necessary for compiling the Linux kernel. +These differences are to avoid hwasan library initialization calls and to +account for the stack pointer having a different value in its top byte. + +@emph{Note:} This option has different defaults to the @option{-fsanitize=hwaddress}. +Instrumenting the stack and alloca calls are not on by default but are still +possible by specifying the command-line options +@option{--param hwasan-instrument-stack=1} and +@option{--param hwasan-instrument-allocas=1} respectively. Using a random frame +tag is not implemented for kernel instrumentation. + @item -fsanitize=pointer-compare @opindex fsanitize=pointer-compare Instrument comparison operation (<, <=, >, >=) with pointer operands. diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 2b88f78944f..dda71bb89dd 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -12222,3 +12222,12 @@ This target hook can be used to generate a target-specific code @deftypefn {Target Hook} void TARGET_RUN_TARGET_SELFTESTS (void) If selftests are enabled, run any selftests for this target. @end deftypefn + +@deftypefn {Target Hook} bool TARGET_MEMTAG_CAN_TAG_ADDRESSES () +True if the backend architecture naturally supports ignoring some region +of pointers. This feature means that @option{-fsanitize=hwaddress} can +work. + +At preset, this feature does not support address spaces. It also requires +@code{Pmode} to be the same as @code{ptr_mode}. +@end deftypefn diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 897f2896266..8fbd36e2bf3 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -8184,3 +8184,5 @@ maintainer is familiar with. @hook TARGET_SPECULATION_SAFE_VALUE @hook TARGET_RUN_TARGET_SELFTESTS + +@hook TARGET_MEMTAG_CAN_TAG_ADDRESSES diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 0dbab19943c..9342bd87be3 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -276,6 +276,9 @@ enum sanitize_code { SANITIZE_BUILTIN = 1UL << 25, SANITIZE_POINTER_COMPARE = 1UL << 26, SANITIZE_POINTER_SUBTRACT = 1UL << 27, + SANITIZE_HWADDRESS = 1UL << 28, + SANITIZE_USER_HWADDRESS = 1UL << 29, + SANITIZE_KERNEL_HWADDRESS = 1UL << 30, SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT, SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN diff --git a/gcc/gcc.c b/gcc/gcc.c index d78b5f582b5..16a6ee551de 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -749,6 +749,24 @@ proper position among the other output files. */ #define LIBASAN_EARLY_SPEC "" #endif +#ifndef LIBHWASAN_SPEC +#define STATIC_LIBHWASAN_LIBS \ + " %{static-libhwasan|static:%:include(libsanitizer.spec)%(link_libhwasan)}" +#ifdef LIBHWASAN_EARLY_SPEC +#define LIBHWASAN_SPEC STATIC_LIBHWASAN_LIBS +#elif defined(HAVE_LD_STATIC_DYNAMIC) +#define LIBHWASAN_SPEC "%{static-libhwasan:" LD_STATIC_OPTION \ + "} -lhwasan %{static-libhwasan:" LD_DYNAMIC_OPTION "}" \ + STATIC_LIBHWASAN_LIBS +#else +#define LIBHWASAN_SPEC "-lhwasan" STATIC_LIBHWASAN_LIBS +#endif +#endif + +#ifndef LIBHWASAN_EARLY_SPEC +#define LIBHWASAN_EARLY_SPEC "" +#endif + #ifndef LIBTSAN_SPEC #define STATIC_LIBTSAN_LIBS \ " %{static-libtsan|static:%:include(libsanitizer.spec)%(link_libtsan)}" @@ -1071,6 +1089,7 @@ proper position among the other output files. */ #ifndef SANITIZER_EARLY_SPEC #define SANITIZER_EARLY_SPEC "\ %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \ + %{%:sanitize(hwaddress):" LIBHWASAN_EARLY_SPEC "} \ %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \ %{%:sanitize(leak):" LIBLSAN_EARLY_SPEC "}}}}" #endif @@ -1080,6 +1099,8 @@ proper position among the other output files. */ #define SANITIZER_SPEC "\ %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\ %{static:%ecannot specify -static with -fsanitize=address}}\ + %{%:sanitize(hwaddress):" LIBHWASAN_SPEC "\ + %{static:%ecannot specify -static with -fsanitize=hwaddress}}\ %{%:sanitize(thread):" LIBTSAN_SPEC "\ %{static:%ecannot specify -static with -fsanitize=thread}}\ %{%:sanitize(undefined):" LIBUBSAN_SPEC "}\ @@ -10131,8 +10152,12 @@ sanitize_spec_function (int argc, const char **argv) if (strcmp (argv[0], "address") == 0) return (flag_sanitize & SANITIZE_USER_ADDRESS) ? "" : NULL; + if (strcmp (argv[0], "hwaddress") == 0) + return (flag_sanitize & SANITIZE_USER_HWADDRESS) ? "" : NULL; if (strcmp (argv[0], "kernel-address") == 0) return (flag_sanitize & SANITIZE_KERNEL_ADDRESS) ? "" : NULL; + if (strcmp (argv[0], "kernel-hwaddress") == 0) + return (flag_sanitize & SANITIZE_KERNEL_HWADDRESS) ? "" : NULL; if (strcmp (argv[0], "thread") == 0) return (flag_sanitize & SANITIZE_THREAD) ? "" : NULL; if (strcmp (argv[0], "undefined") == 0) diff --git a/gcc/opts.c b/gcc/opts.c index 57774916a09..cc1d0cc04f6 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -823,6 +823,57 @@ control_options_for_live_patching (struct gcc_options *opts, /* --help option argument if set. */ vec help_option_arguments; +/* Return the string name describing a sanitizer argument which has been + provided on the command line and has set this particular flag. */ +const char * +find_sanitizer_argument (struct gcc_options *opts, unsigned int flags) +{ + for (int i = 0; sanitizer_opts[i].name != NULL; ++i) + { + /* Need to find the sanitizer_opts element which: + a) Could have set the flags requested. + b) Has been set on the command line. + + Can have (a) without (b) if the flag requested is e.g. + SANITIZE_ADDRESS, since both -fsanitize=address and + -fsanitize=kernel-address set this flag. + + Can have (b) without (a) by requesting more than one sanitizer on the + command line. */ + if ((sanitizer_opts[i].flag & opts->x_flag_sanitize) + != sanitizer_opts[i].flag) + continue; + if ((sanitizer_opts[i].flag & flags) != flags) + continue; + return sanitizer_opts[i].name; + } + return NULL; +} + + +/* Report an error to the user about sanitizer options they have requested + which have set conflicting flags. + + LEFT and RIGHT indicate sanitizer flags which conflict with each other, this + function reports an error if both have been set in OPTS->x_flag_sanitize and + ensures the error identifies the requested command line options that have + set these flags. */ +static void +report_conflicting_sanitizer_options (struct gcc_options *opts, location_t loc, + unsigned int left, unsigned int right) +{ + unsigned int left_seen = (opts->x_flag_sanitize & left); + unsigned int right_seen = (opts->x_flag_sanitize & right); + if (left_seen && right_seen) + { + const char* left_arg = find_sanitizer_argument (opts, left_seen); + const char* right_arg = find_sanitizer_argument (opts, right_seen); + gcc_assert (left_arg && right_arg); + error_at (loc, + "%<-fsanitize=%s%> is incompatible with %<-fsanitize=%s%>", + left_arg, right_arg); + } +} /* After all options at LOC have been read into OPTS and OPTS_SET, finalize settings of those options and diagnose incompatible @@ -1074,22 +1125,22 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, "%<-fsanitize=address%> or %<-fsanitize=kernel-address%>"); } - /* Userspace and kernel ASan conflict with each other. */ - if ((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS) - && (opts->x_flag_sanitize & SANITIZE_KERNEL_ADDRESS)) - error_at (loc, "%qs is incompatible with %qs", - "-fsanitize=address", "-fsanitize=kernel-address"); + /* Address sanitizers conflict with the thread sanitizer. */ + report_conflicting_sanitizer_options (opts, loc, SANITIZE_THREAD, + SANITIZE_ADDRESS | SANITIZE_HWADDRESS); + /* The leak sanitizer conflicts with the thread sanitizer. */ + report_conflicting_sanitizer_options (opts, loc, SANITIZE_LEAK, + SANITIZE_THREAD); - /* And with TSan. */ - if ((opts->x_flag_sanitize & SANITIZE_ADDRESS) - && (opts->x_flag_sanitize & SANITIZE_THREAD)) - error_at (loc, "%qs is incompatible with %qs", - "-fsanitize=thread", "-fsanitize=address|kernel-address"); + /* No combination of HWASAN and ASAN work together. */ + report_conflicting_sanitizer_options (opts, loc, + SANITIZE_HWADDRESS, SANITIZE_ADDRESS); - if ((opts->x_flag_sanitize & SANITIZE_LEAK) - && (opts->x_flag_sanitize & SANITIZE_THREAD)) - error_at (loc, "%qs is incompatible with %qs", - "-fsanitize=leak", "-fsanitize=thread"); + /* The userspace and kernel address sanitizers conflict with each other. */ + report_conflicting_sanitizer_options (opts, loc, SANITIZE_USER_HWADDRESS, + SANITIZE_KERNEL_HWADDRESS); + report_conflicting_sanitizer_options (opts, loc, SANITIZE_USER_ADDRESS, + SANITIZE_KERNEL_ADDRESS); /* Check error recovery for -fsanitize-recover option. */ for (int i = 0; sanitizer_opts[i].name != NULL; ++i) @@ -1108,9 +1159,10 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, if (opts->x_flag_sanitize & ~(SANITIZE_LEAK | SANITIZE_UNREACHABLE)) opts->x_flag_aggressive_loop_optimizations = 0; - /* Enable -fsanitize-address-use-after-scope if address sanitizer is + /* Enable -fsanitize-address-use-after-scope if either address sanitizer is enabled. */ - if (opts->x_flag_sanitize & SANITIZE_USER_ADDRESS) + if (opts->x_flag_sanitize + & (SANITIZE_USER_ADDRESS | SANITIZE_USER_HWADDRESS)) SET_OPTION_IF_UNSET (opts, opts_set, flag_sanitize_address_use_after_scope, true); @@ -1724,8 +1776,13 @@ const struct sanitizer_opts_s sanitizer_opts[] = #define SANITIZER_OPT(name, flags, recover) \ { #name, flags, sizeof #name - 1, recover } SANITIZER_OPT (address, (SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), true), + SANITIZER_OPT (hwaddress, (SANITIZE_HWADDRESS | SANITIZE_USER_HWADDRESS), + true), SANITIZER_OPT (kernel-address, (SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS), true), + SANITIZER_OPT (kernel-hwaddress, + (SANITIZE_HWADDRESS | SANITIZE_KERNEL_HWADDRESS), + true), SANITIZER_OPT (pointer-compare, SANITIZE_POINTER_COMPARE, true), SANITIZER_OPT (pointer-subtract, SANITIZE_POINTER_SUBTRACT, true), SANITIZER_OPT (thread, SANITIZE_THREAD, false), @@ -2304,6 +2361,15 @@ common_handle_option (struct gcc_options *opts, SET_OPTION_IF_UNSET (opts, opts_set, param_asan_protect_allocas, 0); SET_OPTION_IF_UNSET (opts, opts_set, param_asan_use_after_return, 0); } + if (opts->x_flag_sanitize & SANITIZE_KERNEL_HWADDRESS) + { + SET_OPTION_IF_UNSET (opts, opts_set, + param_hwasan_instrument_stack, 0); + SET_OPTION_IF_UNSET (opts, opts_set, + param_hwasan_random_frame_tag, 0); + SET_OPTION_IF_UNSET (opts, opts_set, + param_hwasan_instrument_allocas, 0); + } break; case OPT_fsanitize_recover_: diff --git a/gcc/params.opt b/gcc/params.opt index 202d92fd601..ec15357bc27 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -62,6 +62,30 @@ Enable asan stack protection. Common Joined UInteger Var(param_asan_use_after_return) Init(1) IntegerRange(0, 1) Param Optimization Enable asan detection of use-after-return bugs. +-param=hwasan-instrument-stack= +Common Joined UInteger Var(param_hwasan_instrument_stack) Init(1) IntegerRange(0, 1) Param Optimization +Enable hwasan instrumentation of statically sized stack-allocated variables. + +-param=hwasan-random-frame-tag= +Common Joined UInteger Var(param_hwasan_random_frame_tag) Init(1) IntegerRange(0, 1) Param Optimization +Use random base tag for each frame, as opposed to base always zero. + +-param=hwasan-instrument-allocas= +Common Joined UInteger Var(param_hwasan_instrument_allocas) Init(1) IntegerRange(0, 1) Param Optimization +Enable hwasan instrumentation of allocas/VLAs. + +-param=hwasan-instrument-reads= +Common Joined UInteger Var(param_hwasan_instrument_reads) Init(1) IntegerRange(0, 1) Param Optimization +Enable hwasan instrumentation of load operations. + +-param=hwasan-instrument-writes= +Common Joined UInteger Var(param_hwasan_instrument_writes) Init(1) IntegerRange(0, 1) Param Optimization +Enable hwasan instrumentation of store operations. + +-param=hwasan-instrument-mem-intrinsics= +Common Joined UInteger Var(param_hwasan_instrument_mem_intrinsics) Init(1) IntegerRange(0, 1) Param Optimization +Enable hwasan instrumentation of builtin functions. + -param=avg-loop-niter= Common Joined UInteger Var(param_avg_loop_niter) Init(10) IntegerRange(1, 65536) Param Optimization Average number of iterations of a loop. diff --git a/gcc/target.def b/gcc/target.def index 810d5542c28..31e33ecc9a5 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -6862,6 +6862,21 @@ DEFHOOK HOOK_VECTOR_END (mode_switching) +#undef HOOK_PREFIX +#define HOOK_PREFIX "TARGET_MEMTAG_" +HOOK_VECTOR (TARGET_MEMTAG_, memtag) + +DEFHOOK +(can_tag_addresses, + "True if the backend architecture naturally supports ignoring some region\n\ +of pointers. This feature means that @option{-fsanitize=hwaddress} can\n\ +work.\n\ +\n\ +At preset, this feature does not support address spaces. It also requires\n\ +@code{Pmode} to be the same as @code{ptr_mode}.", + bool, (), default_memtag_can_tag_addresses) + +HOOK_VECTOR_END (memtag) #undef HOOK_PREFIX #define HOOK_PREFIX "TARGET_" diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 5b68a2ad7d4..46cb536041d 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -2415,4 +2415,10 @@ default_speculation_safe_value (machine_mode mode ATTRIBUTE_UNUSED, return result; } +bool +default_memtag_can_tag_addresses () +{ + return false; +} + #include "gt-targhooks.h" diff --git a/gcc/targhooks.h b/gcc/targhooks.h index e0a925fa2be..0065c686978 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -286,4 +286,5 @@ extern bool default_have_speculation_safe_value (bool); extern bool speculation_safe_value_not_needed (bool); extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx); +extern bool default_memtag_can_tag_addresses (); #endif /* GCC_TARGHOOKS_H */ diff --git a/gcc/toplev.c b/gcc/toplev.c index e0e0e04e95f..2a3e7c064a5 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1853,6 +1853,15 @@ process_options (void) flag_sanitize &= ~SANITIZE_ADDRESS; } + /* HWAsan requires top byte ignore feature in the backend. */ + if (flag_sanitize & SANITIZE_HWADDRESS + && ! targetm.memtag.can_tag_addresses ()) + { + warning_at (UNKNOWN_LOCATION, 0, "%qs is not supported for this target", + "-fsanitize=hwaddress"); + flag_sanitize &= ~SANITIZE_HWADDRESS; + } + /* Do not use IPA optimizations for register allocation if profiler is active or patchable function entries are inserted for run-time instrumentation or port does not emit prologue and epilogue as RTL. */