From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-pl1-x62a.google.com (mail-pl1-x62a.google.com [IPv6:2607:f8b0:4864:20::62a]) by sourceware.org (Postfix) with ESMTPS id 0D9273858D35 for ; Wed, 29 Nov 2023 08:53:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0D9273858D35 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=adacore.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 0D9273858D35 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::62a ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701248007; cv=none; b=bbeK4ym3DSeeqp/LvESWP/jlsA37Z7N7RBsmT2jwOebGKdlRBrrJ2P1fCnxyQ/AS+GmB7WPWTFQzHR0gg5NkIOGCPn67L0Fl91DpptQBi4s+WEc5tXoZGC+CaxS3YAWxv9IVruLtsb1YJhadV27KDPHlhCaJE2l2L4E0cH0V3zQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701248007; c=relaxed/simple; bh=AYpDGJRDzWGtZfLrel21Gvf0NMeeUvA52l+5cQWnG/4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=COhoaWgbMuuaRllchnufJLxGmN8xL1dGmYZzGuWnsF7/iMJ3P961obVejNxj5C28Ux216OSqj/q+nckERVYKDJLKGeL9CZ08NxNslWl7Znz3tZZiXBPC8+pK1OhFeaFmI6wgOQTCMhVAJUheYgJnEBkxQ06O6AHm2hAtZhcnyw4= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pl1-x62a.google.com with SMTP id d9443c01a7336-1cfb4d28c43so34073515ad.1 for ; Wed, 29 Nov 2023 00:53:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1701248003; x=1701852803; darn=gcc.gnu.org; h=mime-version:user-agent:message-id:in-reply-to:date:references :organization:subject:cc:to:from:from:to:cc:subject:date:message-id :reply-to; bh=CXna2T6SDu8Z8Y/VeTkRU+kDJlT0a26afBRoCVlwHB8=; b=Xyh4CslbcrtyskEO0OUn8tkJQX/ZMqOq99h+KUdxuvedHjhisXq9CBm1EUxD9dWTtb 1kH+seFyZoUcz8EVeCx6xP2sRdqN2WLZAdGjOePSZaZ/UPmfzs1crwhhkfvsRtSQM7wP Ny22cT6+t92GnCRQ/oCL/VfqA90iLfXZ2G+/GWA8+DVGs/1STybUr2vIatWyATe+dgo9 TqaxRP8iaNvIXGDj6KF/bUqXuavcNfa6MI+lvSUEmQ+/GPuobiWqTGrMcGqn4sSG7+1r WXVhMuUEfSBktS5xgV+Cteototyr6wYq5RNttXJLyayiunbetCvUs95ginY8U2Xar/c/ 6Tkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701248003; x=1701852803; h=mime-version:user-agent:message-id:in-reply-to:date:references :organization:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CXna2T6SDu8Z8Y/VeTkRU+kDJlT0a26afBRoCVlwHB8=; b=CHEMLXoA2qaHktwRTudI2zCjJAwAijXnJYxebm7Mh8/fTLHI9pOtGsJasCJ37ZITzz HNzfHEF64HS0wmKvuTjXWYoW4Qh7ShRK3E0936TVqXnSd1w4o/T1UwXOHVwjVzsuBCoP EQqIsMXDbmWjPstiJcpuVzOKEAu/vDyqfqOdSouUutmQ7qqQV+MBsIxaz3ORTIMOqG7F gCdxl9mbZIQK7mS68QRVm0CmuX+ub9avA29l7z4ZKlVZwvWFEpy83IvYsV1QgRKp2ooy 54JWQKFPItZLHJ0fNs1ob3UyPWJfdJYK0Z44CrKSea4qp2bycFi91W6atzur7Y3qIWAW KHqQ== X-Gm-Message-State: AOJu0YyzfUIvcvAmvRH6BsGZqxCU9yaBIVe51hM/OmyEMhb4ik+bJx8R ueXfeqwZzKBww1dyNR34xVYMqA== X-Google-Smtp-Source: AGHT+IFrMGrZENRy3xLYR7HMMKLweT/4NqE3SXFjPaGCD8Wf2HClY+yvF5knTP7k9xX4EXNyHp6vMw== X-Received: by 2002:a17:902:ecc5:b0:1cf:c2c8:7f96 with SMTP id a5-20020a170902ecc500b001cfc2c87f96mr13013374plh.48.1701248002515; Wed, 29 Nov 2023 00:53:22 -0800 (PST) Received: from free.home ([2804:7f1:2080:8316:5de:a3fa:396c:13d9]) by smtp.gmail.com with ESMTPSA id h1-20020a170902f7c100b001cfad601a4bsm8819488plw.10.2023.11.29.00.53.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Nov 2023 00:53:22 -0800 (PST) Received: from livre (livre.home [172.31.160.2]) by free.home (8.15.2/8.15.2) with ESMTPS id 3AT8r7mr023570 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 29 Nov 2023 05:53:07 -0300 From: Alexandre Oliva To: Richard Biener Cc: gcc-patches@gcc.gnu.org, Jeremy Bennett , Craig Blackmore , Graham Markall , Martin Jambor , Jan Hubicka , Jim Wilson , Jeff Law , Jakub Jelinek Subject: Re: [PATCH v4] Introduce strub: machine-independent stack scrubbing Organization: Free thinker, does not speak for AdaCore References: Date: Wed, 29 Nov 2023 05:53:07 -0300 In-Reply-To: (Richard Biener's message of "Thu, 23 Nov 2023 13:05:27 +0100") Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (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,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE,WEIRD_QUOTING autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Nov 23, 2023, Richard Biener wrote: > Conceptually it shouldn't be much different from what IPA-SRA does > which is cloning a function but with different arguments, the function > signature transform described in terms of ipa-param-manipulation bits. > I've talked with Martin and at least there's currently no > by-value-to-by-reference > "transform", but IPA-SRA can pass two registers instead of one aggregate > for example. There's IPA_PARAM_OP_NEW already to add a new param. > In principle the whole function rewriting (apart of recovering > from inlining) should be doable within this framework. I agree, but my attempts to do so have been unfruitful, and hit various very obscure issues that made it unworkable. Maybe someone smarter than I am, or with more time than I had, can make the conversion. The uses of IPA_PARAM_OP_NEW for the cloning are there, and the more conservative choices I made got it to work reliably, unlike the more adventurous alternatives I tried. One of the obscure issues I recall hitting was this one. I can probably still locate the early strub patch that hit the described issue back then, if there's interest. https://gcc.gnu.org/pipermail/gcc-patches/2021-July/575044.html >> The >> wrapper already needs a custom ABI, because of the added watermark >> pointer, and va_list and whatnot when needed, so a little further >> customization to avoid a quite significant overhead seemed desirable. > I understood the purpose of this, but I also saw it's only ever needed for > non-strict operation Erhm... I suppose you're not talking about -fstrub=strict, because I can't see how this relates with the by-reference argument passing from wrapper to wrapped in internal strubbing. > and I think that if you care about security you'd never > want to operate in a way that you don't absolutely know the function > you call isn't going to scrub your secrets ... The ABI between wrapper and wrapped function splitting in internal strub doesn't change this. > But yes, I also wondered why you even run into re-gimplification issues. Because &arg_#(D)[n_#] is good gimple, but &(*byref_arg_#(D))[n_#] isn't. Maybe instead of going through regimplify, we could explicitly create an SSA name for the indirection load, so that the purpose is made more explicit. > replacing the PARM_DECL there with a MEM_REF (new-PARM_DECL) should > work without re-gimplification. FWIW, I thought so as well ;-) > I didn't remember seeing that you do sth like wrapping > each "strubbed call" inside a try { call(); } finally { do-strub } to > ensure this. > Guess it was well hidden in the large patch ;) Indeed, gsi_insert_finally_seq_after_call is where this is taken care of. >> > As it's only for optimization, how much of the code would go away when >> > you avoid changing the parameters of the wrapped function? >> >> We can't avoid changing them entirely, and IIRC some of the >> infrastructure for regimplification was also used for va_list and >> apply_args handling, so it wouldn't save all that much. > Ah, var-args ... indeed for simple forwarding it shouldn't be too bad. > I wonder if this were a way to remove the restriction on function > splitting of var-args functions - there's a recent bugreport about that > (before any va_arg () has been called, of course). If running va_start unconditionally in varargs functions is generally acceptable, then the method I've used for wrapping varargs functions should work generally, yeah. The trick was to turn: foo (...) { va_list ap; ... va_start (&ap, ); ... } into wrapped_foo (va_list &wrap) { va_list ap; ... va_copy (ap, wrap); ... } foo (...) { va_list wrap; va_start (wrap, ); wrapped_foo (wrap); va_end (wrap); } Here's the opening comment I added to ipa-strub.cc: /* This file introduces two passes that, together, implement machine-independent stack scrubbing, strub for short. It arranges for stack frames that have strub enabled to be zeroed-out after relinquishing control to a caller, whether by returning or by propagating an exception. This admittedly unusual design decision was driven by exception support (one needs a stack frame to be active to propagate exceptions out of it), and it enabled an implementation that is entirely machine-independent (no custom epilogue code is required). Strub modes can be selected for stack frames by attaching attribute strub to functions or to variables (to their types, actually). Different strub modes, with different implementation details, are available, and they can be selected by an argument to the strub attribute. When enabled by strub-enabled variables, whether by accessing (as in reading from) statically-allocated ones, or by introducing (as in declaring) automatically-allocated ones, a suitable mode is selected automatically. At-calls mode modifies the interface of a function, adding a stack watermark argument, that callers use to clean up the stack frame of the called function. Because of the interface change, it can only be used when explicitly selected, or when a function is internal to a translation unit. Strub-at-calls function types are distinct from their original types (they're not modified in-place), and they are not interchangeable with other function types. Internal mode, in turn, does not modify the type or the interface of a function. It is currently implemented by turning the function into a wrapper, moving the function body to a separate wrapped function, and scrubbing the wrapped body's stack in the wrapper. Internal-strub function types are mostly interface-compatible with other strub modes, namely callable (from strub functions, though not strub-enabled) and disabled (not callable from strub functions). Always_inline functions can be strub functions, but they can only be called from other strub functions, because strub functions must never be inlined into non-strub functions. Internal and at-calls modes are indistinguishable when it comes to always_inline functions: they will necessarily be inlined into another strub function, and will thus be integrated into the caller's stack frame, whatever the mode. (Contrast with non-always_inline strub functions: an at-calls function can be called from other strub functions, ensuring no discontinuity in stack erasing, whereas an internal-strub function can only be called from other strub functions if it happens to be inlined, or if -fstrub=relaxed mode is in effect (that's the default). In -fstrub=strict mode, internal-strub functions are not callable from strub functions, because the wrapper itself is not strubbed. The implementation involves two simple-IPA passes. The earliest one, strub-mode, assigns strub modes to functions. It needs to run before any inlining, so that we can prevent inlining of strub functions into non-strub functions. It notes explicit strub mode requests, enables strub in response to strub variables and testing options, and flags unsatisfiable requests. Three possibilities of unsatisfiable requests come to mind: (a) when a strub mode is explicitly selected, but the function uses features that make it ineligible for that mode (e.g. at-calls rules out calling __builtin_apply_args, because of the interface changes, and internal mode rules out noclone or otherwise non-versionable functions, non-default varargs, non-local or forced labels, and functions with far too many arguments); (b) when some strub mode must be enabled because of a strub variable, but the function is not eligible or not viable for any mode; and (c) when -fstrub=strict is enabled, and calls are found in strub functions to functions that are not callable from strub contexts. compute_strub_mode implements (a) and (b), and verify_strub implements (c). The second IPA pass modifies interfaces of at-calls-strub functions and types, introduces strub calls in and around them. and splits internal-strub functions. It is placed after early inlining, so that even internal-strub functions get a chance of being inlined into other strub functions, but before non-early inlining, so that internal-strub wrapper functions still get a chance of inlining after splitting. Wrappers avoid duplicating the copying of large arguments again by passing them by reference to the wrapped bodies. This involves occasional SSA rewriting of address computations, because of the additional indirection. Besides these changes, and the introduction of the stack watermark parameter, wrappers and wrapped functions cooperate to handle variable argument lists (performing va_start in the wrapper, passing the list as an argument, and replacing va_start calls in the wrapped body with va_copy), and __builtin_apply_args (also called in the wrapper and passed to the wrapped body as an argument). Strub bodies (both internal-mode wrapped bodies, and at-calls functions) always start by adjusting the watermark parameter, by calling __builtin___strub_update. The compiler inserts them in the main strub pass. Allocations of additional stack space for the frame (__builtin_alloca) are also followed by watermark updates. Stack space temporarily allocated to pass arguments to other functions, released right after the call, is not regarded as part of the frame. Around calls to them, i.e., in internal-mode wrappers and at-calls callers (even calls through pointers), calls to __builtin___strub_enter and __builtin___strub_leave are inserted, the latter as a __finally block, so that it runs at regular and exceptional exit paths. strub_enter only initializes the stack watermark, and strub_leave is where the scrubbing takes place, overwriting with zeros the stack space from the top of the stack to the watermark. These calls can be optimized in various cases. In pass_ipa_strub::adjust_at_calls_call, for example, we enable tail-calling and other optimized calls from one strub body to another by passing on the watermark parameter. The builtins themselves may undergo inline substitution during expansion, dependign on optimization levels. This involves dealing with stack red zones (when the builtins are called out-of-line, the red zone cannot be used) and other ugly details related with inlining strub bodies into other strub bodies (see expand_builtin_strub_update). expand_builtin_strub_leave may even perform partial inline substitution. */ The type attribute description now starts like this: @cindex @code{strub} type attribute @item strub This attribute defines stack-scrubbing properties of functions and variables, so that functions that access sensitive data can have their stack frames zeroed-out upon returning or propagating exceptions. This may be enabled explicitly, by selecting certain @code{strub} modes for specific functions, or implicitly, by means of @code{strub} variables. And I've fixed the symbol versioning for strub and hardcfr functions. I've just pushed the base strub patch and the recent incremental changes (and some commits used for testing) to refs/users/aoliva/heads/strub. Here are changes.html entries for this and for the other newly-added features: new AdaCore-contributed hardening features in gcc 13 and 14 Mention hardening of conditionals (added in gcc 13), control flow redundancy, hardened booleans, and stack scrubbing. Also cover forced inlining of string operations while at that. --- htdocs/gcc-13/changes.html | 6 ++++++ htdocs/gcc-14/changes.html | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/htdocs/gcc-13/changes.html b/htdocs/gcc-13/changes.html index 8ef3d63952daf..c1dea18caf59b 100644 --- a/htdocs/gcc-13/changes.html +++ b/htdocs/gcc-13/changes.html @@ -168,6 +168,12 @@ You may also want to check out our been added, see also Profiling and Test Coverage in Freestanding Environments. +
  • + New options -fharden-compares + and -fharden-conditional-branches to verify compares + and conditional branches, to detect some power-deprivation + hardware attacks, using reversed conditions. +
  • diff --git a/htdocs/gcc-14/changes.html b/htdocs/gcc-14/changes.html index 2088ee91a34e1..cb92f8d8095c3 100644 --- a/htdocs/gcc-14/changes.html +++ b/htdocs/gcc-14/changes.html @@ -109,6 +109,35 @@ a work-in-progress.

    of hardening flags. The options it enables can be displayed using the --help=hardened option. +
  • + New option -fharden-control-flow-redundancy, to + verify, at the end of functions, that the visited basic blocks + correspond to a legitimate execution path, so as to detect and + prevent attacks that transfer control into the middle of + functions. +
  • +
  • + New type attribute hardbool, for C and Ada. Hardened + booleans take user-specified representations for true + and false, presumably with higher hamming distance + than standard booleans, and get verified at every use, detecting + memory corruption and some malicious attacks. +
  • +
  • + New type attribute strub to control stack scrubbing + properties of functions and variables. The stack frame used by + functions marked with the attribute gets zeroed-out upon returning + or exception escaping. Scalar variables marked with the attribute + cause functions contaning or accessing them to get stack scrubbing + enabled implicitly. +
  • +
  • + New option -finline-stringops, to force inline + expansion of memcmp, memcpy, + memmove and memset, even when that is + not an optimization, to avoid relying on library + implementations. +
  • New Languages and Language specific improvements

    -- Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/ Free Software Activist GNU Toolchain Engineer More tolerance and less prejudice are key for inclusion and diversity Excluding neuro-others for not behaving ""normal"" is *not* inclusive