(CC’ing Kees Cook on this topic)

Hi, 

This is the first version of the complete patch for the new security feature 
for GCC: 

Initialize automatic variables with new first class option 
-ftrivial-auto-var-init=[uninitialized|pattern|zero] 
and  a new variable attribute “uninitialized” to exclude some variables from 
automatical initialization to
Control runtime overhead.

====

'-ftrivial-auto-var-init=CHOICE'
     Initialize automatic variables with either a pattern or with zeroes
     to increase program security by preventing uninitialized memory
     disclosure and use.

     The three values of CHOICE are:

        * 'uninitialized' doesn't initialize any automatic variables.
          This is C and C++'s default.

        * 'pattern' Initialize automatic variables with values which
          will likely transform logic bugs into crashes down the line,
          are easily recognized in a crash dump and without being values
          that programmers can rely on for useful program semantics.
          The values used for pattern initialization might be changed in
          the future.

        * 'zero' Initialize automatic variables with zeroes.

     The default is 'uninitialized'.

     You can control this behavior for a specific variable by using the
     variable attribute 'uninitialized' (*note Variable Attributes::).

'uninitialized'
     This attribute, attached to a variable with automatic storage,
     means that the variable should not be automatically initialized by
     the compiler when the option '-ftrivial-auto-var-init' presents.

     With the option '-ftrivial-auto-var-init', all the automatic
     variables that do not have explicit initializers will be
     initialized by the compiler.  These additional compiler
     initializations might incur run-time overhead, sometimes
     dramatically.  This attribute can be used to mark some variables to
     be excluded from such automatical initialization in order to reduce
     runtime overhead.

     This attribute has no effect when the option
     '-ftrivial-auto-var-init' does not present.
====

******This implementation has the following features:

1.  A new internal function .DEFERRED_INIT is introduced;
2.  During gimplification phase, calls to .DEFERRED_INIT will be inserted for 
the initialization;
3.  During expand phase, calls to .DEFERRED_INIT are expanded to real “zero” or 
“pattern” initialization;
4.  In order to maintain the -Wuninitialized warning,  uninitialized warning 
phase is adjusted to specially
     handling the calls to .DEFERRED_INIT;
5.  In order to reduce the stack usage per strength reduction transformation, 
the strength reduction phase
     Is adjusted to specially handle the calls to .DEFERRED_INIT;
6.  Point to analysis also is adjusted to specially handle the calls to 
.DEFERRED_INIT;
7.  VLA auto variables are initialized specially, for “zero” initialization, 
add a call to MEMSET to initialize it;
     for “pattern” initialization, add a loop of calls to MEMCPY to initialize 
it;
8.  For “pattern” initialization, used the similar patten as LLVM 
implementation for integers and pointers:
+  /* The following value is a guaranteed unmappable pointer value and has a
+     repeated byte-pattern which makes it easier to synthesize.  We use it for
+     pointers as well as integers so that aggregates are likely to be
+     initialized with this repeated value.  */
+  uint64_t largevalue = 0xAAAAAAAAAAAAAAAAull;
+  /* For 32-bit platforms it's a bit trickier because, across systems, only the
+     zero page can reasonably be expected to be unmapped, and even then we need
+     a very low address.  We use a smaller value, and that value sadly doesn't
+     have a repeated byte-pattern.  We don't use it for integers.  */
+  uint32_t smallvalue = 0x000000AA;

Use quiet NAN for real type. 

******testing cases:

1. In c-c++-common, verification at gimple level for all types, all combination 
of options, new attributes;
2. In gcc.target, (for x86 and aarch64) verification at RTL or assembly level 
for all types, all combination of options, new attributes;
3. In gcc.dg and g++.dg, verification of the new option still keep the 
-Wuninitialized warnings.  Copy the existing uninit-*.c to
   auto-init-uninit-*.c, add the new option -ftrivial-auto-var-init=zero to it.


******NOTE for the review:

****In this version implementation, I still keep the implementation to the 
following two approaches for your references:

A. Adding real initialization during gimplification, not maintain the 
uninitialized warnings.
D. Adding .DEFFERED_INIT during gimplification, expand the .DEFFERED_INIT 
during expand to
    real initialization. Adjusting uninitialized pass with the new refs with 
“.DEFFERED_INIT”

A is the approach that I will delete in the next version. D will be the one we 
choose. 

(The reason I kept both implementation is, please check the implementation for 
both A and D 
 since the performance, code size, stack size data are all based on the 
comparison between A and D,
 Please help me to make sure both the implementation is correct)

Currently, there is a first class option -fauto-var-init-approach=[A|B|C|D]. is 
added to choose A or D. 

If after the review, there is no issue, I will delete the code related to “A” 
in the next version. 

****There are several places, I put “FIXME” in the comments, please review 
those part and let me 
know any issues with those parts. 

*******Changelog:

gcc/ChangeLog:

2021-02-17  qing zhao  <qing.z...@oracle.com <mailto:qing.z...@oracle.com>>

        * common.opt (ftrivial-auto-var-init=): New.
        (fauto-var-init-approach=): Likewise.
        * doc/extend.texi: Document the uninitialized attribute.
        * doc/invoke.texi: Document -ftrivial-auto-var-init.
        * flag-types.h (enum auto_init_type): New enumerated type
        auto_init_type.
        (enum auto_init_approach): New enumerated type auto_init_approach.
        * gimple.h (enum gf_mask): Add GF_CALL_MEMSET_FOR_UNINIT case.
        (gimple_call_set_memset_for_uninit): New function.
        (gimple_call_memset_for_uninit_p): Likewise.
        * gimplify.c (gimplify_vla_decl): Add initialization to vla per users'
        requests. 
        (build_deferred_init): New function.
        (gimple_add_init_for_auto_var): Likewise.
        (gimplify_decl_expr): Add initialization to automatic variables per
        users' requests.
        * internal-fn.c (expand_DEFERRED_INIT): New function.
        * internal-fn.def (DEFERRED_INIT): New internal function.
        * tree-cfg.c (verify_gimple_call): Skip calls to DEFERRED_INIT.
        * tree-core.h (tree_decl_with_vis): Add uninitialized field.
        * tree-sra.c (sra_stats): Add two new fields deferred_init and
        subtree_deferred_init.
        (generate_subtree_deferred_init): New function.
        (sra_modify_deferred_init): Likewise.
        (sra_modify_function_body): Handle calls to DEFERRED_INIT specially.
        * tree-ssa-structalias.c (find_func_aliases_for_deferred_init): New
        function.
        (find_func_aliases_for_call): Handle calls to DEFERRED_INIT specially.
        * tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT
        specially.
        (check_defs): Handle calls to DEFERRED_INIT and MEMSET for uninitialized
        variable specially.
        (warn_uninitialized_vars): Handle calls to DEFERRED_INIT specially.
        * tree-ssa.c (ssa_undefined_value_p): Handle calls to DEFERRED_INIT
        specially.
        * tree.c (build_pattern_cst): New function.
        * tree.h (DECL_UNINITIALIZED): New macro.
        (build_pattern_cst): New declaration.

gcc/c-family/ChangeLog:

2021-02-17  qing zhao  <qing.z...@oracle.com <mailto:qing.z...@oracle.com>>

        * c-attribs.c (handle_uninitialized_attribute): New function.
        (c_common_attribute_table): Add "uninitialized" attribute.

gcc/testsuite/ChangeLog:

2021-02-17  qing zhao  <qing.z...@oracle.com <mailto:qing.z...@oracle.com>>

        * c-c++-common/auto-init-1.c: New test.
        * c-c++-common/auto-init-10.c: New test.
        * c-c++-common/auto-init-11.c: New test.
        * c-c++-common/auto-init-12.c: New test.
        * c-c++-common/auto-init-2.c: New test.
        * c-c++-common/auto-init-3.c: New test.
        * c-c++-common/auto-init-4.c: New test.
        * c-c++-common/auto-init-5.c: New test.
        * c-c++-common/auto-init-6.c: New test.
        * c-c++-common/auto-init-7.c: New test.
        * c-c++-common/auto-init-8.c: New test.
        * c-c++-common/auto-init-9.c: New test.
        * c-c++-common/auto-init-esra.c: New test.
        * g++.dg/auto-init-uninit-pred-1_a.C: New test.
        * g++.dg/auto-init-uninit-pred-1_b.C: New test.
        * g++.dg/auto-init-uninit-pred-2_a.C: New test.
        * g++.dg/auto-init-uninit-pred-2_b.C: New test.
        * g++.dg/auto-init-uninit-pred-3_a.C: New test.
        * g++.dg/auto-init-uninit-pred-3_b.C: New test.
        * g++.dg/auto-init-uninit-pred-4.C: New test.
        * g++.dg/auto-init-uninit-pred-loop-1_a.cc 
<http://auto-init-uninit-pred-loop-1_a.cc/>: New test.
        * g++.dg/auto-init-uninit-pred-loop-1_b.cc 
<http://auto-init-uninit-pred-loop-1_b.cc/>: New test.
        * g++.dg/auto-init-uninit-pred-loop-1_c.cc 
<http://auto-init-uninit-pred-loop-1_c.cc/>: New test.
        * g++.dg/auto-init-uninit-pred-loop_1.cc 
<http://auto-init-uninit-pred-loop_1.cc/>: New test.
        * gcc.dg/auto-init-uninit-1.c: New test.
        * gcc.dg/auto-init-uninit-11.c: New test.
        * gcc.dg/auto-init-uninit-12.c: New test.
        * gcc.dg/auto-init-uninit-13.c: New test.
        * gcc.dg/auto-init-uninit-14.c: New test.
        * gcc.dg/auto-init-uninit-15.c: New test.
        * gcc.dg/auto-init-uninit-16.c: New test.
        * gcc.dg/auto-init-uninit-17.c: New test.
        * gcc.dg/auto-init-uninit-18.c: New test.
        * gcc.dg/auto-init-uninit-19.c: New test.
        * gcc.dg/auto-init-uninit-2.c: New test.
        * gcc.dg/auto-init-uninit-20.c: New test.
        * gcc.dg/auto-init-uninit-21.c: New test.
        * gcc.dg/auto-init-uninit-22.c: New test.
        * gcc.dg/auto-init-uninit-23.c: New test.
        * gcc.dg/auto-init-uninit-24.c: New test.
        * gcc.dg/auto-init-uninit-25.c: New test.
        * gcc.dg/auto-init-uninit-26.c: New test.
        * gcc.dg/auto-init-uninit-3.c: New test.
        * gcc.dg/auto-init-uninit-34.c: New test.
        * gcc.dg/auto-init-uninit-36.c: New test.
        * gcc.dg/auto-init-uninit-37.c: New test.
        * gcc.dg/auto-init-uninit-4.c: New test.
        * gcc.dg/auto-init-uninit-5.c: New test.
        * gcc.dg/auto-init-uninit-6.c: New test.
        * gcc.dg/auto-init-uninit-8.c: New test.
        * gcc.dg/auto-init-uninit-9.c: New test.
        * gcc.dg/auto-init-uninit-A.c: New test.
        * gcc.dg/auto-init-uninit-B.c: New test.
        * gcc.dg/auto-init-uninit-C.c: New test.
        * gcc.dg/auto-init-uninit-H.c: New test.
        * gcc.dg/auto-init-uninit-I.c: New test.
        * gcc.target/aarch64/auto-init-1.c: New test.
        * gcc.target/aarch64/auto-init-2.c: New test.
        * gcc.target/aarch64/auto-init-3.c: New test.
        * gcc.target/aarch64/auto-init-4.c: New test.
        * gcc.target/aarch64/auto-init-5.c: New test.
        * gcc.target/aarch64/auto-init-6.c: New test.
        * gcc.target/aarch64/auto-init-7.c: New test.
        * gcc.target/aarch64/auto-init-8.c: New test.
        * gcc.target/i386/auto-init-1.c: New test.
        * gcc.target/i386/auto-init-2.c: New test.
        * gcc.target/i386/auto-init-3.c: New test.
        * gcc.target/i386/auto-init-4.c: New test.
        * gcc.target/i386/auto-init-5.c: New test.
        * gcc.target/i386/auto-init-6.c: New test.
        * gcc.target/i386/auto-init-7.c: New test.
        * gcc.target/i386/auto-init-8.c: New test.


******the complete patch:

See the attachment.


Reply via email to