From patchwork Mon Nov 14 13:52:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marc_Poulhi=C3=A8s?= X-Patchwork-Id: 19820 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp2156708wru; Mon, 14 Nov 2022 05:56:58 -0800 (PST) X-Google-Smtp-Source: AA0mqf6kzewBCwHDQsto07VBoqhATODnpm+9VUti1WXX42VHUr76m/kqtIqrcXYF/OieFYHB+wYI X-Received: by 2002:a17:906:170c:b0:78d:3e56:52c with SMTP id c12-20020a170906170c00b0078d3e56052cmr9827961eje.732.1668434218831; Mon, 14 Nov 2022 05:56:58 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668434218; cv=none; d=google.com; s=arc-20160816; b=l9ofGAg/MbVWSjoI/CKbruR1SYgUKCCqiC6tEGNqqUDtUOK6FN4jG0YSI245AnyKlX ohF+W0bYEl4nhtDbbRTabG5nsB5//NyW2Aj75qvmi+tQ+lW9lgS25h32qYNOYDwa3u4R u5PpSglUPDGDqh2GWk8cwao7rJ7i6ScmT1KfmGOUaw+j6oRjMBGV3NhR/ioyKhe0FLfp rNACrb806oJSUurHKs6p6k68+4U52/E8iV+oPwqSfgS6q7baUousxFWhkpL8JusQHUDL w+GgLTPkPJl+kvXUl7EwJ17ZSOZ1m/W6m05EKiXomcJ9UTN4pMDzO0m4An/QJ5fAz89a fgxw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:message-id:date:subject:cc :to:dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=sD2ykyWN4hOlgqFLS9dFy4DrJbV8QCRgFGf+vA0XT4o=; b=uyXMvvhAc1FUvClEUzcpXzzyQFGgLaZstKEswTeIEL5GaGAZQ57nFrbblI8vvb4Ym1 88USZOTT1yBsdoZzxctokDUdhOUN4M25zjomTorOpkx4ApQZlhzyfWSiZypjaMHgpvJI /QDyD9jC6Bf4S+Csq/ejTBOo9pmvM7ABtR1IR7mXytgSors6cDg3IxIXY6Dr12bPJD+K rgZTvI3pFg+XPrYnY91wUOYTzxDd3Mxecq2BFO8JislyA3CB6c9iFSiOrqfhwlKX9u1S 1ibdWmIqRh/Bx0rcJYf/ACEW4zYKbxujkQ/bCTZ75SBFxTSDy6CC7LDSxhg9ZduyD91D hxLA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=gkNbE1QS; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id b14-20020a056402278e00b00458ac23f0b8si9136999ede.399.2022.11.14.05.56.58 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Nov 2022 05:56:58 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=gkNbE1QS; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5933938A9094 for ; Mon, 14 Nov 2022 13:54:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5933938A9094 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1668434068; bh=sD2ykyWN4hOlgqFLS9dFy4DrJbV8QCRgFGf+vA0XT4o=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=gkNbE1QSfIKzPJFwSmh/oxvQh0Do/9odImCVMzGS6Qr9vmVvsmqDwWS3Hmn0WoL2i i36PeiGDyp/EfLMoPzvD6FVFA0XY+tzH8GxD0r5Is+I98PcsSb66M0djXdba/qE9lY goUBQnRRCeaUNusD+E9yhiaKSZ2h9izrBuoxcvjQ= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by sourceware.org (Postfix) with ESMTPS id CDB38382EF1F for ; Mon, 14 Nov 2022 13:52:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org CDB38382EF1F Received: by mail-wm1-x333.google.com with SMTP id t1so7531038wmi.4 for ; Mon, 14 Nov 2022 05:52:44 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=sD2ykyWN4hOlgqFLS9dFy4DrJbV8QCRgFGf+vA0XT4o=; b=Jsmh3VWPLgX5iogxyK7iYHlY36MDr+PmlhkxW7umM8lKxLkbMgstKnuGtOTsZuLEaG fMieUvxqQP/6FUr29AEB84DTMO26VCQ2kiz+b/Nsga54KRovcVFkkwOIvaINMkwQJ9aD jQjYcMuuX1V7XF5YT6j+PFMYgcXdobsYeRSBWvvDjVjsO4GhwZIjGtZX7jC3e7bPgSBq rSvcEiPuySTDELDONr+wHRq6K6zrXVn35dU0bG2u+Fnwxu7DqIhyLwsL5FUuMa3G4SVa S1bLLo/16YXOexlah/Cfenq33c+kH4KgThxN1POz+lrGAtawLyuZIjosCtOq9Eyo5eVD BVtA== X-Gm-Message-State: ANoB5pnZR9of+9TZFirB7+QIE9G76sYNw1zWLwr25NndcyYaohpvLq61 vPfqtPafIsTziDaYm/6TrMMP41Za6vOOMQ== X-Received: by 2002:a7b:c00c:0:b0:3cf:6fd8:95a4 with SMTP id c12-20020a7bc00c000000b003cf6fd895a4mr7926432wmb.73.1668433963473; Mon, 14 Nov 2022 05:52:43 -0800 (PST) Received: from localhost.localdomain (static-176-191-105-132.ftth.abo.bbox.fr. [176.191.105.132]) by smtp.gmail.com with ESMTPSA id b11-20020a5d550b000000b0023659925b2asm9514160wrv.51.2022.11.14.05.52.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Nov 2022 05:52:42 -0800 (PST) To: gcc-patches@gcc.gnu.org Cc: Alexandre Oliva Subject: [COMMITTED] ada: hardcfr docs: add optional checkpoints Date: Mon, 14 Nov 2022 14:52:40 +0100 Message-Id: <20221114135240.53093-1-poulhies@adacore.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, 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-Patchwork-Original-From: =?utf-8?q?Marc_Poulhi=C3=A8s_via_Gcc-patches?= From: =?utf-8?q?Marc_Poulhi=C3=A8s?= Reply-To: =?utf-8?q?Marc_Poulhi=C3=A8s?= Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1749480079118464892?= X-GMAIL-MSGID: =?utf-8?q?1749480079118464892?= From: Alexandre Oliva Previously, control flow redundancy only checked the visited bitmap against the control flow graph at return points and before mandatory tail calls, missing various other possibilities of exiting a subprogram, such as by raising or propagating exceptions, and calling noreturn functions. The checks inserted before returns also prevented potential tail-call optimizations. This incremental change introduces options to control checking at each of these previously-missed checkpoints. Unless disabled, a cleanup is introduced to check when an exceptions escapes a subprogram. To avoid disrupting sibcall optimizations, when they are enabled, checks are introduced before calls whose results are immediately returned, whether or not they are ultimately optimized. If enabled, checks are introduced before noreturn calls and exception raises, or only before nothrow noreturn calls. Add examples of code transformations to the GNAT RM. gcc/ada/ * doc/gnat_rm/security_hardening_features.rst: Document optional hardcfr checkpoints. * gnat_rm.texi: Regenerate. * gnat_ugn.texi: Regenerate. Tested on x86_64-pc-linux-gnu, committed on master. --- .../gnat_rm/security_hardening_features.rst | 126 +++++++++++++++++- gcc/ada/gnat_rm.texi | 123 ++++++++++++++++- gcc/ada/gnat_ugn.texi | 5 +- 3 files changed, 240 insertions(+), 14 deletions(-) diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features.rst b/gcc/ada/doc/gnat_rm/security_hardening_features.rst index d7c02b94f36..ad165cd6849 100644 --- a/gcc/ada/doc/gnat_rm/security_hardening_features.rst +++ b/gcc/ada/doc/gnat_rm/security_hardening_features.rst @@ -383,11 +383,127 @@ For each block that is marked as visited, the mechanism checks that at least one of its predecessors, and at least one of its successors, are also marked as visited. -Verification is performed just before returning. Subprogram -executions that complete by raising or propagating an exception bypass -verification-and-return points. A subprogram that can only complete -by raising or propagating an exception may have instrumentation -disabled altogether. +Verification is performed just before a subprogram returns. The +following fragment: + +.. code-block:: ada + + if X then + Y := F (Z); + return; + end if; + + +gets turned into: + +.. code-block:: ada + + type Visited_Bitmap is array (1..N) of Boolean with Pack; + Visited : aliased Visited_Bitmap := (others => False); + -- Bitmap of visited blocks. N is the basic block count. + [...] + -- Basic block #I + Visited(I) := True; + if X then + -- Basic block #J + Visited(J) := True; + Y := F (Z); + CFR.Check (N, Visited'Access, CFG'Access); + -- CFR is a hypothetical package whose Check procedure calls + -- libgcc's __hardcfr_check, that traps if the Visited bitmap + -- does not hold a valid path in CFG, the run-time + -- representation of the control flow graph in the enclosing + -- subprogram. + return; + end if; + -- Basic block #K + Visited(K) := True; + + +Verification would also be performed before tail calls, if any +front-ends marked them as mandatory or desirable, but none do. +Regular calls are optimized into tail calls too late for this +transformation to act on it. + +In order to avoid adding verification after potential tail calls, +which would prevent tail-call optimization, we recognize returning +calls, i.e., calls whose result, if any, is returned by the calling +subprogram to its caller immediately after the call returns. +Verification is performed before such calls, whether or not they are +ultimately optimized to tail calls. This behavior is enabled by +default whenever sibcall optimization is enabled (see +:switch:`-foptimize-sibling-calls`); it may be disabled with +:switch:`-fno-hardcfr-check-returning-calls`, or enabled with +:switch:`-fhardcfr-check-returning-calls`, regardless of the +optimization, but the lack of other optimizations may prevent calls +from being recognized as returning calls: + +.. code-block:: ada + + -- CFR.Check here, with -fhardcfr-check-returning-calls. + P (X); + -- CFR.Check here, with -fno-hardcfr-check-returning-calls. + return; + +or: + +.. code-block:: ada + + -- CFR.Check here, with -fhardcfr-check-returning-calls. + R := F (X); + -- CFR.Check here, with -fno-hardcfr-check-returning-calls. + return R; + + +Any subprogram from which an exception may escape, i.e., that may +raise or propagate an exception that isn't handled internally, is +conceptually enclosed by a cleanup handler that performs verification, +unless this is disabled with :switch:`-fno-hardcfr-check-exceptions`. +With this feature enabled, a subprogram body containing: + +.. code-block:: ada + + -- ... + Y := F (X); -- May raise exceptions. + -- ... + raise E; -- Not handled internally. + -- ... + + +gets modified as follows: + +.. code-block:: ada + + begin + -- ... + Y := F (X); -- May raise exceptions. + -- ... + raise E; -- Not handled internally. + -- ... + exception + when others => + CFR.Check (N, Visited'Access, CFG'Access); + raise; + end; + + +Verification may also be performed before No_Return calls, whether +only nothrow ones, with +:switch:`-fhardcfr-check-noreturn-calls=nothrow`, or all of them, with +:switch:`-fhardcfr-check-noreturn-calls=always`. The default is +:switch:`-fhardcfr-check-noreturn-calls=never` for this feature, that +disables checking before No_Return calls. + +When a No_Return call returns control to its caller through an +exception, verification may have already been performed before the +call, if :switch:`-fhardcfr-check-noreturn-calls=always` is in effect. +The compiler arranges for already-checked No_Return calls without a +preexisting handler to bypass the implicitly-added cleanup handler and +thus the redundant check, but a local exception or cleanup handler, if +present, will modify the set of visited blocks, and checking will take +place again when the caller reaches the next verification point, +whether it is a return or reraise statement after the exception is +otherwise handled, or even another No_Return call. The instrumentation for hardening with control flow redundancy can be observed in dump files generated by the command-line option diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index fbd8bb8d6b2..83458cb60a6 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -19,7 +19,7 @@ @copying @quotation -GNAT Reference Manual , Oct 27, 2022 +GNAT Reference Manual , Nov 14, 2022 AdaCore @@ -29037,11 +29037,122 @@ For each block that is marked as visited, the mechanism checks that at least one of its predecessors, and at least one of its successors, are also marked as visited. -Verification is performed just before returning. Subprogram -executions that complete by raising or propagating an exception bypass -verification-and-return points. A subprogram that can only complete -by raising or propagating an exception may have instrumentation -disabled altogether. +Verification is performed just before a subprogram returns. The +following fragment: + +@example +if X then + Y := F (Z); + return; +end if; +@end example + +gets turned into: + +@example +type Visited_Bitmap is array (1..N) of Boolean with Pack; +Visited : aliased Visited_Bitmap := (others => False); +-- Bitmap of visited blocks. N is the basic block count. +[...] +-- Basic block #I +Visited(I) := True; +if X then + -- Basic block #J + Visited(J) := True; + Y := F (Z); + CFR.Check (N, Visited'Access, CFG'Access); + -- CFR is a hypothetical package whose Check procedure calls + -- libgcc's __hardcfr_check, that traps if the Visited bitmap + -- does not hold a valid path in CFG, the run-time + -- representation of the control flow graph in the enclosing + -- subprogram. + return; +end if; +-- Basic block #K +Visited(K) := True; +@end example + +Verification would also be performed before tail calls, if any +front-ends marked them as mandatory or desirable, but none do. +Regular calls are optimized into tail calls too late for this +transformation to act on it. + +In order to avoid adding verification after potential tail calls, +which would prevent tail-call optimization, we recognize returning +calls, i.e., calls whose result, if any, is returned by the calling +subprogram to its caller immediately after the call returns. +Verification is performed before such calls, whether or not they are +ultimately optimized to tail calls. This behavior is enabled by +default whenever sibcall optimization is enabled (see +@code{-foptimize-sibling-calls}); it may be disabled with +@code{-fno-hardcfr-check-returning-calls}, or enabled with +@code{-fhardcfr-check-returning-calls}, regardless of the +optimization, but the lack of other optimizations may prevent calls +from being recognized as returning calls: + +@example +-- CFR.Check here, with -fhardcfr-check-returning-calls. +P (X); +-- CFR.Check here, with -fno-hardcfr-check-returning-calls. +return; +@end example + +or: + +@example +-- CFR.Check here, with -fhardcfr-check-returning-calls. +R := F (X); +-- CFR.Check here, with -fno-hardcfr-check-returning-calls. +return R; +@end example + +Any subprogram from which an exception may escape, i.e., that may +raise or propagate an exception that isn’t handled internally, is +conceptually enclosed by a cleanup handler that performs verification, +unless this is disabled with @code{-fno-hardcfr-check-exceptions}. +With this feature enabled, a subprogram body containing: + +@example +-- ... + Y := F (X); -- May raise exceptions. +-- ... + raise E; -- Not handled internally. +-- ... +@end example + +gets modified as follows: + +@example +begin + -- ... + Y := F (X); -- May raise exceptions. + -- ... + raise E; -- Not handled internally. + -- ... +exception + when others => + CFR.Check (N, Visited'Access, CFG'Access); + raise; +end; +@end example + +Verification may also be performed before No_Return calls, whether +only nothrow ones, with +@code{-fhardcfr-check-noreturn-calls=nothrow}, or all of them, with +@code{-fhardcfr-check-noreturn-calls=always}. The default is +@code{-fhardcfr-check-noreturn-calls=never} for this feature, that +disables checking before No_Return calls. + +When a No_Return call returns control to its caller through an +exception, verification may have already been performed before the +call, if @code{-fhardcfr-check-noreturn-calls=always} is in effect. +The compiler arranges for already-checked No_Return calls without a +preexisting handler to bypass the implicitly-added cleanup handler and +thus the redundant check, but a local exception or cleanup handler, if +present, will modify the set of visited blocks, and checking will take +place again when the caller reaches the next verification point, +whether it is a return or reraise statement after the exception is +otherwise handled, or even another No_Return call. The instrumentation for hardening with control flow redundancy can be observed in dump files generated by the command-line option diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index 7b1aaeba954..2f43b4f71c8 100644 --- a/gcc/ada/gnat_ugn.texi +++ b/gcc/ada/gnat_ugn.texi @@ -19,7 +19,7 @@ @copying @quotation -GNAT User's Guide for Native Platforms , Oct 27, 2022 +GNAT User's Guide for Native Platforms , Nov 14, 2022 AdaCore @@ -17993,7 +17993,6 @@ instr.ads - @c -- Example: A |withing| unit has a |with| clause, it |withs| a |withed| unit @node GNAT and Program Execution,Platform-Specific Information,GNAT Utility Programs,Top @@ -29382,8 +29381,8 @@ to permit their use in free software. @printindex ge -@anchor{cf}@w{ } @anchor{gnat_ugn/gnat_utility_programs switches-related-to-project-files}@w{ } +@anchor{cf}@w{ } @c %**end of body @bye