Enable Shadow Stack by default on x86_64

Resolves: RHEL-223924
This commit is contained in:
Paul Murphy 2026-08-10 17:26:33 -05:00
parent 7d47df59fc
commit b03c8da1e1
2 changed files with 320 additions and 0 deletions

View File

@ -0,0 +1,315 @@
From b719e2d72779dd0493e38c8c71a5916dfd0d99c6 Mon Sep 17 00:00:00 2001
From: Josh Stone <jistone@redhat.com>
Date: Thu, 30 Apr 2026 13:21:13 -0700
Subject: [PATCH] Enable SHSTK by default on x86_64-unknown-linux-gnu
(cherry picked from commit ab9f08d9ae374144bd78524a9edec007abcf9a35)
---
compiler/rustc_codegen_llvm/src/context.rs | 9 ++---
compiler/rustc_session/src/config.rs | 24 +++----------
compiler/rustc_session/src/options.rs | 35 +++++++++----------
compiler/rustc_session/src/session.rs | 10 ++++--
compiler/rustc_target/src/spec/mod.rs | 24 +++++++++++++
.../spec/targets/x86_64_unknown_linux_gnu.rs | 7 +++-
6 files changed, 63 insertions(+), 46 deletions(-)
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 3e575f969afa..f4f08ef2a517 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -23,12 +23,12 @@
use rustc_middle::{bug, span_bug};
use rustc_session::Session;
use rustc_session::config::{
- BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet,
+ BranchProtection, CFGuard, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet,
};
use rustc_span::{DUMMY_SP, Span, Spanned, Symbol};
use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::spec::{
- Arch, CfgAbi, Env, HasTargetSpec, Os, RelocModel, SmallDataThresholdSupport, Target, TlsModel,
+ Arch, CFProtection, CfgAbi, Env, HasTargetSpec, Os, RelocModel, SmallDataThresholdSupport, Target, TlsModel,
};
use smallvec::SmallVec;
@@ -427,7 +427,8 @@ pub(crate) unsafe fn create_module<'ll>(
}
// Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
- if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
+ let cf_protection = sess.cf_protection();
+ if let CFProtection::Branch | CFProtection::Full = cf_protection {
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
@@ -435,7 +436,7 @@ pub(crate) unsafe fn create_module<'ll>(
1,
);
}
- if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
+ if let CFProtection::Return | CFProtection::Full = cf_protection {
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 2040cd48ec44..4229645f9216 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -72,22 +72,6 @@ pub enum CFGuard {
Checks,
}
-/// The different settings that the `-Z cf-protection` flag can have.
-#[derive(Clone, Copy, PartialEq, Hash, Debug)]
-pub enum CFProtection {
- /// Do not enable control-flow protection
- None,
-
- /// Emit control-flow protection for branches (enables indirect branch tracking).
- Branch,
-
- /// Emit control-flow protection for returns.
- Return,
-
- /// Emit control-flow protection for both branches and returns.
- Full,
-}
-
#[derive(Clone, Copy, Debug, PartialEq, Hash, StableHash, Encodable, Decodable)]
pub enum OptLevel {
/// `-Copt-level=0`
@@ -3042,13 +3026,13 @@ pub(crate) mod dep_tracking {
use rustc_span::edition::Edition;
use rustc_span::{RealFileName, RemapPathScopeComponents};
use rustc_target::spec::{
- CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel,
- RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTuple,
- TlsModel,
+ CFProtection, CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy,
+ RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility,
+ TargetTuple, TlsModel,
};
use super::{
- AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CFProtection, CoverageOptions,
+ AnnotateMoves, AutoDiff, BranchProtection, CFGuard, CoverageOptions,
CrateType, DebugInfo, DebugInfoCompression, ErrorOutputType, FmtDebug, FunctionReturn,
InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, LocationDetail,
LtoCli, MirStripDebugInfo, NextSolverConfig, Offload, OptLevel, OutFileName, OutputType,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index aa9331ee8f65..e1e772e1265d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -15,9 +15,9 @@
use rustc_span::edition::Edition;
use rustc_span::{RealFileName, RemapPathScopeComponents, SourceFileHashAlgorithm};
use rustc_target::spec::{
- CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
- RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility,
- TargetTuple, TlsModel,
+ CFProtection, CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe,
+ PanicStrategy, RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector,
+ SymbolVisibility, TargetTuple, TlsModel,
};
use crate::config::*;
@@ -1286,22 +1286,20 @@ pub(crate) fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
true
}
- pub(crate) fn parse_cfprotection(slot: &mut CFProtection, v: Option<&str>) -> bool {
- if v.is_some() {
- let mut bool_arg = None;
- if parse_opt_bool(&mut bool_arg, v) {
- *slot = if bool_arg.unwrap() { CFProtection::Full } else { CFProtection::None };
- return true;
+ pub(crate) fn parse_cfprotection(slot: &mut Option<CFProtection>, v: Option<&str>) -> bool {
+ let mut bool_arg = None;
+ *slot = Some(match v {
+ Some(_) if parse_opt_bool(&mut bool_arg, v) => {
+ if bool_arg.unwrap() {
+ CFProtection::Full
+ } else {
+ CFProtection::None
+ }
}
- }
-
- *slot = match v {
- None | Some("none") => CFProtection::None,
- Some("branch") => CFProtection::Branch,
- Some("return") => CFProtection::Return,
- Some("full") => CFProtection::Full,
+ Some(s) if let Ok(cfp) = CFProtection::from_str(s) => cfp,
Some(_) => return false,
- };
+ None => CFProtection::None,
+ });
true
}
@@ -2234,7 +2232,8 @@ pub(crate) fn parse_assert_incr_state(
"whether the stable interface is being built"),
cache_proc_macros: bool = (false, parse_bool, [TRACKED],
"cache the results of derive proc macro invocations (potentially unsound!) (default: no"),
- cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
+ #[rustc_lint_opt_deny_field_access("use `Session::cf_protection` instead of this field")]
+ cf_protection: Option<CFProtection> = (None, parse_cfprotection, [TRACKED],
"instrument control-flow architecture protection"),
check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED],
"show all expected values in check-cfg diagnostics (default: no)"),
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 003164e8f905..bd0b9ffdb6c4 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -29,9 +29,9 @@
use rustc_span::{RealFileName, Span, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{
- Arch, CodeModel, DebuginfoKind, Os, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
- SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target,
- TargetTuple, TlsModel, apple,
+ Arch, CFProtection, CodeModel, DebuginfoKind, Os, PanicStrategy, RelocModel, RelroLevel,
+ SanitizerSet, SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility,
+ Target, TargetTuple, TlsModel, apple,
};
use crate::code_stats::CodeStats;
@@ -770,6 +770,10 @@ pub fn stack_protector(&self) -> StackProtector {
}
}
+ pub fn cf_protection(&self) -> CFProtection {
+ self.opts.unstable_opts.cf_protection.unwrap_or(self.target.options.cf_protection)
+ }
+
pub fn must_emit_unwind_tables(&self) -> bool {
// This is used to control the emission of the `uwtable` attribute on
// LLVM functions. The `uwtable` attribute according to LLVM is:
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index d6a9e27c4655..eee118962332 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1374,6 +1374,26 @@ pub enum StackProtector {
into_diag_arg_using_display!(StackProtector);
+crate::target_spec_enum! {
+ /// The different settings for control-flow protection for targets,
+ /// which may also be overridden by `-Z cf-protection`.
+ pub enum CFProtection {
+ /// Do not enable control-flow protection
+ None = "none",
+
+ /// Emit control-flow protection for branches (enables indirect branch tracking).
+ Branch = "branch",
+
+ /// Emit control-flow protection for returns.
+ Return = "return",
+
+ /// Emit control-flow protection for both branches and returns.
+ Full = "full",
+ }
+
+ parse_error_type = "control-flow protection";
+}
+
crate::target_spec_enum! {
pub enum BinaryFormat {
Coff = "coff",
@@ -2694,6 +2714,9 @@ pub struct TargetOptions {
/// since this is most common among tier 1 and tier 2 targets.
pub supports_stack_protector: bool,
+ /// The level of control-flow protection enabled for a target -- `None` by default.
+ pub cf_protection: CFProtection,
+
/// The name of entry function.
/// Default value is "main"
pub entry_name: StaticCow<str>,
@@ -2942,6 +2965,7 @@ fn default() -> TargetOptions {
c_enum_min_bits: None,
generate_arange_section: true,
supports_stack_protector: true,
+ cf_protection: CFProtection::None,
entry_name: "main".into(),
entry_abi: CanonAbi::C,
supports_xray: false,
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
index defa9f146d79..41c4a19b5270 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
@@ -1,5 +1,6 @@
use crate::spec::{
- Arch, Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, base,
+ Arch, CFProtection, Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target,
+ TargetMetadata, base,
};
pub(crate) fn target() -> Target {
@@ -21,6 +22,10 @@ pub(crate) fn target() -> Target {
| SanitizerSet::REALTIME;
base.supports_xray = true;
+ // Shadow Stack doesn't change codegen -- this only enables the SHSTK flag in
+ // `.note.gnu.property` so glibc will use it when the system is enabled.
+ base.cf_protection = CFProtection::Return;
+
Target {
llvm_target: "x86_64-unknown-linux-gnu".into(),
metadata: TargetMetadata {
--
diff --git a/tests/codegen-llvm/cf-protection.rs b/tests/codegen-llvm/cf-protection.rs
index a1c902755af..b233b241a01 100644
--- a/tests/codegen-llvm/cf-protection.rs
+++ b/tests/codegen-llvm/cf-protection.rs
@@ -21,7 +21,7 @@
pub fn test() {}
// undefined-NOT: !"cf-protection-branch"
-// undefined-NOT: !"cf-protection-return"
+// undefined: !"cf-protection-return"
// none-NOT: !"cf-protection-branch"
// none-NOT: !"cf-protection-return"
--
diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs
index c8a22205a5f..155dea32443 100644
--- a/compiler/rustc_target/src/spec/json.rs
+++ b/compiler/rustc_target/src/spec/json.rs
@@ -12,7 +12,7 @@
TargetKind, TargetOptions, TargetWarnings, TlsModel,
};
use crate::json::{Json, ToJson};
-use crate::spec::{AbiMap, LlvmAbi};
+use crate::spec::{AbiMap, CFProtection, LlvmAbi};
impl Target {
/// Loads a target descriptor from a JSON object.
@@ -224,6 +224,7 @@ macro_rules! forward_opt {
forward!(small_data_threshold_support);
forward!(entry_name);
forward!(supports_xray);
+ forward!(cf_protection);
// we're going to run `update_from_cli`, but that won't change the target's AbiMap
// FIXME: better factor the Target definition so we enforce this on a type level
@@ -408,6 +409,7 @@ macro_rules! target_option_val {
target_option_val!(entry_name);
target_option_val!(entry_abi);
target_option_val!(supports_xray);
+ target_option_val!(cf_protection);
// Serializing `-Clink-self-contained` needs a dynamic key to support the
// backwards-compatible variants.
@@ -630,6 +632,7 @@ struct TargetSpecJson {
entry_name: Option<StaticCow<str>>,
supports_xray: Option<bool>,
entry_abi: Option<ExternAbiWrapper>,
+ cf_protection: Option<CFProtection>,
}
pub fn json_schema() -> schemars::Schema {
--
2.55.0

View File

@ -139,6 +139,10 @@ Patch6: rustc-1.97.0-unbundle-sqlite.patch
# stage0 tries to copy all of /usr/lib, sometimes unsuccessfully, see #143735
Patch7: 0001-only-copy-rustlib-into-stage0-sysroot.patch
# https://fedoraproject.org/wiki/Changes/ShadowStack
# This patch enables `-Zcf-protection=return` for SHSTK by default
Patch8: 0001-Enable-SHSTK-by-default-on-x86_64-unknown-linux-gnu.patch
### RHEL-specific patches below ###
# Simple rpm macros for rust-toolset (as opposed to full rust-packaging)
@ -713,6 +717,7 @@ test "$(cut -d' ' -f1 ./version)" = "%{lua: print((rpm.expand('%version'):gsub('
%patch -P6 -p1
%endif
%patch -P7 -p1
%patch -P8 -p1
%if %with disabled_libssh2
%patch -P100 -p1