From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from rock.gnat.com (rock.gnat.com [205.232.38.15]) by sourceware.org (Postfix) with ESMTPS id 1EAC8385840A for ; Fri, 29 Jul 2022 06:24:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 1EAC8385840A Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id 6C4141168D2; Fri, 29 Jul 2022 02:24:40 -0400 (EDT) X-Virus-Scanned: Debian amavisd-new at gnat.com Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id WDdh6gqrM53m; Fri, 29 Jul 2022 02:24:40 -0400 (EDT) Received: from free.home (tron.gnat.com [IPv6:2620:20:4000:0:46a8:42ff:fe0e:e294]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by rock.gnat.com (Postfix) with ESMTPS id 762CE1168CD; Fri, 29 Jul 2022 02:24:39 -0400 (EDT) Received: from livre (livre.home [172.31.160.2]) by free.home (8.15.2/8.15.2) with ESMTPS id 26T6OTQ71851928 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 29 Jul 2022 03:24:29 -0300 From: Alexandre Oliva To: gcc-patches@gcc.gnu.org Cc: Jeremy Bennett , Craig Blackmore , Graham Markall , Martin Jambor , Jan Hubicka , Richard Biener , Jim Wilson Subject: [PATCH v2 01/10] Introduce strub: documentation, and new command-line options Organization: Free thinker, does not speak for AdaCore References: Errors-To: aoliva@lxoliva.fsfla.org Date: Fri, 29 Jul 2022 03:24:29 -0300 In-Reply-To: (Alexandre Oliva's message of "Fri, 29 Jul 2022 03:16:41 -0300") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Scanned-By: MIMEDefang 2.84 X-Spam-Status: No, score=-12.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 29 Jul 2022 06:24:44 -0000 Ada already has some strub documentation in gcc/ada/doc/gnat_rm/security_hardening_features.rst. for gcc/ChangeLog * common.opt (fstrub=*): New options. * doc/extend.texi (strub): New type attribute. (__builtin_stack_address): New function. (Stack Scrubbing): New section. * doc/invoke.texi (-fstrub=*): New options. (-fdump-ipa-*): New passes. diff --git a/gcc/common.opt b/gcc/common.opt index e7a51e882bade..2c635806bbf2c 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2780,6 +2780,35 @@ fstrict-overflow Common Treat signed overflow as undefined. Negated as -fwrapv -fwrapv-pointer. +fstrub=disable +Common RejectNegative Var(flag_strub, 0) +Disable stack scrub entirely, disregarding strub attributes. + +fstrub=strict +Common RejectNegative Var(flag_strub, -4) +Enable stack scrub as per attributes, with strict call checking. + +; If any strub-enabling attribute is seen when the default or strict +; initializer values are in effect, flag_strub is bumped up by 2. The +; scrub mode gate function will then bump these initializer values to +; 0 if no strub-enabling attribute is seen. This minimizes the strub +; overhead. +fstrub=relaxed +Common RejectNegative Var(flag_strub, -3) Init(-3) +Restore default strub mode: as per attributes, with relaxed checking. + +fstrub=all +Common RejectNegative Var(flag_strub, 3) +Enable stack scrubbing for all viable functions. + +fstrub=at-calls +Common RejectNegative Var(flag_strub, 1) +Enable at-calls stack scrubbing for all viable functions. + +fstrub=internal +Common RejectNegative Var(flag_strub, 2) +Enable internal stack scrubbing for all viable functions. + fsync-libcalls Common Var(flag_sync_libcalls) Init(1) Implement __atomic operations via libcalls to legacy __sync functions. diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 7fe7f8817cdd4..90d38c9f08362 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -77,6 +77,7 @@ extensions, accepted by GCC in C90 mode and in C++. * Function Names:: Printable strings which are the name of the current function. * Return Address:: Getting the return or frame address of a function. +* Stack Scrubbing:: Stack scrubbing internal interfaces. * Vector Extensions:: Using vector instructions through built-in functions. * Offsetof:: Special syntax for implementing @code{offsetof}. * __sync Builtins:: Legacy built-in functions for atomic memory access. @@ -8890,6 +8891,263 @@ pid_t wait (wait_status_ptr_t p) @} @end smallexample +@item strub +@cindex @code{strub} type attribute +This attribute defines stack-scrubbing properties of functions and +variables. Being a type attribute, it attaches to types, even when +specified in function and variable declarations. When applied to +function types, it takes an optional string argument. When applied to a +pointer-to-function type, if the optional argument is given, it gets +propagated to the function type. + +@smallexample +/* A strub variable. */ +int __attribute__ ((strub)) var; +/* A strub variable that happens to be a pointer. */ +__attribute__ ((strub)) int *strub_ptr_to_int; +/* A pointer type that may point to a strub variable. */ +typedef int __attribute__ ((strub)) *ptr_to_strub_int_type; + +/* A declaration of a strub function. */ +extern int __attribute__ ((strub)) foo (void); +/* A pointer to that strub function. */ +int __attribute__ ((strub ("at-calls"))) (*ptr_to_strub_fn)(void) = foo; +@end smallexample + +A function associated with @code{at-calls} @code{strub} mode +(@code{strub("at-calls")}, or just @code{strub}) undergoes interface +changes. Its callers are adjusted to match the changes, and to scrub +(overwrite with zeros) the stack space used by the called function after +it returns. The interface change makes the function type incompatible +with an unadorned but otherwise equivalent type, so @emph{every} +declaration and every type that may be used to call the function must be +associated with this strub mode. + +A function associated with @code{internal} @code{strub} mode +(@code{strub("internal")}) retains an unmodified, type-compatible +interface, but it may be turned into a wrapper that calls the wrapped +body using a custom interface. The wrapper then scrubs the stack space +used by the wrapped body. Though the wrapped body has its stack space +scrubbed, the wrapper does not, so arguments and return values may +remain unscrubbed even when such a function is called by another +function that enables @code{strub}. This is why, when compiling with +@option{-fstrub=strict}, a @code{strub} context is not allowed to call +@code{internal} @code{strub} functions. + +@smallexample +/* A declaration of an internal-strub function. */ +extern int __attribute__ ((strub ("internal"))) bar (void); + +int __attribute__ ((strub)) +baz (void) +@{ + /* Ok, foo was declared above as an at-calls strub function. */ + foo (); + /* Not allowed in strict mode, otherwise allowed. */ + bar (); +@} +@end smallexample + +An automatically-allocated variable associated with the @code{strub} +attribute causes the (immediately) enclosing function to have +@code{strub} enabled. + +A statically-allocated variable associated with the @code{strub} +attribute causes functions that @emph{read} it, through its @code{strub} +data type, to have @code{strub} enabled. Reading data by dereferencing +a pointer to a @code{strub} data type has the same effect. Note: The +attribute does not carry over from a composite type to the types of its +components, so the intended effect may not be obtained with non-scalar +types. + +When selecting a @code{strub}-enabled mode for a function that is not +explicitly associated with one, because of @code{strub} variables or +data pointers, the function must satisfy @code{internal} mode viability +requirements (see below), even when @code{at-calls} mode is also viable +and, being more efficient, ends up selected as an optimization. + +@smallexample +/* zapme is implicitly strub-enabled because of strub variables. + Optimization may change its strub mode, but not the requirements. */ +static int +zapme (int i) +@{ + /* A local strub variable enables strub. */ + int __attribute__ ((strub)) lvar; + /* Reading strub data through a pointer-to-strub enables strub. */ + lvar = * (ptr_to_strub_int_type) &i; + /* Writing to a global strub variable does not enable strub. */ + var = lvar; + /* Reading from a global strub variable enables strub. */ + return var; +@} +@end smallexample + +A @code{strub} context is the body (as opposed to the interface) of a +function that has @code{strub} enabled, be it explicitly, by +@code{at-calls} or @code{internal} mode, or implicitly, due to +@code{strub} variables or command-line options. + +A function of a type associated with the @code{disabled} @code{strub} +mode (@code{strub("disabled")} will not have its own stack space +scrubbed. Such functions @emph{cannot} be called from within +@code{strub} contexts. + +In order to enable a function to be called from within @code{strub} +contexts without having its stack space scrubbed, associate it with the +@code{callable} @code{strub} mode (@code{strub("callable")}). + +When a function is not assigned a @code{strub} mode, explicitly or +implicitly, the mode defaults to @code{callable}, except when compiling +with @option{-fstrub=strict}, that causes @code{strub} mode to default +to @code{disabled}. + +@example +extern int __attribute__ ((strub ("callable"))) bac (void); +extern int __attribute__ ((strub ("disabled"))) bad (void); + /* Implicitly disabled with -fstrub=strict, otherwise callable. */ +extern int bah (void); + +int __attribute__ ((strub)) +bal (void) +@{ + /* Not allowed, bad is not strub-callable. */ + bad (); + /* Ok, bac is strub-callable. */ + bac (); + /* Not allowed with -fstrub=strict, otherwise allowed. */ + bah (); +@} +@end example + +Function types marked @code{callable} and @code{disabled} are not +mutually compatible types, but the underlying interfaces are compatible, +so it is safe to convert pointers between them, and to use such pointers +or alternate declarations to call them. Interfaces are also +interchangeable between them and @code{internal} (but not +@code{at-calls}!), but adding @code{internal} to a pointer type will not +cause the pointed-to function to perform stack scrubbing. + +@example +void __attribute__ ((strub)) +bap (void) +@{ + /* Assign a callable function to pointer-to-disabled. + Flagged as not quite compatible with -Wpedantic. */ + int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bac; + /* Not allowed: calls disabled type in a strub context. */ + d_p (); + + /* Assign a disabled function to pointer-to-callable. + Flagged as not quite compatible with -Wpedantic. */ + int __attribute__ ((strub ("callable"))) (*c_p) (void) = bad; + /* Ok, safe. */ + c_p (); + + /* Assign an internal function to pointer-to-callable. + Flagged as not quite compatible with -Wpedantic. */ + c_p = bar; + /* Ok, safe. */ + c_p (); + + /* Assign an at-calls function to pointer-to-callable. + Flaggged as incompatible. */ + c_p = bal; + /* The call through an interface-incompatible type will not use the + modified interface expected by the at-calls function, so it is + likely to misbehave at runtime. */ + c_p (); +@} +@end example + +@code{Strub} contexts are never inlined into non-@code{strub} contexts. +When an @code{internal}-strub function is split up, the wrapper can +often be inlined, but the wrapped body @emph{never} is. A function +marked as @code{always_inline}, even if explicitly assigned +@code{internal} strub mode, will not undergo wrapping, so its body gets +inlined as required. + +@example +inline int __attribute__ ((strub ("at-calls"))) +inl_atc (void) +@{ + /* This body may get inlined into strub contexts. */ +@} + +inline int __attribute__ ((strub ("internal"))) +inl_int (void) +@{ + /* This body NEVER gets inlined, though its wrapper may. */ +@} + +inline int __attribute__ ((strub ("internal"), always_inline)) +inl_int_ali (void) +@{ + /* No internal wrapper, so this body ALWAYS gets inlined, + but it cannot be called from non-strub contexts. */ +@} + +void __attribute__ ((strub ("disabled"))) +bat (void) +@{ + /* Not allowed, cannot inline into a non-strub context. */ + inl_int_ali (); +@} +@end example + +@cindex strub eligibility and viability +Some @option{-fstrub=*} command line options enable @code{strub} modes +implicitly where viable. A @code{strub} mode is only viable for a +function if the function is eligible for that mode, and if other +conditions, detailed below, are satisfied. If it's not eligible for a +mode, attempts to explicitly associate it with that mode are rejected +with an error message. If it is eligible, that mode may be assigned +explicitly through this attribute, but implicit assignment through +command-line options may involve additional viability requirements. + +A function is ineligible for @code{at-calls} @code{strub} mode if a +different @code{strub} mode is explicitly requested, if attribute +@code{noipa} is present, or if it calls @code{__builtin_apply_args}. +@code{At-calls} @code{strub} mode, if not requested through the function +type, is only viable for an eligible function if the function is not +visible to other translation units, if it doesn't have its address +taken, and if it is never called with a function type overrider. + +@smallexample +/* bar is eligible for at-calls strub mode, + but not viable for that mode because it is visible to other units. + It is eligible and viable for internal strub mode. */ +void bav () @{@} + +/* setp is eligible for at-calls strub mode, + but not viable for that mode because its address is taken. + It is eligible and viable for internal strub mode. */ +void setp (void) @{ static void (*p)(void); = setp; @} +@end smallexample + +A function is ineligible for @code{internal} @code{strub} mode if a +different @code{strub} mode is explicitly requested, or if attribute +@code{noipa} is present. For an @code{always_inline} function, meeting +these requirements is enough to make it eligible. Any function that has +attribute @code{noclone}, that uses such extensions as non-local labels, +computed gotos, alternate variable argument passing interfaces, +@code{__builtin_next_arg}, or @code{__builtin_return_address}, or that +takes too many (about 64Ki) arguments is ineligible, unless it is +@code{always_inline}. For @code{internal} @code{strub} mode, all +eligible functions are viable. + +@smallexample +/* flop is not eligible, thus not viable, for at-calls strub mode. + Likewise for internal strub mode. */ +__attribute__ ((noipa)) void flop (void) @{@} + +/* flip is eligible and viable for at-calls strub mode. + It would be ineligible for internal strub mode, because of noclone, + if it weren't for always_inline. With always_inline, noclone is not + an obstacle, so it is also eligible and viable for internal strub mode. */ +inline __attribute__ ((noclone, always_inline)) void flip (void) @{@} +@end smallexample + @item unused @cindex @code{unused} type attribute When attached to a type (including a @code{union} or a @code{struct}), @@ -11927,6 +12185,55 @@ option is in effect. Such calls should only be made in debugging situations. @end deftypefn +@deftypefn {Built-in Function} {void *} __builtin_stack_address () +This function returns the value of the stack pointer register. +@end deftypefn + +@node Stack Scrubbing +@section Stack scrubbing internal interfaces + +Stack scrubbing involves cooperation between a @code{strub} context, +i.e., a function whose stack frame is to be zeroed-out, and its callers. +The caller initializes a stack watermark, the @code{strub} context +updates the watermark according to its stack use, and the caller zeroes +it out once it regains control, whether by the callee's returning or by +an exception. + +Each of these steps is performed by a different builtin function call. +Calls to these builtins are introduced automatically, in response to +@code{strub} attributes and command-line options; they are not expected +to be explicitly called by source code. + +The functions that implement the builtins are available in libgcc but, +depending on optimization levels, they are expanded internally, adjusted +to account for inlining, and sometimes combined/deferred (e.g. passing +the caller-supplied watermark on to callees, refraining from erasing +stack areas that the caller will) to enable tail calls and to optimize +for code size. + +@deftypefn {Built-in Function} {void} __builtin___strub_enter (void **@var{wmptr}) +This function initializes a stack @var{watermark} variable with the +current top of the stack. A call to this builtin function is introduced +before entering a @code{strub} context. It remains as a function call +if optimization is not enabled. +@end deftypefn + +@deftypefn {Built-in Function} {void} __builtin___strub_update (void **@var{wmptr}) +This function updates a stack @var{watermark} variable with the current +top of the stack, if it tops the previous watermark. A call to this +builtin function is inserted within @code{strub} contexts, whenever +additional stack space may have been used. It remains as a function +call at optimization levels lower than 2. +@end deftypefn + +@deftypefn {Built-in Function} {void} __builtin___strub_leave (void **@var{wmptr}) +This function overwrites the memory area between the current top of the +stack, and the @var{watermark}ed address. A call to this builtin +function is inserted after leaving a @code{strub} context. It remains +as a function call at optimization levels lower than 3, and it is guarded by +a condition at level 2. +@end deftypefn + @node Vector Extensions @section Using Vector Instructions through Built-in Functions diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index fa23fbeaaaa22..1226efb5e7e3a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -624,6 +624,8 @@ Objective-C and Objective-C++ Dialects}. -fstack-protector-explicit -fstack-check @gol -fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym} @gol -fno-stack-limit -fsplit-stack @gol +-fstrub=disable -fstrub=strict -fstrub=relaxed @gol +-fstrub=all -fstrub=at-calls -fstrub=internal @gol -fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]} @gol -fvtv-counts -fvtv-debug @gol -finstrument-functions -finstrument-functions-once @gol @@ -16482,6 +16484,56 @@ without @option{-fsplit-stack} always has a large stack. Support for this is implemented in the gold linker in GNU binutils release 2.21 and later. +@item -fstrub=disable +@opindex -fstrub=disable +Disable stack scrubbing entirely, ignoring any @code{strub} attributes. +See @xref{Common Type Attributes}. + +@item -fstrub=strict +@opindex fstrub=strict +Functions default to @code{strub} mode @code{disabled}, and apply +@option{strict}ly the restriction that only functions associated with +@code{strub}-@code{callable} modes (@code{at-calls}, @code{callable} and +@code{always_inline} @code{internal}) are @code{callable} by functions +with @code{strub}-enabled modes (@code{at-calls} and @code{internal}). + +@item -fstrub=relaxed +@opindex fstrub=relaxed +Restore the default stack scrub (@code{strub}) setting, namely, +@code{strub} is only enabled as required by @code{strub} attributes +associated with function and data types. @code{Relaxed} means that +strub contexts are only prevented from calling functions explicitly +associated with @code{strub} mode @code{disabled}. This option is only +useful to override other @option{-fstrub=*} options that precede it in +the command line. + +@item -fstrub=at-calls +@opindex fstrub=at-calls +Enable @code{at-calls} @code{strub} mode where viable. The primary use +of this option is for testing. It exercises the @code{strub} machinery +in scenarios strictly local to a translation unit. This @code{strub} +mode modifies function interfaces, so any function that is visible to +other translation units, or that has its address taken, will @emph{not} +be affected by this option. Optimization options may also affect +viability. See the @code{strub} attribute documentation for details on +viability and eligibility requirements. + +@item -fstrub=internal +@opindex fstrub=internal +Enable @code{internal} @code{strub} mode where viable. The primary use +of this option is for testing. This option is intended to exercise +thoroughly parts of the @code{strub} machinery that implement the less +efficient, but interface-preserving @code{strub} mode. Functions that +would not be affected by this option are quite uncommon. + +@item -fstrub=all +@opindex fstrub=all +Enable some @code{strub} mode where viable. When both strub modes are +viable, @code{at-calls} is preferred. @option{-fdump-ipa-strubm} adds +function attributes that tell which mode was selected for each function. +The primary use of this option is for testing, to exercise thoroughly +the @code{strub} machinery. + @item -fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]} @opindex fvtable-verify This option is only available when compiling C++ code. @@ -18379,6 +18431,14 @@ and inlining decisions. @item inline Dump after function inlining. +@item strubm +Dump after selecting @code{strub} modes, and recording the selections as +function attributes. + +@item strub +Dump @code{strub} transformations: interface changes, function wrapping, +and insertion of builtin calls for stack scrubbing and watermarking. + @end table Additionally, the options @option{-optimized}, @option{-missed}, -- Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/ Free Software Activist GNU Toolchain Engineer Disinformation flourishes because many people care deeply about injustice but very few check the facts. Ask me about