From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by sourceware.org (Postfix) with ESMTPS id D2398385694E for ; Fri, 12 May 2023 05:44:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D2398385694E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1683870257; x=1715406257; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=Z6hAbvn61E4lVsR2x18RyFJ05TJ0NapNgWl2cdqTNj8=; b=JkQcrJnvil55n585LwEj5Yz1x3vue+n0bTkqKneDdyKWIZK3NtwaYuYG C1IFGqUM37K+ysGTFJNNhkYU9OjQY8oNd836EfsE0fn0wIsLpFHdm3PAf 96znIoTKw8qyElwK4ZtKlN6FwE9Uf4prpLRoACT6tOAr5Pdj9/eocyZvi 0GHXbOwFG1ZufsVwSuZwdXruqULn6k15zaDvlebPIfrNSVVfk5OSEOYYm vMTiRoG1gWFRQhq0LtIfSlGGq1OZro0/gdpph0/AMFhTFpljVeKIMnlVM H6PNrYrXxYCMegxbpXVbmNaw8GS7yDK/x3QdOwYkX5cCwd84QQ10+HZJ4 w==; X-IronPort-AV: E=McAfee;i="6600,9927,10707"; a="348204476" X-IronPort-AV: E=Sophos;i="5.99,269,1677571200"; d="scan'208";a="348204476" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 11 May 2023 22:44:16 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10707"; a="700033759" X-IronPort-AV: E=Sophos;i="5.99,269,1677571200"; d="scan'208";a="700033759" Received: from shvmail03.sh.intel.com ([10.239.245.20]) by orsmga002.jf.intel.com with ESMTP; 11 May 2023 22:44:14 -0700 Received: from shliclel4217.sh.intel.com (shliclel4217.sh.intel.com [10.239.240.127]) by shvmail03.sh.intel.com (Postfix) with ESMTP id 069761007BC8; Fri, 12 May 2023 13:44:14 +0800 (CST) From: liuhongt To: gcc-patches@gcc.gnu.org Cc: crazylht@gmail.com, hjl.tools@gmail.com Subject: [PATCH] Provide -fcf-protection=branch,return. Date: Fri, 12 May 2023 13:42:13 +0800 Message-Id: <20230512054213.2211594-1-hongtao.liu@intel.com> X-Mailer: git-send-email 2.39.1.388.g2fc9e9ca3c MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE 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: Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}. Ok for trunk? gcc/ChangeLog: PR target/89701 * common.opt: Refactor -fcf-protection= to support combination of param. * lto-wrapper.c (merge_and_complain): Adjusted. * opts.c (parse_cf_protection_options): New. (common_handle_option): Decode argument for -fcf-protection=. * opts.h (parse_cf_protection_options): Declare. gcc/testsuite/ChangeLog: PR target/89701 * c-c++-common/fcf-protection-8.c: New test. * c-c++-common/fcf-protection-9.c: New test. * c-c++-common/fcf-protection-10.c: New test. * gcc.target/i386/pr89701-1.c: New test. * gcc.target/i386/pr89701-2.c: New test. * gcc.target/i386/pr89701-3.c: New test. * gcc.target/i386/pr89701-4.c: New test. --- gcc/common.opt | 24 ++---- gcc/lto-wrapper.cc | 21 +++-- gcc/opts.cc | 79 +++++++++++++++++++ gcc/opts.h | 1 + .../c-c++-common/fcf-protection-10.c | 3 + .../c-c++-common/fcf-protection-11.c | 2 + .../c-c++-common/fcf-protection-12.c | 2 + gcc/testsuite/c-c++-common/fcf-protection-8.c | 3 + gcc/testsuite/c-c++-common/fcf-protection-9.c | 3 + gcc/testsuite/gcc.target/i386/pr89701-1.c | 4 + gcc/testsuite/gcc.target/i386/pr89701-2.c | 4 + gcc/testsuite/gcc.target/i386/pr89701-3.c | 5 ++ gcc/testsuite/gcc.target/i386/pr89701-4.c | 5 ++ 13 files changed, 130 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-10.c create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-11.c create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-12.c create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-8.c create mode 100644 gcc/testsuite/c-c++-common/fcf-protection-9.c create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr89701-4.c diff --git a/gcc/common.opt b/gcc/common.opt index a28ca13385a..ac12da52733 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -229,6 +229,10 @@ bool dump_base_name_prefixed = false Variable unsigned int flag_zero_call_used_regs +;; What the CF check should instrument +Variable +unsigned int flag_cf_protection = 0 + ### Driver @@ -1886,28 +1890,10 @@ fcf-protection Common RejectNegative Alias(fcf-protection=,full) fcf-protection= -Common Joined RejectNegative Enum(cf_protection_level) Var(flag_cf_protection) Init(CF_NONE) +Common Joined -fcf-protection=[full|branch|return|none|check] Instrument functions with checks to verify jump/call/return control-flow transfer instructions have valid targets. -Enum -Name(cf_protection_level) Type(enum cf_protection_level) UnknownError(unknown Control-Flow Protection Level %qs) - -EnumValue -Enum(cf_protection_level) String(full) Value(CF_FULL) - -EnumValue -Enum(cf_protection_level) String(branch) Value(CF_BRANCH) - -EnumValue -Enum(cf_protection_level) String(return) Value(CF_RETURN) - -EnumValue -Enum(cf_protection_level) String(check) Value(CF_CHECK) - -EnumValue -Enum(cf_protection_level) String(none) Value(CF_NONE) - finstrument-functions Common Var(flag_instrument_function_entry_exit,1) Instrument function entry and exit with profiling calls. diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc index 5186d040ce0..568c8af659d 100644 --- a/gcc/lto-wrapper.cc +++ b/gcc/lto-wrapper.cc @@ -359,26 +359,33 @@ merge_and_complain (vec &decoded_options, case OPT_fcf_protection_: /* Default to link-time option, else append or check identical. */ if (!cf_protection_option - || cf_protection_option->value == CF_CHECK) + || !memcmp (cf_protection_option->arg, "check", 5)) { + const char* parg = decoded_options[existing_opt].arg; if (existing_opt == -1) decoded_options.safe_push (*foption); - else if (decoded_options[existing_opt].value != foption->value) + else if ((strlen (parg) != strlen (foption->arg)) + || memcmp (parg, foption->arg, strlen (foption->arg))) { if (cf_protection_option - && cf_protection_option->value == CF_CHECK) + && !memcmp (cf_protection_option->arg, "check", 5)) fatal_error (input_location, "option %qs with mismatching values" " (%s, %s)", "-fcf-protection", - decoded_options[existing_opt].arg, + parg, foption->arg); else { /* Merge and update the -fcf-protection option. */ - decoded_options[existing_opt].value - &= (foption->value & CF_FULL); - switch (decoded_options[existing_opt].value) + HOST_WIDE_INT flags1 + = parse_cf_protection_options (foption->arg, + input_location); + HOST_WIDE_INT flags2 + = parse_cf_protection_options (parg, + input_location); + flags2 &= (flags1 & CF_FULL); + switch (flags2) { case CF_NONE: decoded_options[existing_opt].arg = "none"; diff --git a/gcc/opts.cc b/gcc/opts.cc index 86b94d62b58..6389383bc92 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -2187,6 +2187,81 @@ get_closest_sanitizer_option (const string_fragment &arg, return bm.get_best_meaningful_candidate (); } +unsigned int +parse_cf_protection_options (const char *p, location_t loc) +{ + unsigned int flags = 0; + bool combined = false; + while (*p != 0) + { + size_t len; + const char *comma = strchr (p, ','); + if (comma == NULL) + len = strlen (p); + else + { + combined = true; + len = comma - p; + } + + if (len == 0) + { + p = comma + 1; + continue; + } + + switch (len) + { + case 4: + if (!memcmp (p, "full", 4)) + { + if (combined && flags != CF_NONE) + warning_at (loc, 0, "better to use %<-fcf-protection=%> " + "option: full alone instead of in a combination"); + flags |= CF_FULL; + } + else if (!memcmp (p, "none", 4)) + { + if (combined && flags != CF_NONE) + warning_at (loc, 0, "combination of %<-fcf-protection=%> " + "option: none is ignored"); + } + else + error_at (loc, "unrecognized argument to %<-fcf-protection=%> " + "option: %.4s", p); + break; + case 5: + if (!memcmp (p, "check", 5)) + { + if (combined && flags != CF_CHECK) + error_at (loc, "Combination for %<-fcf-protection=%> " + "option: check is not valid"); + flags |= CF_CHECK; + } + else + error_at (loc, "unrecognized argument to %<-fcf-protection=%> " + "option: %.5s", p); + break; + case 6: + if (!memcmp (p, "branch", 6)) + flags |= CF_BRANCH; + else if (!memcmp (p, "return", 6)) + flags |= CF_RETURN; + else + error_at (loc, "unrecognized argument to %<-fcf-protection=%> " + "option: %.6s", p); + break; + default: + error_at (loc, "unrecognized argument to %<-fcf-protection=%> " + "option: %.*s", (int) len, p); + } + + if (comma == NULL) + break; + p = comma + 1; + } + return flags; +} /* Parse comma separated sanitizer suboptions from P for option SCODE, adjust previous FLAGS and return new ones. If COMPLAIN is false, don't issue diagnostics. */ @@ -2671,6 +2746,10 @@ common_handle_option (struct gcc_options *opts, case OPT__completion_: break; + case OPT_fcf_protection_: + opts->x_flag_cf_protection + = parse_cf_protection_options (arg, loc); + break; case OPT_fsanitize_: opts_set->x_flag_sanitize = true; opts->x_flag_sanitize diff --git a/gcc/opts.h b/gcc/opts.h index 9959a440ca1..00d396d95f8 100644 --- a/gcc/opts.h +++ b/gcc/opts.h @@ -425,6 +425,7 @@ extern void control_warning_option (unsigned int opt_index, int kind, extern char *write_langs (unsigned int mask); extern void print_ignored_options (void); extern void handle_common_deferred_options (void); +extern unsigned int parse_cf_protection_options (const char*, location_t); unsigned int parse_sanitizer_options (const char *, location_t, int, unsigned int, int, bool); diff --git a/gcc/testsuite/c-c++-common/fcf-protection-10.c b/gcc/testsuite/c-c++-common/fcf-protection-10.c new file mode 100644 index 00000000000..8692a08374b --- /dev/null +++ b/gcc/testsuite/c-c++-common/fcf-protection-10.c @@ -0,0 +1,3 @@ +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */ +/* { dg-options "-fcf-protection=branch,check" } */ +/* { dg-error "Combination for '-fcf-protection=' option: check is not valid" "" { target *-*-* } 0 } */ diff --git a/gcc/testsuite/c-c++-common/fcf-protection-11.c b/gcc/testsuite/c-c++-common/fcf-protection-11.c new file mode 100644 index 00000000000..2e566350ccd --- /dev/null +++ b/gcc/testsuite/c-c++-common/fcf-protection-11.c @@ -0,0 +1,2 @@ +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */ +/* { dg-options "-fcf-protection=branch,return" } */ diff --git a/gcc/testsuite/c-c++-common/fcf-protection-12.c b/gcc/testsuite/c-c++-common/fcf-protection-12.c new file mode 100644 index 00000000000..b39c2f8e25d --- /dev/null +++ b/gcc/testsuite/c-c++-common/fcf-protection-12.c @@ -0,0 +1,2 @@ +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */ +/* { dg-options "-fcf-protection=return,branch" } */ diff --git a/gcc/testsuite/c-c++-common/fcf-protection-8.c b/gcc/testsuite/c-c++-common/fcf-protection-8.c new file mode 100644 index 00000000000..33e46223b6b --- /dev/null +++ b/gcc/testsuite/c-c++-common/fcf-protection-8.c @@ -0,0 +1,3 @@ +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */ +/* { dg-options "-fcf-protection=branch,none" } */ +/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-* } } 0 } */ diff --git a/gcc/testsuite/c-c++-common/fcf-protection-9.c b/gcc/testsuite/c-c++-common/fcf-protection-9.c new file mode 100644 index 00000000000..7848fe4b959 --- /dev/null +++ b/gcc/testsuite/c-c++-common/fcf-protection-9.c @@ -0,0 +1,3 @@ +/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */ +/* { dg-options "-fcf-protection=branch,full" } */ +/* { dg-warning "better to use '-fcf-protection=' option: full alone instead of in a combination" "" { target { *-*-* } } 0 } */ diff --git a/gcc/testsuite/gcc.target/i386/pr89701-1.c b/gcc/testsuite/gcc.target/i386/pr89701-1.c new file mode 100644 index 00000000000..1879c9ab4d8 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr89701-1.c @@ -0,0 +1,4 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-fcf-protection=branch,return" } */ +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */ +/* { dg-final { scan-assembler-times ".long 0x3" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr89701-2.c b/gcc/testsuite/gcc.target/i386/pr89701-2.c new file mode 100644 index 00000000000..d5100575028 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr89701-2.c @@ -0,0 +1,4 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-fcf-protection=return,branch" } */ +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */ +/* { dg-final { scan-assembler-times ".long 0x3" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr89701-3.c b/gcc/testsuite/gcc.target/i386/pr89701-3.c new file mode 100644 index 00000000000..1505051a2bb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr89701-3.c @@ -0,0 +1,5 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-fcf-protection=return,none" } */ +/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-linux* } } 0 } */ +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */ +/* { dg-final { scan-assembler-times ".long 0x2" 1 } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr89701-4.c b/gcc/testsuite/gcc.target/i386/pr89701-4.c new file mode 100644 index 00000000000..242b8810abb --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr89701-4.c @@ -0,0 +1,5 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-fcf-protection=branch,none" } */ +/* { dg-warning "combination of '-fcf-protection=' option: none is ignored" "" { target { *-*-* } } 0 } */ +/* { dg-final { scan-assembler-times ".note.gnu.property" 1 } } */ +/* { dg-final { scan-assembler-times ".long 0x1" 1 } } */ -- 2.39.1.388.g2fc9e9ca3c