[Ada] introduce stack scrub (strub) feature
gcc/ada/ * doc/gnat_rm.rst: Add... * doc/gnat_rm/security_hardening_features.rst: New. * doc/gnat_rm/about_this_guide.rst: Link to new chapter. * gnat_rm.texi: Regenerate. * gcc-interface/utils.c (handle_strub_attribute): New. (gnat_internal_attribute_table): Add strub. * libgnat/a-except.adb: Make Rcheck_CE_* strub-callable. * libgnat/a-except.ads (Raise_Exception): Likewise. (Raise_Exception_Always): Likewise. * libgnat/s-arit128.ads (Multiply_With_Ovflo_Check128): Likewise. * libgnat/s-arit64.ads (Multiply_With_Ovflo_Check64): Likewise. * libgnat/s-secsta.ads (SS_Allocate, SS_Mark, SS_Release): Likewise.
This commit is contained in:
parent
b1657ff3a0
commit
a23e02091e
@ -55,6 +55,7 @@ GNAT Reference Manual
|
||||
gnat_rm/specialized_needs_annexes
|
||||
gnat_rm/implementation_of_specific_ada_features
|
||||
gnat_rm/implementation_of_ada_2012_features
|
||||
gnat_rm/security_hardening_features
|
||||
gnat_rm/obsolescent_features
|
||||
gnat_rm/compatibility_and_porting_guide
|
||||
|
||||
|
@ -96,6 +96,9 @@ This reference manual contains the following chapters:
|
||||
* :ref:`Implementation_of_Ada_2012_Features`, describes the status of the
|
||||
GNAT implementation of the Ada 2012 language standard.
|
||||
|
||||
* :ref:`Security_Hardening_Features` documents GNAT extensions aimed
|
||||
at security hardening.
|
||||
|
||||
* :ref:`Obsolescent_Features` documents implementation dependent features,
|
||||
including pragmas and attributes, which are considered obsolescent, since
|
||||
there are other preferred ways of achieving the same results. These
|
||||
|
89
gcc/ada/doc/gnat_rm/security_hardening_features.rst
Normal file
89
gcc/ada/doc/gnat_rm/security_hardening_features.rst
Normal file
@ -0,0 +1,89 @@
|
||||
.. _Security_Hardening_Features:
|
||||
|
||||
***************************
|
||||
Security Hardening Features
|
||||
***************************
|
||||
|
||||
This chapter describes Ada extensions aimed at security hardening that
|
||||
are provided by GNAT.
|
||||
|
||||
.. Register Scrubbing:
|
||||
|
||||
Register Scrubbing
|
||||
==================
|
||||
|
||||
GNAT can generate code to zero-out hardware registers before returning
|
||||
from a subprogram.
|
||||
|
||||
It can be enabled with the *-fzero-call-used-regs* command line
|
||||
option, to affect all subprograms in a compilation, and with a
|
||||
:samp:`Machine_Attribute` pragma, to affect only specific subprograms.
|
||||
|
||||
.. code-block:: ada
|
||||
|
||||
procedure Foo;
|
||||
pragma Machine_Attribute (Foo, "zero_call_used_regs", "used");
|
||||
-- Before returning, Foo scrubs only call-clobbered registers
|
||||
-- that it uses itself.
|
||||
|
||||
function Bar return Integer;
|
||||
pragma Machine_Attribute (Bar, "zero_call_used_regs", "all");
|
||||
-- Before returning, Bar scrubs all call-clobbered registers.
|
||||
|
||||
|
||||
For usage and more details on the command line option, and on the
|
||||
``zero_call_used_regs`` attribute, see :title:`Using the GNU Compiler
|
||||
Collection (GCC)`.
|
||||
|
||||
|
||||
.. Stack Scrubbing:
|
||||
|
||||
Stack Scrubbing
|
||||
===============
|
||||
|
||||
GNAT can generate code to zero-out stack frames used by subprograms.
|
||||
|
||||
It can be activated with the :samp:`Machine_Attribute` pragma, on
|
||||
specific subprograms and variables.
|
||||
|
||||
.. code-block:: ada
|
||||
|
||||
function Foo returns Integer;
|
||||
pragma Machine_Attribute (Foo, "strub");
|
||||
-- Foo and its callers are modified so as to scrub the stack
|
||||
-- space used by Foo after it returns.
|
||||
|
||||
procedure Bar;
|
||||
pragma Machine_Attribute (Bar, "strub", "internal");
|
||||
-- Bar is turned into a wrapper for its original body,
|
||||
-- and they scrub the stack used by the original body.
|
||||
|
||||
Var : Integer;
|
||||
pragma Machine_Attribute (Var, "strub");
|
||||
-- Reading from Var in a subprogram enables stack scrubbing
|
||||
-- of the stack space used by the subprogram.
|
||||
|
||||
|
||||
There are also *-fstrub* command line options to control default
|
||||
settings. For usage and more details on the command line option, and
|
||||
on the ``strub`` attribute, see :title:`Using the GNU Compiler
|
||||
Collection (GCC)`.
|
||||
|
||||
Note that Ada secondary stacks are not scrubbed. The restriction
|
||||
``No_Secondary_Stack`` avoids their use, and thus their accidental
|
||||
preservation of data that should be scrubbed.
|
||||
|
||||
Also note that the machine attribute is not integrated in the Ada type
|
||||
system. Though it may modify subprogram and variable interfaces, it
|
||||
is not fully reflected in Ada types, ``Access`` attributes, renaming
|
||||
and overriding. Every access type, renaming, and overriding and
|
||||
overridden dispatching operations that may refer to an entity with an
|
||||
attribute-modified interface must be annotated with the same
|
||||
interface-modifying attribute, or with an interface-compatible one.
|
||||
|
||||
Even then, the pragma is currently only functional when applied to
|
||||
subprograms and scalar variables; other uses, such as directly on
|
||||
types and subtypes, may be silently ignored. Specifically, it is not
|
||||
currently recommended to rely on any effects this pragma might be
|
||||
expected to have when calling subprograms through access-to-subprogram
|
||||
variables.
|
@ -94,6 +94,7 @@ static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_no_stack_protector_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_strub_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
|
||||
@ -157,6 +158,8 @@ const struct attribute_spec gnat_internal_attribute_table[] =
|
||||
{ "no_stack_protector",0, 0, true, false, false, false,
|
||||
handle_no_stack_protector_attribute,
|
||||
attr_stack_protect_exclusions },
|
||||
{ "strub", 0, 1, false, true, false, true,
|
||||
handle_strub_attribute, NULL },
|
||||
{ "noinline", 0, 0, true, false, false, false,
|
||||
handle_noinline_attribute, NULL },
|
||||
{ "noclone", 0, 0, true, false, false, false,
|
||||
@ -6602,6 +6605,15 @@ handle_no_stack_protector_attribute (tree *node, tree name, tree, int,
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Handle a "strub" attribute; arguments as in
|
||||
struct attribute_spec.handler. */
|
||||
|
||||
static tree
|
||||
handle_strub_attribute (tree *, tree, tree, int, bool *no_add_attrs)
|
||||
{
|
||||
*no_add_attrs = true;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Handle a "noinline" attribute; arguments as in
|
||||
struct attribute_spec.handler. */
|
||||
|
1806
gcc/ada/gnat_rm.texi
1806
gcc/ada/gnat_rm.texi
File diff suppressed because it is too large
Load Diff
@ -629,6 +629,96 @@ package body Ada.Exceptions is
|
||||
pragma No_Return (Rcheck_CE_Invalid_Data_Ext);
|
||||
pragma No_Return (Rcheck_CE_Range_Check_Ext);
|
||||
|
||||
-- Make all of these procedures callable from strub contexts.
|
||||
-- These attributes are not visible to callers; they are made
|
||||
-- visible in trans.c:build_raise_check.
|
||||
|
||||
pragma Machine_Attribute (Rcheck_CE_Access_Check,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Null_Access_Parameter,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Discriminant_Check,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Divide_By_Zero,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Explicit_Raise,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Index_Check,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Invalid_Data,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Length_Check,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Null_Exception_Id,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Null_Not_Allowed,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Overflow_Check,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Partition_Check,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Range_Check,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Tag_Check,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Access_Before_Elaboration,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Accessibility_Check,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Address_Of_Intrinsic,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Aliased_Parameters,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_All_Guards_Closed,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Bad_Predicated_Generic_Type,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Build_In_Place_Mismatch,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Current_Task_In_Entry_Body,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Duplicated_Entry_Address,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Explicit_Raise,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Implicit_Return,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Misaligned_Address_Value,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Missing_Return,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Non_Transportable_Actual,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Overlaid_Controlled_Object,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Potentially_Blocking_Operation,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Stream_Operation_Not_Allowed,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Stubbed_Subprogram_Called,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Unchecked_Union_Restriction,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_PE_Finalize_Raised_Exception,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_SE_Empty_Storage_Pool,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_SE_Explicit_Raise,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_SE_Infinite_Recursion,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_SE_Object_Too_Large,
|
||||
"strub", "callable");
|
||||
|
||||
pragma Machine_Attribute (Rcheck_CE_Access_Check_Ext,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Index_Check_Ext,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Invalid_Data_Ext,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Rcheck_CE_Range_Check_Ext,
|
||||
"strub", "callable");
|
||||
|
||||
---------------------------------------------
|
||||
-- Reason Strings for Run-Time Check Calls --
|
||||
---------------------------------------------
|
||||
|
@ -184,6 +184,15 @@ private
|
||||
-- Raise_Exception_Always if it can determine this is the case. The Export
|
||||
-- allows this routine to be accessed from Pure units.
|
||||
|
||||
-- Make these callable from strub contexts.
|
||||
pragma Machine_Attribute (Raise_Exception_Always,
|
||||
"strub", "callable");
|
||||
pragma Machine_Attribute (Raise_Exception,
|
||||
"strub", "callable");
|
||||
-- This property should arguably be visible to callers, but let's
|
||||
-- keep it private for now. In practice, it doesn't matter, since
|
||||
-- it's only checked in the back end.
|
||||
|
||||
procedure Raise_From_Controlled_Operation (X : Exception_Occurrence);
|
||||
pragma No_Return (Raise_From_Controlled_Operation);
|
||||
pragma Export
|
||||
|
@ -81,4 +81,11 @@ package System.Arith_128 is
|
||||
-- then Q is the rounded quotient. The remainder R is not affected by the
|
||||
-- setting of the Round flag.
|
||||
|
||||
private
|
||||
-- Make it callable from strub contexts.
|
||||
-- There is a matching setting in trans.c,
|
||||
-- for calls issued by Gigi.
|
||||
pragma Machine_Attribute (Multiply_With_Ovflo_Check128,
|
||||
"strub", "callable");
|
||||
|
||||
end System.Arith_128;
|
||||
|
@ -93,4 +93,11 @@ package System.Arith_64 is
|
||||
Round : Boolean) renames Double_Divide64;
|
||||
-- Renamed procedure to preserve compatibility with earlier versions
|
||||
|
||||
private
|
||||
-- Make it callable from strub contexts.
|
||||
-- There is a matching setting in trans.c,
|
||||
-- for calls issued by Gigi.
|
||||
pragma Machine_Attribute (Multiply_With_Ovflo_Check64,
|
||||
"strub", "callable");
|
||||
|
||||
end System.Arith_64;
|
||||
|
@ -440,4 +440,9 @@ private
|
||||
function Get_Stack_Info (Stack : SS_Stack_Ptr) return Stack_Info;
|
||||
-- Obtain the information attributes of secondary stack Stack
|
||||
|
||||
pragma Machine_Attribute (SS_Allocate, "strub", "callable");
|
||||
pragma Machine_Attribute (SS_Mark, "strub", "callable");
|
||||
pragma Machine_Attribute (SS_Release, "strub", "callable");
|
||||
-- Enable these to be called from within strub contexts.
|
||||
|
||||
end System.Secondary_Stack;
|
||||
|
Loading…
x
Reference in New Issue
Block a user