parent
f35db108b9
commit
497a1c6692
|
@ -1,4 +1,8 @@
|
||||||
2012-11-12 Wei Mi <wmi@google.com>
|
2012-11-12 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
|
* asan.c: Formatting cleanups.
|
||||||
|
|
||||||
|
2012-11-12 Wei Mi <wmi@google.com>
|
||||||
|
|
||||||
* gcc.c (LINK_COMMAND_SPEC): Add -lasan to link command if
|
* gcc.c (LINK_COMMAND_SPEC): Add -lasan to link command if
|
||||||
-faddress-sanitizer is on.
|
-faddress-sanitizer is on.
|
||||||
|
@ -28,7 +32,6 @@
|
||||||
* asan.c (create_cond_insert_point_before_iter): Factorize out of ...
|
* asan.c (create_cond_insert_point_before_iter): Factorize out of ...
|
||||||
(build_check_stmt): ... here.
|
(build_check_stmt): ... here.
|
||||||
|
|
||||||
|
|
||||||
2012-11-12 Dodji Seketeli <dodji@redhat.com>
|
2012-11-12 Dodji Seketeli <dodji@redhat.com>
|
||||||
|
|
||||||
* asan.c (create_cond_insert_point_before_iter): Factorize out of ...
|
* asan.c (create_cond_insert_point_before_iter): Factorize out of ...
|
||||||
|
@ -40,7 +43,7 @@
|
||||||
represented by an SSA_NAME.
|
represented by an SSA_NAME.
|
||||||
|
|
||||||
2012-11-12 Jakub Jelinek <jakub@redhat.com>
|
2012-11-12 Jakub Jelinek <jakub@redhat.com>
|
||||||
Wei Mi <wmi@google.com>
|
Wei Mi <wmi@google.com>
|
||||||
|
|
||||||
* varasm.c: Include asan.h.
|
* varasm.c: Include asan.h.
|
||||||
(assemble_noswitch_variable): Grow size by asan_red_zone_size
|
(assemble_noswitch_variable): Grow size by asan_red_zone_size
|
||||||
|
@ -111,7 +114,7 @@
|
||||||
|
|
||||||
2012-11-12 Jakub Jelinek <jakub@redhat.com>
|
2012-11-12 Jakub Jelinek <jakub@redhat.com>
|
||||||
Xinliang David Li <davidxl@google.com>
|
Xinliang David Li <davidxl@google.com>
|
||||||
Dodji Seketeli <dodji@redhat.com>
|
Dodji Seketeli <dodji@redhat.com>
|
||||||
|
|
||||||
* Makefile.in (GTFILES): Add $(srcdir)/asan.c.
|
* Makefile.in (GTFILES): Add $(srcdir)/asan.c.
|
||||||
(asan.o): Update the dependencies of asan.o.
|
(asan.o): Update the dependencies of asan.o.
|
||||||
|
@ -155,9 +158,9 @@
|
||||||
* config/i386/i386.c (ix86_asan_shadow_offset): New function.
|
* config/i386/i386.c (ix86_asan_shadow_offset): New function.
|
||||||
(TARGET_ASAN_SHADOW_OFFSET): Define.
|
(TARGET_ASAN_SHADOW_OFFSET): Define.
|
||||||
|
|
||||||
2012-11-12 Wei Mi <wmi@google.com>
|
2012-11-12 Wei Mi <wmi@google.com>
|
||||||
Diego Novillo <dnovillo@google.com>
|
Diego Novillo <dnovillo@google.com>
|
||||||
Dodji Seketeli <dodji@redhat.com>
|
Dodji Seketeli <dodji@redhat.com>
|
||||||
|
|
||||||
* Makefile.in: Add asan.c and its dependencies.
|
* Makefile.in: Add asan.c and its dependencies.
|
||||||
* common.opt: Add -faddress-sanitizer option.
|
* common.opt: Add -faddress-sanitizer option.
|
||||||
|
|
177
gcc/asan.c
177
gcc/asan.c
|
@ -33,42 +33,41 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "optabs.h"
|
#include "optabs.h"
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
|
|
||||||
/*
|
/* AddressSanitizer finds out-of-bounds and use-after-free bugs
|
||||||
AddressSanitizer finds out-of-bounds and use-after-free bugs
|
with <2x slowdown on average.
|
||||||
with <2x slowdown on average.
|
|
||||||
|
|
||||||
The tool consists of two parts:
|
The tool consists of two parts:
|
||||||
instrumentation module (this file) and a run-time library.
|
instrumentation module (this file) and a run-time library.
|
||||||
The instrumentation module adds a run-time check before every memory insn.
|
The instrumentation module adds a run-time check before every memory insn.
|
||||||
For a 8- or 16- byte load accessing address X:
|
For a 8- or 16- byte load accessing address X:
|
||||||
ShadowAddr = (X >> 3) + Offset
|
ShadowAddr = (X >> 3) + Offset
|
||||||
ShadowValue = *(char*)ShadowAddr; // *(short*) for 16-byte access.
|
ShadowValue = *(char*)ShadowAddr; // *(short*) for 16-byte access.
|
||||||
if (ShadowValue)
|
if (ShadowValue)
|
||||||
__asan_report_load8(X);
|
__asan_report_load8(X);
|
||||||
For a load of N bytes (N=1, 2 or 4) from address X:
|
For a load of N bytes (N=1, 2 or 4) from address X:
|
||||||
ShadowAddr = (X >> 3) + Offset
|
ShadowAddr = (X >> 3) + Offset
|
||||||
ShadowValue = *(char*)ShadowAddr;
|
ShadowValue = *(char*)ShadowAddr;
|
||||||
if (ShadowValue)
|
if (ShadowValue)
|
||||||
if ((X & 7) + N - 1 > ShadowValue)
|
if ((X & 7) + N - 1 > ShadowValue)
|
||||||
__asan_report_loadN(X);
|
__asan_report_loadN(X);
|
||||||
Stores are instrumented similarly, but using __asan_report_storeN functions.
|
Stores are instrumented similarly, but using __asan_report_storeN functions.
|
||||||
A call too __asan_init() is inserted to the list of module CTORs.
|
A call too __asan_init() is inserted to the list of module CTORs.
|
||||||
|
|
||||||
The run-time library redefines malloc (so that redzone are inserted around
|
The run-time library redefines malloc (so that redzone are inserted around
|
||||||
the allocated memory) and free (so that reuse of free-ed memory is delayed),
|
the allocated memory) and free (so that reuse of free-ed memory is delayed),
|
||||||
provides __asan_report* and __asan_init functions.
|
provides __asan_report* and __asan_init functions.
|
||||||
|
|
||||||
Read more:
|
Read more:
|
||||||
http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
|
http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
|
||||||
|
|
||||||
The current implementation supports detection of out-of-bounds and
|
The current implementation supports detection of out-of-bounds and
|
||||||
use-after-free in the heap, on the stack and for global variables.
|
use-after-free in the heap, on the stack and for global variables.
|
||||||
|
|
||||||
[Protection of stack variables]
|
[Protection of stack variables]
|
||||||
|
|
||||||
To understand how detection of out-of-bounds and use-after-free works
|
To understand how detection of out-of-bounds and use-after-free works
|
||||||
for stack variables, lets look at this example on x86_64 where the
|
for stack variables, lets look at this example on x86_64 where the
|
||||||
stack grows downward:
|
stack grows downward:
|
||||||
|
|
||||||
int
|
int
|
||||||
foo ()
|
foo ()
|
||||||
|
@ -82,28 +81,28 @@ along with GCC; see the file COPYING3. If not see
|
||||||
return a[5] + b[1];
|
return a[5] + b[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
For this function, the stack protected by asan will be organized as
|
For this function, the stack protected by asan will be organized as
|
||||||
follows, from the top of the stack to the bottom:
|
follows, from the top of the stack to the bottom:
|
||||||
|
|
||||||
Slot 1/ [red zone of 32 bytes called 'RIGHT RedZone']
|
Slot 1/ [red zone of 32 bytes called 'RIGHT RedZone']
|
||||||
|
|
||||||
Slot 2/ [8 bytes of red zone, that adds up to the space of 'a' to make
|
Slot 2/ [8 bytes of red zone, that adds up to the space of 'a' to make
|
||||||
the next slot be 32 bytes aligned; this one is called Partial
|
the next slot be 32 bytes aligned; this one is called Partial
|
||||||
Redzone; this 32 bytes alignment is an asan constraint]
|
Redzone; this 32 bytes alignment is an asan constraint]
|
||||||
|
|
||||||
Slot 3/ [24 bytes for variable 'a']
|
Slot 3/ [24 bytes for variable 'a']
|
||||||
|
|
||||||
Slot 4/ [red zone of 32 bytes called 'Middle RedZone']
|
Slot 4/ [red zone of 32 bytes called 'Middle RedZone']
|
||||||
|
|
||||||
Slot 5/ [24 bytes of Partial Red Zone (similar to slot 2]
|
Slot 5/ [24 bytes of Partial Red Zone (similar to slot 2]
|
||||||
|
|
||||||
Slot 6/ [8 bytes for variable 'b']
|
Slot 6/ [8 bytes for variable 'b']
|
||||||
|
|
||||||
Slot 7/ [32 bytes of Red Zone at the bottom of the stack, called 'LEFT
|
Slot 7/ [32 bytes of Red Zone at the bottom of the stack, called
|
||||||
RedZone']
|
'LEFT RedZone']
|
||||||
|
|
||||||
The 32 bytes of LEFT red zone at the bottom of the stack can be
|
The 32 bytes of LEFT red zone at the bottom of the stack can be
|
||||||
decomposed as such:
|
decomposed as such:
|
||||||
|
|
||||||
1/ The first 8 bytes contain a magical asan number that is always
|
1/ The first 8 bytes contain a magical asan number that is always
|
||||||
0x41B58AB3.
|
0x41B58AB3.
|
||||||
|
@ -122,7 +121,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
3/ The following 16 bytes of the red zone have no particular
|
3/ The following 16 bytes of the red zone have no particular
|
||||||
format.
|
format.
|
||||||
|
|
||||||
The shadow memory for that stack layout is going to look like this:
|
The shadow memory for that stack layout is going to look like this:
|
||||||
|
|
||||||
- content of shadow memory 8 bytes for slot 7: 0xF1F1F1F1.
|
- content of shadow memory 8 bytes for slot 7: 0xF1F1F1F1.
|
||||||
The F1 byte pattern is a magic number called
|
The F1 byte pattern is a magic number called
|
||||||
|
@ -149,39 +148,39 @@ along with GCC; see the file COPYING3. If not see
|
||||||
seat between two 32 aligned slots of {variable,padding}.
|
seat between two 32 aligned slots of {variable,padding}.
|
||||||
|
|
||||||
- content of shadow memory 8 bytes for slot 3 and 2:
|
- content of shadow memory 8 bytes for slot 3 and 2:
|
||||||
0xFFFFFFFFF4000000. This represents is the concatenation of
|
0xF4000000. This represents is the concatenation of
|
||||||
variable 'a' and the partial red zone following it, like what we
|
variable 'a' and the partial red zone following it, like what we
|
||||||
had for variable 'b'. The least significant 3 bytes being 00
|
had for variable 'b'. The least significant 3 bytes being 00
|
||||||
means that the 3 bytes of variable 'a' are addressable.
|
means that the 3 bytes of variable 'a' are addressable.
|
||||||
|
|
||||||
- content of shadow memory 8 bytes for slot 1: 0xFFFFFFFFF3F3F3F3.
|
- content of shadow memory 8 bytes for slot 1: 0xF3F3F3F3.
|
||||||
The F3 byte pattern is a magic number called
|
The F3 byte pattern is a magic number called
|
||||||
ASAN_STACK_MAGIC_RIGHT. It flags the fact that the memory
|
ASAN_STACK_MAGIC_RIGHT. It flags the fact that the memory
|
||||||
region for this shadow byte is a RIGHT red zone intended to seat
|
region for this shadow byte is a RIGHT red zone intended to seat
|
||||||
at the top of the variables of the stack.
|
at the top of the variables of the stack.
|
||||||
|
|
||||||
Note that the real variable layout is done in expand_used_vars in
|
Note that the real variable layout is done in expand_used_vars in
|
||||||
cfgexpand.c. As far as Address Sanitizer is concerned, it lays out
|
cfgexpand.c. As far as Address Sanitizer is concerned, it lays out
|
||||||
stack variables as well as the different red zones, emits some
|
stack variables as well as the different red zones, emits some
|
||||||
prologue code to populate the shadow memory as to poison (mark as
|
prologue code to populate the shadow memory as to poison (mark as
|
||||||
non-accessible) the regions of the red zones and mark the regions of
|
non-accessible) the regions of the red zones and mark the regions of
|
||||||
stack variables as accessible, and emit some epilogue code to
|
stack variables as accessible, and emit some epilogue code to
|
||||||
un-poison (mark as accessible) the regions of red zones right before
|
un-poison (mark as accessible) the regions of red zones right before
|
||||||
the function exits.
|
the function exits.
|
||||||
|
|
||||||
[Protection of global variables]
|
[Protection of global variables]
|
||||||
|
|
||||||
The basic idea is to insert a red zone between two global variables
|
The basic idea is to insert a red zone between two global variables
|
||||||
and install a constructor function that calls the asan runtime to do
|
and install a constructor function that calls the asan runtime to do
|
||||||
the populating of the relevant shadow memory regions at load time.
|
the populating of the relevant shadow memory regions at load time.
|
||||||
|
|
||||||
So the global variables are laid out as to insert a red zone between
|
So the global variables are laid out as to insert a red zone between
|
||||||
them. The size of the red zones is so that each variable starts on a
|
them. The size of the red zones is so that each variable starts on a
|
||||||
32 bytes boundary.
|
32 bytes boundary.
|
||||||
|
|
||||||
Then a constructor function is installed so that, for each global
|
Then a constructor function is installed so that, for each global
|
||||||
variable, it calls the runtime asan library function
|
variable, it calls the runtime asan library function
|
||||||
__asan_register_globals_with an instance of this type:
|
__asan_register_globals_with an instance of this type:
|
||||||
|
|
||||||
struct __asan_global
|
struct __asan_global
|
||||||
{
|
{
|
||||||
|
@ -202,8 +201,8 @@ along with GCC; see the file COPYING3. If not see
|
||||||
uptr __has_dynamic_init;
|
uptr __has_dynamic_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
A destructor function that calls the runtime asan library function
|
A destructor function that calls the runtime asan library function
|
||||||
_asan_unregister_globals is also installed. */
|
_asan_unregister_globals is also installed. */
|
||||||
|
|
||||||
alias_set_type asan_shadow_set = -1;
|
alias_set_type asan_shadow_set = -1;
|
||||||
|
|
||||||
|
@ -475,7 +474,7 @@ asan_protect_global (tree decl)
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16}.
|
/* Construct a function tree for __asan_report_{load,store}{1,2,4,8,16}.
|
||||||
|
@ -490,13 +489,13 @@ report_error_func (bool is_store, int size_in_bytes)
|
||||||
char name[100];
|
char name[100];
|
||||||
|
|
||||||
sprintf (name, "__asan_report_%s%d",
|
sprintf (name, "__asan_report_%s%d",
|
||||||
is_store ? "store" : "load", size_in_bytes);
|
is_store ? "store" : "load", size_in_bytes);
|
||||||
fn_type = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
|
fn_type = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
|
||||||
def = build_fn_decl (name, fn_type);
|
def = build_fn_decl (name, fn_type);
|
||||||
TREE_NOTHROW (def) = 1;
|
TREE_NOTHROW (def) = 1;
|
||||||
TREE_THIS_VOLATILE (def) = 1; /* Attribute noreturn. Surprise! */
|
TREE_THIS_VOLATILE (def) = 1; /* Attribute noreturn. Surprise! */
|
||||||
DECL_ATTRIBUTES (def) = tree_cons (get_identifier ("leaf"),
|
DECL_ATTRIBUTES (def) = tree_cons (get_identifier ("leaf"),
|
||||||
NULL, DECL_ATTRIBUTES (def));
|
NULL, DECL_ATTRIBUTES (def));
|
||||||
DECL_ASSEMBLER_NAME (def);
|
DECL_ASSEMBLER_NAME (def);
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
@ -598,7 +597,7 @@ create_cond_insert_point (gimple_stmt_iterator *iter,
|
||||||
outcoming edge of the 'then block' -- starts with the statement
|
outcoming edge of the 'then block' -- starts with the statement
|
||||||
pointed to by ITER.
|
pointed to by ITER.
|
||||||
|
|
||||||
COND is the condition of the if.
|
COND is the condition of the if.
|
||||||
|
|
||||||
If THEN_MORE_LIKELY_P is true, the probability of the edge to the
|
If THEN_MORE_LIKELY_P is true, the probability of the edge to the
|
||||||
'then block' is higher than the probability of the edge to the
|
'then block' is higher than the probability of the edge to the
|
||||||
|
@ -796,7 +795,7 @@ build_check_stmt (location_t location, tree base, gimple_stmt_iterator *iter,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
instrument_derefs (gimple_stmt_iterator *iter, tree t,
|
instrument_derefs (gimple_stmt_iterator *iter, tree t,
|
||||||
location_t location, bool is_store)
|
location_t location, bool is_store)
|
||||||
{
|
{
|
||||||
tree type, base;
|
tree type, base;
|
||||||
HOST_WIDE_INT size_in_bytes;
|
HOST_WIDE_INT size_in_bytes;
|
||||||
|
@ -864,7 +863,7 @@ instrument_mem_region_access (tree base, tree len,
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
{
|
{
|
||||||
//asan instrumentation code goes here.
|
//asan instrumentation code goes here.
|
||||||
}
|
}
|
||||||
// falltrough instructions, starting with *ITER. */
|
// falltrough instructions, starting with *ITER. */
|
||||||
|
|
||||||
gimple g = gimple_build_cond (NE_EXPR,
|
gimple g = gimple_build_cond (NE_EXPR,
|
||||||
|
@ -930,7 +929,7 @@ instrument_mem_region_access (tree base, tree len,
|
||||||
region_end =
|
region_end =
|
||||||
gimple_build_assign_with_ops (POINTER_PLUS_EXPR,
|
gimple_build_assign_with_ops (POINTER_PLUS_EXPR,
|
||||||
make_ssa_name (TREE_TYPE (base), NULL),
|
make_ssa_name (TREE_TYPE (base), NULL),
|
||||||
gimple_assign_lhs (region_end),
|
gimple_assign_lhs (region_end),
|
||||||
gimple_assign_lhs (offset));
|
gimple_assign_lhs (offset));
|
||||||
gimple_set_location (region_end, location);
|
gimple_set_location (region_end, location);
|
||||||
gsi_insert_after (&gsi, region_end, GSI_NEW_STMT);
|
gsi_insert_after (&gsi, region_end, GSI_NEW_STMT);
|
||||||
|
@ -1378,7 +1377,7 @@ transform_statements (void)
|
||||||
{
|
{
|
||||||
if (bb->index >= saved_last_basic_block) continue;
|
if (bb->index >= saved_last_basic_block) continue;
|
||||||
for (i = gsi_start_bb (bb); !gsi_end_p (i);)
|
for (i = gsi_start_bb (bb); !gsi_end_p (i);)
|
||||||
{
|
{
|
||||||
gimple s = gsi_stmt (i);
|
gimple s = gsi_stmt (i);
|
||||||
|
|
||||||
if (gimple_assign_single_p (s))
|
if (gimple_assign_single_p (s))
|
||||||
|
@ -1391,7 +1390,7 @@ transform_statements (void)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
gsi_next (&i);
|
gsi_next (&i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1594,18 +1593,18 @@ struct gimple_opt_pass pass_asan =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
GIMPLE_PASS,
|
GIMPLE_PASS,
|
||||||
"asan", /* name */
|
"asan", /* name */
|
||||||
OPTGROUP_NONE, /* optinfo_flags */
|
OPTGROUP_NONE, /* optinfo_flags */
|
||||||
gate_asan, /* gate */
|
gate_asan, /* gate */
|
||||||
asan_instrument, /* execute */
|
asan_instrument, /* execute */
|
||||||
NULL, /* sub */
|
NULL, /* sub */
|
||||||
NULL, /* next */
|
NULL, /* next */
|
||||||
0, /* static_pass_number */
|
0, /* static_pass_number */
|
||||||
TV_NONE, /* tv_id */
|
TV_NONE, /* tv_id */
|
||||||
PROP_ssa | PROP_cfg | PROP_gimple_leh,/* properties_required */
|
PROP_ssa | PROP_cfg | PROP_gimple_leh,/* properties_required */
|
||||||
0, /* properties_provided */
|
0, /* properties_provided */
|
||||||
0, /* properties_destroyed */
|
0, /* properties_destroyed */
|
||||||
0, /* todo_flags_start */
|
0, /* todo_flags_start */
|
||||||
TODO_verify_flow | TODO_verify_stmts
|
TODO_verify_flow | TODO_verify_stmts
|
||||||
| TODO_update_ssa /* todo_flags_finish */
|
| TODO_update_ssa /* todo_flags_finish */
|
||||||
}
|
}
|
||||||
|
@ -1622,7 +1621,7 @@ struct gimple_opt_pass pass_asan_O0 =
|
||||||
{
|
{
|
||||||
GIMPLE_PASS,
|
GIMPLE_PASS,
|
||||||
"asan0", /* name */
|
"asan0", /* name */
|
||||||
OPTGROUP_NONE, /* optinfo_flags */
|
OPTGROUP_NONE, /* optinfo_flags */
|
||||||
gate_asan_O0, /* gate */
|
gate_asan_O0, /* gate */
|
||||||
asan_instrument, /* execute */
|
asan_instrument, /* execute */
|
||||||
NULL, /* sub */
|
NULL, /* sub */
|
||||||
|
|
Loading…
Reference in New Issue