Commit 6dc4a604 by Martin Liska Committed by Martin Liska

Introduce -fsanitize-address-use-after-scope

	* c-warn.c (warn_for_unused_label): Save all labels used
	in goto or in &label.
	* asan.c (enum asan_check_flags): Move the enum to header file.
	(asan_init_shadow_ptr_types): Make type creation more generic.
	(shadow_mem_size): New function.
	(asan_emit_stack_protection): Use newly added ASAN_SHADOW_GRANULARITY.
	Rewritten stack unpoisoning code.
	(build_shadow_mem_access): Add new argument return_address.
	(instrument_derefs): Instrument local variables if use after scope
	sanitization is enabled.
	(asan_store_shadow_bytes): New function.
	(asan_expand_mark_ifn): Likewise.
	(asan_sanitize_stack_p): Moved from asan_sanitize_stack_p.
	* asan.h (enum asan_mark_flags): Moved here from asan.c
	(asan_protect_stack_decl): Protect all declaration that need
	to live in memory.
	(asan_sanitize_use_after_scope): New function.
	(asan_no_sanitize_address_p): Likewise.
	* cfgexpand.c (partition_stack_vars): Consider
	asan_sanitize_use_after_scope in condition.
	(expand_stack_vars): Likewise.
	* common.opt (-fsanitize-address-use-after-scope): New option.
	* doc/invoke.texi (use-after-scope-direct-emission-threshold):
	Explain the parameter.
	* flag-types.h (enum sanitize_code): Define SANITIZE_USE_AFTER_SCOPE.
	* gimplify.c (build_asan_poison_call_expr): New function.
	(asan_poison_variable): Likewise.
	(gimplify_bind_expr): Generate poisoning/unpoisoning for local
	variables that have address taken.
	(gimplify_decl_expr): Likewise.
	(gimplify_target_expr): Likewise for C++ temporaries.
	(sort_by_decl_uid): New function.
	(gimplify_expr): Unpoison all variables for a label we can jump
	from outside of a scope.
	(gimplify_switch_expr): Unpoison variables defined in the switch
	context.
	(gimplify_function_tree): Clear asan_poisoned_variables.
	(asan_poison_variables): New function.
	(warn_switch_unreachable_r): Handle IFN_ASAN_MARK.
	* internal-fn.c (expand_ASAN_MARK): New function.
	* internal-fn.def (ASAN_MARK): Declare.
	* opts.c (finish_options): Handle -fstack-reuse if
	-fsanitize-address-use-after-scope is enabled.
	(common_handle_option): Enable address sanitization if
	-fsanitize-address-use-after-scope is enabled.
	* params.def (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD):
	New parameter.
	* params.h: Likewise.
	* sancov.c (pass_sanopt::execute): Handle IFN_ASAN_MARK.
	* sanitizer.def: Define __asan_poison_stack_memory and
	__asan_unpoison_stack_memory functions.
	* asan.c (asan_mark_poison_p): New function.
	(transform_statements): Handle asan_mark_poison_p calls.
	* gimple.c (nonfreeing_call_p): Handle IFN_ASAN_MARK.

From-SVN: r241896
parent 2447ab85
2016-11-07 Martin Liska <mliska@suse.cz>
* asan.c (enum asan_check_flags): Move the enum to header file.
(asan_init_shadow_ptr_types): Make type creation more generic.
(shadow_mem_size): New function.
(asan_emit_stack_protection): Use newly added ASAN_SHADOW_GRANULARITY.
Rewritten stack unpoisoning code.
(build_shadow_mem_access): Add new argument return_address.
(instrument_derefs): Instrument local variables if use after scope
sanitization is enabled.
(asan_store_shadow_bytes): New function.
(asan_expand_mark_ifn): Likewise.
(asan_sanitize_stack_p): Moved from asan_sanitize_stack_p.
* asan.h (enum asan_mark_flags): Moved here from asan.c
(asan_protect_stack_decl): Protect all declaration that need
to live in memory.
(asan_sanitize_use_after_scope): New function.
(asan_no_sanitize_address_p): Likewise.
* cfgexpand.c (partition_stack_vars): Consider
asan_sanitize_use_after_scope in condition.
(expand_stack_vars): Likewise.
* common.opt (-fsanitize-address-use-after-scope): New option.
* doc/invoke.texi (use-after-scope-direct-emission-threshold):
Explain the parameter.
* flag-types.h (enum sanitize_code): Define SANITIZE_USE_AFTER_SCOPE.
* gimplify.c (build_asan_poison_call_expr): New function.
(asan_poison_variable): Likewise.
(gimplify_bind_expr): Generate poisoning/unpoisoning for local
variables that have address taken.
(gimplify_decl_expr): Likewise.
(gimplify_target_expr): Likewise for C++ temporaries.
(sort_by_decl_uid): New function.
(gimplify_expr): Unpoison all variables for a label we can jump
from outside of a scope.
(gimplify_switch_expr): Unpoison variables defined in the switch
context.
(gimplify_function_tree): Clear asan_poisoned_variables.
(asan_poison_variables): New function.
(warn_switch_unreachable_r): Handle IFN_ASAN_MARK.
* internal-fn.c (expand_ASAN_MARK): New function.
* internal-fn.def (ASAN_MARK): Declare.
* opts.c (finish_options): Handle -fstack-reuse if
-fsanitize-address-use-after-scope is enabled.
(common_handle_option): Enable address sanitization if
-fsanitize-address-use-after-scope is enabled.
* params.def (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD):
New parameter.
* params.h: Likewise.
* sancov.c (pass_sanopt::execute): Handle IFN_ASAN_MARK.
* sanitizer.def: Define __asan_poison_stack_memory and
__asan_unpoison_stack_memory functions.
* asan.c (asan_mark_poison_p): New function.
(transform_statements): Handle asan_mark_poison_p calls.
* gimple.c (nonfreeing_call_p): Handle IFN_ASAN_MARK.
2016-11-07 Tamar Christina <tamar.christina@arm.com>
PR driver/78196
......@@ -29,6 +29,7 @@ extern bool asan_protect_global (tree);
extern void initialize_sanitizer_builtins (void);
extern tree asan_dynamic_init_call (bool);
extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool);
extern bool asan_expand_mark_ifn (gimple_stmt_iterator *);
extern gimple_stmt_iterator create_cond_insert_point
(gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *);
......@@ -36,9 +37,14 @@ extern gimple_stmt_iterator create_cond_insert_point
/* Alias set for accessing the shadow memory. */
extern alias_set_type asan_shadow_set;
/* Hash set of labels that are either used in a goto, or their address
has been taken. */
extern hash_set <tree> *asan_used_labels;
/* Shadow memory is found at
(address >> ASAN_SHADOW_SHIFT) + asan_shadow_offset (). */
#define ASAN_SHADOW_SHIFT 3
#define ASAN_SHADOW_GRANULARITY (1UL << ASAN_SHADOW_SHIFT)
/* Red zone size, stack and global variables are padded by ASAN_RED_ZONE_SIZE
up to 2 * ASAN_RED_ZONE_SIZE - 1 bytes. */
......@@ -50,22 +56,32 @@ extern alias_set_type asan_shadow_set;
the frame. Middle is for padding in between variables, right is
above the last protected variable and partial immediately after variables
up to ASAN_RED_ZONE_SIZE alignment. */
#define ASAN_STACK_MAGIC_LEFT 0xf1
#define ASAN_STACK_MAGIC_MIDDLE 0xf2
#define ASAN_STACK_MAGIC_RIGHT 0xf3
#define ASAN_STACK_MAGIC_PARTIAL 0xf4
#define ASAN_STACK_MAGIC_USE_AFTER_RET 0xf5
#define ASAN_STACK_MAGIC_LEFT 0xf1
#define ASAN_STACK_MAGIC_MIDDLE 0xf2
#define ASAN_STACK_MAGIC_RIGHT 0xf3
#define ASAN_STACK_MAGIC_PARTIAL 0xf4
#define ASAN_STACK_MAGIC_USE_AFTER_RET 0xf5
#define ASAN_STACK_MAGIC_USE_AFTER_SCOPE 0xf8
#define ASAN_STACK_FRAME_MAGIC 0x41b58ab3
#define ASAN_STACK_RETIRED_MAGIC 0x45e0360e
/* Return true if DECL should be guarded on the stack. */
static inline bool
asan_protect_stack_decl (tree decl)
/* Various flags for Asan builtins. */
enum asan_check_flags
{
return DECL_P (decl) && !DECL_ARTIFICIAL (decl);
}
ASAN_CHECK_STORE = 1 << 0,
ASAN_CHECK_SCALAR_ACCESS = 1 << 1,
ASAN_CHECK_NON_ZERO_LEN = 1 << 2,
ASAN_CHECK_LAST = 1 << 3
};
/* Flags for Asan check builtins. */
enum asan_mark_flags
{
ASAN_MARK_CLOBBER = 1 << 0,
ASAN_MARK_UNCLOBBER = 1 << 1,
ASAN_MARK_LAST = 1 << 2
};
/* Return the size of padding needed to insert after a protected
decl of SIZE. */
......@@ -81,6 +97,8 @@ extern bool set_asan_shadow_offset (const char *);
extern void set_sanitized_sections (const char *);
extern bool asan_sanitize_stack_p (void);
/* Return TRUE if builtin with given FCODE will be intercepted by
libasan. */
......@@ -105,4 +123,30 @@ asan_intercepted_p (enum built_in_function fcode)
|| fcode == BUILT_IN_STRNCMP
|| fcode == BUILT_IN_STRNCPY;
}
/* Return TRUE if we should instrument for use-after-scope sanity checking. */
static inline bool
asan_sanitize_use_after_scope (void)
{
return (flag_sanitize_address_use_after_scope && asan_sanitize_stack_p ());
}
static inline bool
asan_no_sanitize_address_p (void)
{
return lookup_attribute ("no_sanitize_address",
DECL_ATTRIBUTES (current_function_decl));
}
/* Return true if DECL should be guarded on the stack. */
static inline bool
asan_protect_stack_decl (tree decl)
{
return DECL_P (decl)
&& (!DECL_ARTIFICIAL (decl)
|| (asan_sanitize_use_after_scope () && TREE_ADDRESSABLE (decl)));
}
#endif /* TREE_ASAN */
2016-11-07 Martin Liska <mliska@suse.cz>
* c-warn.c (warn_for_unused_label): Save all labels used
in goto or in &label.
2016-11-03 Jason Merrill <jason@redhat.com>
* c-cppbuiltin.c (c_cpp_builtins): Correct
......
......@@ -28,7 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm_p.h"
#include "diagnostic.h"
#include "intl.h"
#include "asan.h"
/* Print a warning if a constant expression had overflow in folding.
Invoke this function on every expression that the language
......@@ -1627,6 +1627,13 @@ warn_for_unused_label (tree label)
else
warning (OPT_Wunused_label, "label %q+D declared but not defined", label);
}
else if (asan_sanitize_use_after_scope ())
{
if (asan_used_labels == NULL)
asan_used_labels = new hash_set<tree> (16);
asan_used_labels->add (label);
}
}
/* Warn for division by zero according to the value of DIVISOR. LOC
......
......@@ -868,18 +868,6 @@ union_stack_vars (size_t a, size_t b)
}
}
/* Return true if the current function should have its stack frame
protected by address sanitizer. */
static inline bool
asan_sanitize_stack_p (void)
{
return ((flag_sanitize & SANITIZE_ADDRESS)
&& ASAN_STACK
&& !lookup_attribute ("no_sanitize_address",
DECL_ATTRIBUTES (current_function_decl)));
}
/* A subroutine of expand_used_vars. Binpack the variables into
partitions constrained by the interference graph. The overall
algorithm used is as follows:
......@@ -941,7 +929,8 @@ partition_stack_vars (void)
sizes, as the shorter vars wouldn't be adequately protected.
Don't do that for "large" (unsupported) alignment objects,
those aren't protected anyway. */
if (asan_sanitize_stack_p () && isize != jsize
if ((asan_sanitize_stack_p ())
&& isize != jsize
&& ialign * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
break;
......@@ -1128,7 +1117,8 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
{
base = virtual_stack_vars_rtx;
if (asan_sanitize_stack_p () && pred)
if ((asan_sanitize_stack_p ())
&& pred)
{
HOST_WIDE_INT prev_offset
= align_base (frame_offset,
......
......@@ -986,6 +986,9 @@ fsanitize-recover
Common Report
This switch is deprecated; use -fsanitize-recover= instead.
fsanitize-address-use-after-scope
Common Driver Report Var(flag_sanitize_address_use_after_scope) Init(0)
fsanitize-undefined-trap-on-error
Common Driver Report Var(flag_sanitize_undefined_trap_on_error) Init(0)
Use trap instead of a library function for undefined behavior sanitization.
......
......@@ -10290,6 +10290,10 @@ 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 use-after-scope-direct-emission-threshold
If size of a local variables in bytes is smaller of equal to this number,
direct instruction emission is utilized to poison and unpoison local variables.
@item chkp-max-ctor-size
Static constructors generated by Pointer Bounds Checker may become very
large and significantly increase compile time at optimization level
......@@ -10500,6 +10504,7 @@ thread-safe code.
Enable AddressSanitizer, a fast memory error detector.
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://github.com/google/sanitizers/wiki/AddressSanitizer} for
more details. The run-time behavior can be influenced using the
@env{ASAN_OPTIONS} environment variable. When set to @code{help=1},
......@@ -10511,6 +10516,7 @@ The option can't be combined with @option{-fsanitize=thread}.
@item -fsanitize=kernel-address
@opindex fsanitize=kernel-address
Enable AddressSanitizer for Linux kernel.
The option enables @option{-fsanitize-address-use-after-scope}.
See @uref{https://github.com/google/kasan/wiki} for more details.
@item -fsanitize=thread
......@@ -10710,8 +10716,8 @@ except for @option{-fsanitize=unreachable} and @option{-fsanitize=return}),
@option{-fsanitize=float-cast-overflow}, @option{-fsanitize=float-divide-by-zero},
@option{-fsanitize=bounds-strict},
@option{-fsanitize=kernel-address} and @option{-fsanitize=address}.
For these sanitizers error recovery is turned on by default, except @option{-fsanitize=address},
for which this feature is experimental.
For these sanitizers error recovery is turned on by default,
except @option{-fsanitize=address}, for which this feature is experimental.
@option{-fsanitize-recover=all} and @option{-fno-sanitize-recover=all} is also
accepted, the former enables recovery for all sanitizers that support it,
the latter disables recovery for all sanitizers that support it.
......@@ -10733,6 +10739,11 @@ Similarly @option{-fno-sanitize-recover} is equivalent to
-fno-sanitize-recover=undefined,float-cast-overflow,float-divide-by-zero,bounds-strict
@end smallexample
@item -fsanitize-address-use-after-scope
@opindex fsanitize-address-use-after-scope
Enable sanitization of local variables to detect use-after-scope bugs.
The option sets @option{-fstack-reuse} to @samp{none}.
@item -fsanitize-undefined-trap-on-error
@opindex fsanitize-undefined-trap-on-error
The @option{-fsanitize-undefined-trap-on-error} option instructs the compiler to
......
......@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "builtins.h"
#include "selftest.h"
#include "gimple-pretty-print.h"
#include "asan.h"
/* All the tuples have their operand vector (if present) at the very bottom
......@@ -2629,6 +2630,8 @@ nonfreeing_call_p (gimple *call)
{
case IFN_ABNORMAL_DISPATCHER:
return true;
case IFN_ASAN_MARK:
return tree_to_uhwi (gimple_call_arg (call, 0)) == ASAN_MARK_UNCLOBBER;
default:
if (gimple_call_flags (call) & ECF_LEAF)
return true;
......
......@@ -237,6 +237,15 @@ expand_ASAN_CHECK (internal_fn, gcall *)
gcc_unreachable ();
}
/* This should get expanded in the sanopt pass. */
static void
expand_ASAN_MARK (internal_fn, gcall *)
{
gcc_unreachable ();
}
/* This should get expanded in the tsan pass. */
static void
......
......@@ -158,6 +158,7 @@ DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R...")
DEF_INTERNAL_FN (ASAN_MARK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R..")
DEF_INTERNAL_FN (ADD_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
......
......@@ -979,6 +979,25 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
opts->x_flag_aggressive_loop_optimizations = 0;
opts->x_flag_strict_overflow = 0;
}
/* Enable -fsanitize-address-use-after-scope if address sanitizer is
enabled. */
if (opts->x_flag_sanitize
&& !opts_set->x_flag_sanitize_address_use_after_scope)
opts->x_flag_sanitize_address_use_after_scope = true;
/* Force -fstack-reuse=none in case -fsanitize-address-use-after-scope
is enabled. */
if (opts->x_flag_sanitize_address_use_after_scope)
{
if (opts->x_flag_stack_reuse != SR_NONE
&& opts_set->x_flag_stack_reuse != SR_NONE)
error_at (loc,
"-fsanitize-address-use-after-scope requires "
"-fstack-reuse=none option");
opts->x_flag_stack_reuse = SR_NONE;
}
}
#define LEFT_COLUMN 27
......@@ -1452,8 +1471,8 @@ 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 (kernel-address, SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS,
SANITIZER_OPT (address, (SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), true),
SANITIZER_OPT (kernel-address, (SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS),
true),
SANITIZER_OPT (thread, SANITIZE_THREAD, false),
SANITIZER_OPT (leak, SANITIZE_LEAK, false),
......@@ -1781,6 +1800,10 @@ common_handle_option (struct gcc_options *opts,
/* Deferred. */
break;
case OPT_fsanitize_address_use_after_scope:
opts->x_flag_sanitize_address_use_after_scope = value;
break;
case OPT_fsanitize_recover:
if (value)
opts->x_flag_sanitize_recover
......
......@@ -1168,6 +1168,12 @@ DEFPARAM (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD,
"in function becomes greater or equal to this number.",
7000, 0, INT_MAX)
DEFPARAM (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD,
"use-after-scope-direct-emission-threshold",
"Use direct poisoning/unpoisoning intructions for variables "
"smaller or equal to this number.",
256, 0, INT_MAX)
DEFPARAM (PARAM_UNINIT_CONTROL_DEP_ATTEMPTS,
"uninit-control-dep-attempts",
"Maximum number of nested calls to search for control dependencies "
......
......@@ -244,5 +244,7 @@ extern void init_param_values (int *params);
PARAM_VALUE (PARAM_ASAN_USE_AFTER_RETURN)
#define ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD \
PARAM_VALUE (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD)
#define ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD \
((unsigned) PARAM_VALUE (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD))
#endif /* ! GCC_PARAMS_H */
......@@ -165,6 +165,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT,
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_AFTER_DYNAMIC_INIT,
"__asan_after_dynamic_init",
BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_CLOBBER_N, "__asan_poison_stack_memory",
BT_FN_VOID_PTR_PTRMODE, 0)
DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNCLOBBER_N, "__asan_unpoison_stack_memory",
BT_FN_VOID_PTR_PTRMODE, 0)
/* Thread Sanitizer */
DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init",
......
......@@ -732,6 +732,9 @@ pass_sanopt::execute (function *fun)
case IFN_ASAN_CHECK:
no_next = asan_expand_check_ifn (&gsi, use_calls);
break;
case IFN_ASAN_MARK:
no_next = asan_expand_mark_ifn (&gsi);
break;
default:
break;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment