diff options
author | Florian Weimer <fweimer@redhat.com> | 2014-05-09 14:23:46 +0200 |
---|---|---|
committer | Florian Weimer <fw@gcc.gnu.org> | 2014-05-09 14:23:46 +0200 |
commit | 6545746e3c784d94300954ccb155e6510c598ffa (patch) | |
tree | 6da35ec3f858b95d454e7bb32fb9dd5f8dc6c95c /gcc | |
parent | b8d29c66597d6ff2a41ca6a190c0bd52126f491d (diff) | |
download | gcc-6545746e3c784d94300954ccb155e6510c598ffa.zip gcc-6545746e3c784d94300954ccb155e6510c598ffa.tar.gz gcc-6545746e3c784d94300954ccb155e6510c598ffa.tar.bz2 |
-fstack-protector-strong: Instrumentation for return slots
This patch fixes a loophole in the -fstack-protector-strong protection.
If a function call uses a return slot, the caller needs stack protector
instrumentation because the return slot is addressable.
gcc/
2014-05-09 Florian Weimer <fweimer@redhat.com>
* cfgexpand.c (stack_protect_decl_p): New function, extracted from
expand_used_vars.
(stack_protect_return_slot_p): New function.
(expand_used_vars): Call stack_protect_decl_p and
stack_protect_return_slot_p for -fstack-protector-strong.
gcc/testsuite/
2014-05-09 Florian Weimer <fweimer@redhat.com>
* gcc.dg/fstack-protector-strong.c: Add coverage for return slots.
* g++.dg/fstack-protector-strong.C: Likewise.
* gcc.target/i386/ssp-strong-reg.c: New file.
From-SVN: r210275
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/cfgexpand.c | 64 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/fstack-protector-strong.C | 50 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/fstack-protector-strong.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/ssp-strong-reg.c | 19 |
6 files changed, 149 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index ffe31f3..6b508f7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2014-05-09 Florian Weimer <fweimer@redhat.com> + + * cfgexpand.c (stack_protect_decl_p): New function, extracted from + expand_used_vars. + (stack_protect_return_slot_p): New function. + (expand_used_vars): Call stack_protect_decl_p and + stack_protect_return_slot_p for -fstack-protector-strong. + 2014-05-06 Kenneth Zadeck <zadeck@naturalbridge.com> PR middle-end/61111 diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index b57fac1..934f40d 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -1611,6 +1611,52 @@ record_or_union_type_has_array_p (const_tree tree_type) return 0; } +/* Check if the current function has local referenced variables that + have their addresses taken, contain an array, or are arrays. */ + +static bool +stack_protect_decl_p () +{ + unsigned i; + tree var; + + FOR_EACH_LOCAL_DECL (cfun, i, var) + if (!is_global_var (var)) + { + tree var_type = TREE_TYPE (var); + if (TREE_CODE (var) == VAR_DECL + && (TREE_CODE (var_type) == ARRAY_TYPE + || TREE_ADDRESSABLE (var) + || (RECORD_OR_UNION_TYPE_P (var_type) + && record_or_union_type_has_array_p (var_type)))) + return true; + } + return false; +} + +/* Check if the current function has calls that use a return slot. */ + +static bool +stack_protect_return_slot_p () +{ + basic_block bb; + + FOR_ALL_BB_FN (bb, cfun) + for (gimple_stmt_iterator gsi = gsi_start_bb (bb); + !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + /* This assumes that calls to internal-only functions never + use a return slot. */ + if (is_gimple_call (stmt) + && !gimple_call_internal_p (stmt) + && aggregate_value_p (TREE_TYPE (gimple_call_fntype (stmt)), + gimple_call_fndecl (stmt))) + return true; + } + return false; +} + /* Expand all variables used in the function. */ static rtx @@ -1683,22 +1729,8 @@ expand_used_vars (void) pointer_map_destroy (ssa_name_decls); if (flag_stack_protect == SPCT_FLAG_STRONG) - FOR_EACH_LOCAL_DECL (cfun, i, var) - if (!is_global_var (var)) - { - tree var_type = TREE_TYPE (var); - /* Examine local referenced variables that have their addresses taken, - contain an array, or are arrays. */ - if (TREE_CODE (var) == VAR_DECL - && (TREE_CODE (var_type) == ARRAY_TYPE - || TREE_ADDRESSABLE (var) - || (RECORD_OR_UNION_TYPE_P (var_type) - && record_or_union_type_has_array_p (var_type)))) - { - gen_stack_protect_signal = true; - break; - } - } + gen_stack_protect_signal + = stack_protect_decl_p () || stack_protect_return_slot_p (); /* At this point all variables on the local_decls with TREE_USED set are not associated with any block scope. Lay them out. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8918976..9092cba 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2014-05-09 Florian Weimer <fweimer@redhat.com> + + * gcc.dg/fstack-protector-strong.c: Add coverage for return slots. + * g++.dg/fstack-protector-strong.C: Likewise. + * gcc.target/i386/ssp-strong-reg.c: New file. + 2014-05-09 Georg-Johann Lay <avr@gjlay.de> PR target/61055 diff --git a/gcc/testsuite/g++.dg/fstack-protector-strong.C b/gcc/testsuite/g++.dg/fstack-protector-strong.C index a4f0f81..5a820ed 100644 --- a/gcc/testsuite/g++.dg/fstack-protector-strong.C +++ b/gcc/testsuite/g++.dg/fstack-protector-strong.C @@ -32,4 +32,52 @@ int foo2 () return global_func (a); } -/* { dg-final { scan-assembler-times "stack_chk_fail" 2 } } */ +/* Frame addressed exposed through return slot. */ + +struct B +{ + /* Discourage passing this struct in registers. */ + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; + int method (); + B return_slot(); +}; + +B global_func (); +void noop (); + +int foo3 () +{ + return global_func ().a1; +} + +int foo4 () +{ + try { + noop (); + return 0; + } catch (...) { + return global_func ().a1; + } +} + +int foo5 () +{ + try { + return global_func ().a1; + } catch (...) { + return 0; + } +} + +int foo6 () +{ + B b; + return b.method (); +} + +int foo7 (B *p) +{ + return p->return_slot ().a1; +} + +/* { dg-final { scan-assembler-times "stack_chk_fail" 7 } } */ diff --git a/gcc/testsuite/gcc.dg/fstack-protector-strong.c b/gcc/testsuite/gcc.dg/fstack-protector-strong.c index 7c232ff..da33abb 100644 --- a/gcc/testsuite/gcc.dg/fstack-protector-strong.c +++ b/gcc/testsuite/gcc.dg/fstack-protector-strong.c @@ -131,4 +131,22 @@ foo10 () return bb.three; } -/* { dg-final { scan-assembler-times "stack_chk_fail" 10 } } */ +struct B +{ + /* Discourage passing this struct in registers. */ + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10; +}; + +struct B global3 (void); + +int foo11 () +{ + return global3 ().a1; +} + +void foo12 () +{ + global3 (); +} + +/* { dg-final { scan-assembler-times "stack_chk_fail" 12 } } */ diff --git a/gcc/testsuite/gcc.target/i386/ssp-strong-reg.c b/gcc/testsuite/gcc.target/i386/ssp-strong-reg.c new file mode 100644 index 0000000..9fe5664 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/ssp-strong-reg.c @@ -0,0 +1,19 @@ +/* Test that structs returned in registers do not lead to + instrumentation with -fstack-protector-strong. */ + +/* { dg-do compile { target { ! { ia32 } } } } */ +/* { dg-options "-O2 -fstack-protector-strong" } */ + +struct S { + int a; + int b; +}; + +struct S f (void); + +int g (void) +{ + return f ().a; +} + +/* { dg-final { scan-assembler-times "stack_chk_fail" 0 } } */ |