From patchwork Tue May 10 16:29:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 1629279 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=DQhOeGRj; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KyNnC4wHPz9sGF for ; Wed, 11 May 2022 02:30:22 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0E03A395A00A for ; Tue, 10 May 2022 16:30:20 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0E03A395A00A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1652200220; bh=Fdn48cB5T+Qr18jmKlu68VVGOmvcAT7jNz0WyFN9VLY=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=DQhOeGRjbzzAYGIUowH571+r5jgNBOOulGXmXBXt0xJKqwrx1jz3GxF+bSsyQUqO0 HP0ITTP2ZfDkLd82TJNawemR6ygfO+HyXyGfBtBXn/PFKC6Y3YQawt7RocdT/og8MC QHpzLxxGPxtjxX3e49VHES4IHzdYS3W7NDgjIZmo= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pl1-x62e.google.com (mail-pl1-x62e.google.com [IPv6:2607:f8b0:4864:20::62e]) by sourceware.org (Postfix) with ESMTPS id 885C8386EC0E for ; Tue, 10 May 2022 16:29:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 885C8386EC0E Received: by mail-pl1-x62e.google.com with SMTP id j14so17208852plx.3 for ; Tue, 10 May 2022 09:29:57 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Fdn48cB5T+Qr18jmKlu68VVGOmvcAT7jNz0WyFN9VLY=; b=lh9kPfdY4DhVP941yORBpQc88OlvoyEnH2LwEPP4oeUW8MCMCSd+hhBjglNoMHc8lL 8FAWlN+ccyV4/UDqN1yDEqkvi81wjCyzfVdzVsHKqR0xbKFmg71W0OhndWmV3nVYSY4r EhHoKmw/af+sN3GNo6XrdAqbI7ENoQkp7va+y6qPtMCSdojJz17E0ByB5Q1es6R7FfHw ZA+Qfk0lGQ/7t+Zr8D1axLvFletcmTKi2jisIU+QhlGDeuqLc43TR0V2Cnn4jlQAdqmH jleRbj5EboiUVHGa2rMi9j+NbON30VwJmQfG9FPqwyFzLDDaHzvleOk3QIaFKohpndTq mvSg== X-Gm-Message-State: AOAM530eAeJS0L9zF8i4ElAPuHsDwyj2IkVDRsDQK4ZZPnZeYjVVh79B 1+HBcq6RW9M1nABQ7yswdJw= X-Google-Smtp-Source: ABdhPJykmxQwPuYFOBxWKQA9TucXmb6aaUhYFjNgw/zRaBgG7Eb2ILPSK/Kj3J2WuG3K5Ph1BG71sQ== X-Received: by 2002:a17:90b:314c:b0:1dc:767d:a7d9 with SMTP id ip12-20020a17090b314c00b001dc767da7d9mr738332pjb.99.1652200196439; Tue, 10 May 2022 09:29:56 -0700 (PDT) Received: from gnu-tgl-3.localdomain ([172.58.88.122]) by smtp.gmail.com with ESMTPSA id a3-20020a1709027d8300b0015e8d4eb2ccsm2234644plm.278.2022.05.10.09.29.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 May 2022 09:29:55 -0700 (PDT) Received: from gnu-tgl-3.. (localhost [IPv6:::1]) by gnu-tgl-3.localdomain (Postfix) with ESMTP id 8FDD2C03A6; Tue, 10 May 2022 09:29:54 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH] Add -fcf-check-attribute=[yes|no|none] for Linux kernel Date: Tue, 10 May 2022 09:29:54 -0700 Message-Id: <20220510162954.2755700-1-hjl.tools@gmail.com> X-Mailer: git-send-email 2.35.1 MIME-Version: 1.0 X-Spam-Status: No, score=-3028.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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: "H.J. Lu via Gcc-patches" From: "H.J. Lu" Reply-To: "H.J. Lu" Cc: Jakub Jelinek , Richard Biener , Joseph Myers Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" When compiling Linux kernel with -fcf-protection=branch to enable x86 Indiret Branch Tracking (IBT), ENDBR is added to all global functions. This creates more "legal" forward edges than necessary. -mmanual-endbr provides a way to insert ENDBR instruction at function entry only via the 'cf_check' function attribute and programmers can add the 'cf_check' function attribute to functions which can be reached by indirect branch. Add -fcf-check-attribute=[yes|no|none] to imply "cf_check" or "nocf_check" function attributes so that GCC can produce a diagnostic when there is a mismatch in cf_check or nocf_check function attributes. This has been tested on Linux kernel. gcc/ PR target/102953 * attribs.cc (decl_attributes): Add implied cf_check or nocf_check function attributes. * common.opt: Add -fcf-check-attribute=. * flag-types.h (cf_check_attribute): New. * doc/invoke.texi: Document -fcf-check-attribute=. gcc/c/ PR target/102953 * c-decl.cc (diagnose_mismatched_decls): Check implied cf_check and nocf_check function attributes. gcc/testsuite/ PR target/102953 * gcc.target/i386/pr102953-3.c: New test. * gcc.target/i386/pr102953-4.c: Likewise. * gcc.target/i386/pr102953-5.c: Likewise. * gcc.target/i386/pr102953-6.c: Likewise. --- gcc/attribs.cc | 19 +++++++++++++++++++ gcc/c/c-decl.cc | 22 +++++++++++++++++++++- gcc/common.opt | 16 ++++++++++++++++ gcc/doc/invoke.texi | 12 ++++++++++++ gcc/flag-types.h | 8 ++++++++ gcc/testsuite/gcc.target/i386/pr102953-3.c | 8 ++++++++ gcc/testsuite/gcc.target/i386/pr102953-4.c | 7 +++++++ gcc/testsuite/gcc.target/i386/pr102953-5.c | 7 +++++++ gcc/testsuite/gcc.target/i386/pr102953-6.c | 8 ++++++++ 9 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr102953-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr102953-4.c create mode 100644 gcc/testsuite/gcc.target/i386/pr102953-5.c create mode 100644 gcc/testsuite/gcc.target/i386/pr102953-6.c diff --git a/gcc/attribs.cc b/gcc/attribs.cc index b219f878042..34e8707eac1 100644 --- a/gcc/attribs.cc +++ b/gcc/attribs.cc @@ -694,6 +694,25 @@ decl_attributes (tree *node, tree attributes, int flags, attributes = tree_cons (get_identifier ("no_icf"), NULL, attributes); } + /* -fcf-check-attribute=[yes|no] implies "cf_check" or "nocf_check" + function attribute. */ + if (TREE_CODE (*node) == FUNCTION_DECL + && flag_cf_check_attribute != CF_CHECK_ATTRIBUTE_NONE + && !fndecl_built_in_p (*node) + && lookup_attribute ("nocf_check", + DECL_ATTRIBUTES (*node)) == nullptr + && lookup_attribute ("cf_check", + DECL_ATTRIBUTES (*node)) == nullptr + && (!attributes + || (lookup_attribute ("nocf_check", attributes) == nullptr + && lookup_attribute ("cf_check", attributes) == nullptr))) + { + const char *attr = (flag_cf_check_attribute == CF_CHECK_ATTRIBUTE_YES + ? "cf_check" : "nocf_check"); + attributes = tree_cons (get_identifier (attr), nullptr, + attributes); + } + targetm.insert_attributes (*node, &attributes); /* Note that attributes on the same declaration are not necessarily diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index c701f07befe..787c39dc0fe 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -2133,7 +2133,27 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, error ("conflicting type qualifiers for %q+D", newdecl); } else - error ("conflicting types for %q+D; have %qT", newdecl, newtype); + { + if (flag_cf_check_attribute == CF_CHECK_ATTRIBUTE_NO + && (!lookup_attribute ("nocf_check", + TYPE_ATTRIBUTES (oldtype)) + != !lookup_attribute ("nocf_check", + TYPE_ATTRIBUTES (newtype)))) + error ("conflicting types for %q+D; have %qT with " + "implied % attribute", + newdecl, newtype); + else if (flag_cf_check_attribute == CF_CHECK_ATTRIBUTE_YES + && (!lookup_attribute ("cf_check", + TYPE_ATTRIBUTES (oldtype)) + != !lookup_attribute ("cf_check", + TYPE_ATTRIBUTES (newtype)))) + error ("conflicting types for %q+D; have %qT with " + "implied % attribute", + newdecl, newtype); + else + error ("conflicting types for %q+D; have %qT", + newdecl, newtype); + } diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); locate_old_decl (olddecl); return false; diff --git a/gcc/common.opt b/gcc/common.opt index 8a0dafc522d..d5952a44765 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1877,6 +1877,22 @@ Enum(cf_protection_level) String(check) Value(CF_CHECK) EnumValue Enum(cf_protection_level) String(none) Value(CF_NONE) +fcf-check-attribute= +Target RejectNegative Joined Enum(cf_check_attribute) Var(flag_cf_check_attribute) Init(CF_CHECK_ATTRIBUTE_NONE) +-fcf-check-attribute=[none|yes|no] Select the implied function attribute. + +Enum +Name(cf_check_attribute) Type(enum cf_check_attribute) UnknownError(unknown default Control-Flow attribute %qs) + +EnumValue +Enum(cf_check_attribute) String(none) Value(CF_CHECK_ATTRIBUTE_NONE) + +EnumValue +Enum(cf_check_attribute) String(yes) Value(CF_CHECK_ATTRIBUTE_YES) + +EnumValue +Enum(cf_check_attribute) String(no) Value(CF_CHECK_ATTRIBUTE_NO) + finstrument-functions Common Var(flag_instrument_function_entry_exit) Instrument function entry and exit with profiling calls. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 7a35d9613a4..22e02b8be7e 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -606,6 +606,7 @@ Objective-C and Objective-C++ Dialects}. -fasan-shadow-offset=@var{number} -fsanitize-sections=@var{s1},@var{s2},... @gol -fsanitize-undefined-trap-on-error -fbounds-check @gol -fcf-protection=@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]} @gol +-fcf-check-attribute=@r{[}none@r{|}yes@r{|}no@r{]} @gol -fharden-compares -fharden-conditional-branches @gol -fstack-protector -fstack-protector-all -fstack-protector-strong @gol -fstack-protector-explicit -fstack-check @gol @@ -16070,6 +16071,17 @@ Currently the x86 GNU/Linux target provides an implementation based on Intel Control-flow Enforcement Technology (CET) which works for i686 processor or newer. +@item -fcf-check-attribute=@r{[}none@r{|}yes@r{|}no@r{]} +@opindex fcf-check-attribute +Select the implied function attribute for code instrumentation of +control-flow transfers. + +The value @code{yes} makes the @code{cf_check} attribute implied on +functions. The value @code{no} makes the @code{nocf_check} attribute +implied on functions. The value @code{none}, which is the default, +doesn't imply the @code{cf_check} nor @code{nocf_check} attributes on +functions. + @item -fharden-compares @opindex fharden-compares For every logical test that survives gimple optimizations and is diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 2c8498169e0..c84d67b1ac8 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -449,6 +449,14 @@ enum cf_protection_level CF_CHECK = 1 << 3 }; +/* Default Control-Flow Protection attribute. */ +enum cf_check_attribute +{ + CF_CHECK_ATTRIBUTE_NONE = 0, + CF_CHECK_ATTRIBUTE_YES, + CF_CHECK_ATTRIBUTE_NO +}; + /* Parloops schedule type. */ enum parloops_schedule_type { diff --git a/gcc/testsuite/gcc.target/i386/pr102953-3.c b/gcc/testsuite/gcc.target/i386/pr102953-3.c new file mode 100644 index 00000000000..fd92c9c577e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr102953-3.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -fcf-protection -mmanual-endbr -fcf-check-attribute=no" } */ + +static void __attribute__((cf_check)) foo(void); +static void foo(void) /* { dg-error "implied 'nocf_check' attribute" } */ +{ +} +void (*ptr)(void) = foo; /* { dg-warning "incompatible pointer type" } */ diff --git a/gcc/testsuite/gcc.target/i386/pr102953-4.c b/gcc/testsuite/gcc.target/i386/pr102953-4.c new file mode 100644 index 00000000000..cd8f4279180 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr102953-4.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -fcf-protection -mmanual-endbr -fcf-check-attribute=no" } */ + +static void foo(void) +{ +} +void (*ptr)(void) = foo; /* { dg-warning "incompatible pointer type" } */ diff --git a/gcc/testsuite/gcc.target/i386/pr102953-5.c b/gcc/testsuite/gcc.target/i386/pr102953-5.c new file mode 100644 index 00000000000..b1bd4afe85f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr102953-5.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -fcf-protection -mmanual-endbr -fcf-check-attribute=no" } */ + +extern void foo(void); +void __attribute__((cf_check)) foo(void) /* { dg-error "implied 'nocf_check' attribute" } */ +{ +} diff --git a/gcc/testsuite/gcc.target/i386/pr102953-6.c b/gcc/testsuite/gcc.target/i386/pr102953-6.c new file mode 100644 index 00000000000..ee0c66f94cb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr102953-6.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -fcf-protection -mmanual-endbr -fcf-check-attribute=no" } */ + +static int __attribute__((cf_check)) foo(char a[], int b) +{ + return 0; +} +int (*ptr)(char[], int) = foo;