Repository navigation
Conversation
|
Some changes occurred in tests/codegen-llvm/stack-protector.rs cc @rust-lang/project-exploit-mitigations, @rcvalle
This PR modifies If appropriate, please update Some changes occurred in src/doc/rustc/src/exploit-mitigations.md cc @rust-lang/project-exploit-mitigations, @rcvalle Some changes occurred in tests/ui/stack-protector cc @rust-lang/project-exploit-mitigations, @rcvalle |
|
|
|
actually, r? @rcvalle |
|
This needs a FCP |
This comment has been minimized.
This comment has been minimized.
56f8fa3 to
a172a39
Compare
This comment has been minimized.
This comment has been minimized.
…ic, r=jieyouxu Remove `-Z stack-protector=basic` This is a part of the stack-protector stabilization (pulled out from rust-lang#165704) The `-Z stack-protector=basic` mode (`-fstack-protector`) uses heuristics that are specifically designed to catch old-C-style string manipulation. This is not a good fit to Rust, which does not perform much unsafe C-style string manipulation. As far as I can tell, nobody has been asking for it, and few people are using it even in today's C - modern distros (e.g. Debian) tend to use `-fstack-protector-strong`. Therefore, `-Z stack-protector=basic` has been **removed**. If anyone is interested in it, they are welcome to add it back as an unstable option. r? @jieyouxu
Rollup merge of #165812 - arielb1:remove-stack-protector-basic, r=jieyouxu Remove `-Z stack-protector=basic` This is a part of the stack-protector stabilization (pulled out from #165704) The `-Z stack-protector=basic` mode (`-fstack-protector`) uses heuristics that are specifically designed to catch old-C-style string manipulation. This is not a good fit to Rust, which does not perform much unsafe C-style string manipulation. As far as I can tell, nobody has been asking for it, and few people are using it even in today's C - modern distros (e.g. Debian) tend to use `-fstack-protector-strong`. Therefore, `-Z stack-protector=basic` has been **removed**. If anyone is interested in it, they are welcome to add it back as an unstable option. r? @jieyouxu
| ## stack-protector | ||
|
|
||
| The option `-C stack-protector` (currently also supported in the | ||
| old style `-Z stack-protector`) controls the generation of | ||
| stack-protector canaries. | ||
|
|
||
| This flag controls stack smashing protection strategy. | ||
|
|
||
| Supported values for this option are: | ||
| - `none` (default): Disable stack canary generation | ||
| - `strong`: Generate stack canaries in all functions, unless the compiler | ||
| can prove these functions can't be the source of a stack | ||
| buffer overflow (even in the presence of undefined behavior). | ||
|
|
||
| This provides similar security guarantees to Clang's | ||
| `-fstack-protector-strong`. | ||
|
|
||
| The exact rules are unstable and subject to change, but | ||
| currently, it generates stack protectors for functions that, | ||
| *post-optimization*, contain LLVM allocas (which | ||
| include all stack allocations - including fixed-size | ||
| allocations - that are used in a way that is not completely | ||
| determined by static control flow). | ||
| - `all`: Generate stack canaries in all functions | ||
|
|
||
| rustc does not have a mode equivalent to Clang's (or GCC's) | ||
| plain `-fstack-protector`. `-fstack-protector` is an older heuristic | ||
| designed for C, that only protects functions that allocate a | ||
| `char buf[N];` buffer on the stack, making it prone to buffer overflows | ||
| from length miscalculations. This heuristic is poorly suited for Rust | ||
| code. Even in C codebases, `-fstack-protector-strong` is nowadays | ||
| preferred because plain `-fstack-protector` misses many stack | ||
| buffer overflows. | ||
|
|
||
| Stack protectors are not supported on some targets such as GPU targets, use | ||
| of stack protectors on these targets is an error. | ||
|
|
There was a problem hiding this comment.
A couple suggestions:
- I don't think we should mention the unstable flag. We don't typically mention the
-Zversion when stabilizing a feature. - We should note that this flag is heavily dependent on the codegen-backend. Since rustc really does nothing with this flag other than pass it to the backend, we should mention that somehow.
- I would generalize the documentation a bit since we specifically are not promising any particular heuristic is used in any case.
- I'd also make the note about
-fstack-protectormuch more concise. It's quite a bit of the docs here by word count for a feature we're not supporting 🙂
| ## stack-protector | |
| The option `-C stack-protector` (currently also supported in the | |
| old style `-Z stack-protector`) controls the generation of | |
| stack-protector canaries. | |
| This flag controls stack smashing protection strategy. | |
| Supported values for this option are: | |
| - `none` (default): Disable stack canary generation | |
| - `strong`: Generate stack canaries in all functions, unless the compiler | |
| can prove these functions can't be the source of a stack | |
| buffer overflow (even in the presence of undefined behavior). | |
| This provides similar security guarantees to Clang's | |
| `-fstack-protector-strong`. | |
| The exact rules are unstable and subject to change, but | |
| currently, it generates stack protectors for functions that, | |
| *post-optimization*, contain LLVM allocas (which | |
| include all stack allocations - including fixed-size | |
| allocations - that are used in a way that is not completely | |
| determined by static control flow). | |
| - `all`: Generate stack canaries in all functions | |
| rustc does not have a mode equivalent to Clang's (or GCC's) | |
| plain `-fstack-protector`. `-fstack-protector` is an older heuristic | |
| designed for C, that only protects functions that allocate a | |
| `char buf[N];` buffer on the stack, making it prone to buffer overflows | |
| from length miscalculations. This heuristic is poorly suited for Rust | |
| code. Even in C codebases, `-fstack-protector-strong` is nowadays | |
| preferred because plain `-fstack-protector` misses many stack | |
| buffer overflows. | |
| Stack protectors are not supported on some targets such as GPU targets, use | |
| of stack protectors on these targets is an error. | |
| ## stack-protector | |
| The option `-C stack-protector` controls the generation of | |
| stack-protector canaries which offer stack smashing protection. | |
| This option is heavily dependent on the codegen-backend used by | |
| rustc and the exact behavior of each value is unstable and subject to change. | |
| Supported values for this option are: | |
| - `none` (default): Disable stack canary generation | |
| - `strong`: Generate stack canaries in any function that could be the source | |
| of a stack buffer overflow (even in the presence of undefined behavior). | |
| This provides similar security guarantees to Clang (or GCC's) | |
| `-fstack-protector-strong`. | |
| - `all`: Generate stack canaries in all functions | |
| There is no mode equivalent to Clang's (or GCC's) plain `-fstack-protector` | |
| because its heuristic is tuned for C and does not offer protection for Rust programs. | |
| Stack protectors are not supported on some targets such as GPU targets; use | |
| of stack protectors on these targets is an error. |
There was a problem hiding this comment.
I prefer the softer "The exact presence and location of the stack-protector canaries is a codegen detail that is
unstable and subject to change.", but will do the other changes
There was a problem hiding this comment.
I also have a preference for the heavier emphasis (or something to that affect)
This option is heavily dependent on the codegen-backend used by rustc and the exact behavior of each value is unstable and subject to change.
with the rationale that if you're using -C stack-protectors you probably expect that stack protectors actually Do Something ™️. The CG backend can ignore the flag passed to it or not support generating stack-protector canaries at all. We should be abundantly clear about this.
| if my_mitigation.kind == DeniedPartialMitigationKind::StackProtector | ||
| && !tcx.sess.using_stable_stack_protector() | ||
| { | ||
| // make stack-protector with -Z stack-protector only a forward-compat warning since it was | ||
| // pretty widely used. When using -C stack-protector, it should still be a hard error since | ||
| // -C stack-protector has no pre-existing users |
There was a problem hiding this comment.
nit: seems like this comment should move up?
| if my_mitigation.kind == DeniedPartialMitigationKind::StackProtector | |
| && !tcx.sess.using_stable_stack_protector() | |
| { | |
| // make stack-protector with -Z stack-protector only a forward-compat warning since it was | |
| // pretty widely used. When using -C stack-protector, it should still be a hard error since | |
| // -C stack-protector has no pre-existing users | |
| // Make stack-protector with -Z stack-protector only a forward-compat warning since it was | |
| // pretty widely used. When using -C stack-protector, it should still be a hard error since | |
| // -C stack-protector has no pre-existing users | |
| if my_mitigation.kind == DeniedPartialMitigationKind::StackProtector | |
| && !tcx.sess.using_stable_stack_protector() | |
| { | |
| // also test that stack protector is fine in edition 2024 with an explicit allow | ||
| //@ [stack-protector-2024-explicit-allow] compile-flags: -Z stack-protector=all -Z allow-partial-mitigations=stack-protector | ||
|
|
||
| fn main() {} |
There was a problem hiding this comment.
Why did we delete this test?
There was a problem hiding this comment.
probably vanished in a rebase, re-adding it
a172a39 to
af4ad80
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
I propose stabilizing `-Cstack-protector` as `-Zstack-protector`. This PR adds a new `-Cstack-protector` flag, leaving the unstable `-Z` flag as is to ease the transition period. The `-Z` flag will be removed in the future. No RFC/MCP, this flag was added in 84197 and was not deemed large enough to require additional process. The tracking issue for this feature is 114903. The `-Cstack-protector=strong` mode uses the same underlying heuristics as Clang's `-fstack-protector-strong`. These heuristics weren't designed for Rust, and may be over-conservative in some cases - for example, if Rust stores a field's data in an alloca using an LLVM array type, LLVM regard the alloca as meaning that the function has a C array, and enable stack overflow canaries even if the function accesses the alloca in a safe way. Some people thought we should wait on stabilization until there are better heuristics, but I didn't hear about any concrete case where this unduly harms performance, and I think that when a need comes, we can improve the heuristics in LLVM after stabilization. The heuristics do seem to not be under-conservative, so this should not be a security risk. The `-Cstack-protector=basic` mode (`-fstack-protector`) uses heuristics that are specifically designed to catch old-C-style string manipulation. This is not a good fit to Rust, which does not perform much unsafe C-style string manipulation. As far as I can tell, nobody has been asking for it, and few people are using it even in today's C - modern distros (e.g. [Debian]) tend to use `-fstack-protector-strong`. Therefore, `-Cstack-protector=basic` has been **removed**. If anyone is interested in it, they are welcome to add it back as an unstable option. [Debian]: https://wiki.debian.org/Hardening#DEB_BUILD_HARDENING_STACKPROTECTOR_.28gcc.2Fg.2B-.2B-_-fstack-protector-strong.29 Most implementation was done in <rust-lang#84197>. The command-line attribute enables the relevant LLVM attribute on all functions in <https://github.com/rust-lang/rust/blob/68baa87ba6f03f8b6af2a368690161f1601e4040/compiler/rustc_codegen_llvm/src/attributes.rs#L267-L276>. Each target can indicate that it does not support stack canaries - currently, the GPU platforms `nvptx64-nvidia-cuda` and `amdgcn-amd-amdhsa`. On these platforms, use of `-Cstack-protector` causes an error. The feature has tests that make sure that the LLVM heuristic gives reasonable results for several functions, by checking for `__security_check_cookie` (on Windows) or `__stack_chk_fail` (on Linux). See <https://github.com/rust-lang/rust/tree/68baa87ba6f03f8b6af2a368690161f1601e4040/tests/assembly-llvm/stack-protector> No call-for-testing has been conducted, but the feature seems to be in use. No reported bugs seem to exist. - bbjornse was the original implementor at 84197 - mrcnski documented it at 111722 - wesleywiser added tests for Windows at 116037 - davidtwco worked on the feature at 121742 - nikic provided support from the LLVM side (on Zulip on <https://rust-lang.zulipchat.com/#narrow/channel/233931-t-compiler.2Fmajor-changes/topic/Proposal.20for.20Adapt.20Stack.20Protector.20for.20Ru.E2.80.A6.20compiler-team.23841> and elsewhere), thanks nikic! No FIXMEs related to this feature. This feature cannot cause undefined behavior. No changes to reference/spec, docs added to the codegen docs as part of the stabilization PR. No. None. No support needed for rustdoc, clippy, rust-analyzer, rustfmt or rustup. Cargo could expose this as an option in build profiles but I would expect the decision as to what version should be used would be made for the entire crate graph at build time rather than by individual package authors. `-C stack-protector` is propagated to C compilers using cc-rs via rust-lang/cc-rs issue 1550
af4ad80 to
f05f75a
Compare
| // Use -Zstack-protector here instead of -Cstack-protector | ||
| // to avoid bootstrap problems using the 1.100 stage0 compiler. | ||
| rustflags.arg(&format!("-Zstack-protector={stack_protector}")); |
There was a problem hiding this comment.
I think this should probably use
cfg(bootstrap)using the unstable-Zform (that's what 1.101 stage0 beta compiler would know after stage 0 bump in Bump stage0 to 1.101.0-beta.1 #165778)cfg(not(bootstrap))using the stable-Cform
There was a problem hiding this comment.
In this context (bootstrap itself) you can check build_compiler_stage == 0 for the old way.
(but do add a cfg(bootstrap) comment to help us find this later)
| | Read-only relocations and immediate binding | Yes | Yes | 1.21.0 (2017-10-12) | | ||
| | Heap corruption protection | Yes | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) | | ||
| | Stack smashing protection | Yes | No, `-Z stack-protector` | Nightly | | ||
| | Stack smashing protection | Yes | No, `-C stack-protector` | 1.101.0 (2026-12-24) | |
There was a problem hiding this comment.
This will need to become 1.102.0 (2027-02-04) https://forge.rust-lang.org/index.html I think. Nightly is already on 1.102.0 cycle.
| ## stack-protector | ||
|
|
||
| The option `-C stack-protector` (currently also supported in the | ||
| old style `-Z stack-protector`) controls the generation of | ||
| stack-protector canaries. | ||
|
|
||
| This flag controls stack smashing protection strategy. | ||
|
|
||
| Supported values for this option are: | ||
| - `none` (default): Disable stack canary generation | ||
| - `strong`: Generate stack canaries in all functions, unless the compiler | ||
| can prove these functions can't be the source of a stack | ||
| buffer overflow (even in the presence of undefined behavior). | ||
|
|
||
| This provides similar security guarantees to Clang's | ||
| `-fstack-protector-strong`. | ||
|
|
||
| The exact rules are unstable and subject to change, but | ||
| currently, it generates stack protectors for functions that, | ||
| *post-optimization*, contain LLVM allocas (which | ||
| include all stack allocations - including fixed-size | ||
| allocations - that are used in a way that is not completely | ||
| determined by static control flow). | ||
| - `all`: Generate stack canaries in all functions | ||
|
|
||
| rustc does not have a mode equivalent to Clang's (or GCC's) | ||
| plain `-fstack-protector`. `-fstack-protector` is an older heuristic | ||
| designed for C, that only protects functions that allocate a | ||
| `char buf[N];` buffer on the stack, making it prone to buffer overflows | ||
| from length miscalculations. This heuristic is poorly suited for Rust | ||
| code. Even in C codebases, `-fstack-protector-strong` is nowadays | ||
| preferred because plain `-fstack-protector` misses many stack | ||
| buffer overflows. | ||
|
|
||
| Stack protectors are not supported on some targets such as GPU targets, use | ||
| of stack protectors on these targets is an error. | ||
|
|
There was a problem hiding this comment.
I also have a preference for the heavier emphasis (or something to that affect)
This option is heavily dependent on the codegen-backend used by rustc and the exact behavior of each value is unstable and subject to change.
with the rationale that if you're using -C stack-protectors you probably expect that stack protectors actually Do Something ™️. The CG backend can ignore the flag passed to it or not support generating stack-protector canaries at all. We should be abundantly clear about this.
| //@ [all-z] compile-flags: -Z stack-protector=all -Z allow-partial-mitigations=stack-protector | ||
| //@ [strong] compile-flags: -C stack-protector=strong -Z allow-partial-mitigations=stack-protector | ||
| //@ [strong-z] compile-flags: -Z stack-protector=strong -Z allow-partial-mitigations=stack-protector | ||
| //@ [strong-c-overrides-z] compile-flags: -C stack-protector=strong -Z stack-protector=all -Z allow-partial-mitigations=stack-protector |
There was a problem hiding this comment.
This feels a bit awkward to me. Is this intended to soften the -Z => -C flag transition? Can we timebox some removal of the -Z form post-stabilization?
|
@rust-rfcbot fcp merge compiler |
|
@jieyouxu has proposed to merge this. The next step is review by the rest of the tagged team members:
No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
Stabilize
-Zstack-protectoras-Cstack-protectorMoved from #146369
I propose stabilizing
-Zstack-protectoras-Cstack-protector. This PR adds a new-Cstack-protectorflag, leaving the unstable-Zflag as is to ease the transition period. The-Zflag will be removed in the future.Please hold technical discussion in the zulip thread at https://rust-lang.zulipchat.com/#narrow/channel/233931-t-compiler.2Fmajor-changes/topic/Proposal.20for.20Adapt.20Stack.20Protector.20for.20Ru.E2.80.A6.20compiler-team.23841
Let's move mitigation enforcement discussion to https://rust-lang.zulipchat.com/#narrow/channel/233931-t-compiler.2Fmajor-changes/topic/Mitigation.20enforcement.20.28.60-C.20allow-partial-sanitizer.60.29/with/539144305
-Zstack-protectorstabilization reportWhat is the RFC for this feature and what changes have occurred to the user-facing design since the RFC was finalized?
No RFC/MCP, this flag was added in #84197 and was not deemed large enough to require additional process.
The tracking issue for this feature is #114903.
What behavior are we committing to that has been controversial? Summarize the major arguments pro/con.
The
-Cstack-protector=strongmode uses the same underlying heuristics as Clang's-fstack-protector-strong.These heuristics weren't designed for Rust, and may be over-conservative in some cases - for example, if
Rust stores a field's data in an alloca using an LLVM array type, LLVM regard the alloca as meaning
that the function has a C array, and enable stack overflow canaries even if the function accesses
the alloca in a safe way. Some people thought we should wait on stabilization until there are better
heuristics, but I didn't hear about any concrete case where this unduly harms performance, and I think
that when a need comes, we can improve the heuristics in LLVM after stabilization.
The heuristics do seem to not be under-conservative, so this should not be a security risk.
The
-Cstack-protector=basicmode (-fstack-protector) uses heuristics that are specifically designedto catch old-C-style string manipulation. This is not a good fit to Rust, which does not perform much
unsafe C-style string manipulation. As far as I can tell, nobody has been asking for it,
and few people are using it even in today's C - modern distros (e.g. Debian) tend to use
-fstack-protector-strong.Therefore,
-Cstack-protector=basichas been removed. If anyone is interested in it, theyare welcome to add it back as an unstable option.
Summarize the major parts of the implementation and provide links into the code (or to PRs)
Most implementation was done in #84197. The command-line
attribute enables the relevant LLVM attribute on all functions in
rust/compiler/rustc_codegen_llvm/src/attributes.rs
Lines 267 to 276 in 68baa87
Each target can indicate that it does not support stack canaries - currently,
the GPU platforms
nvptx64-nvidia-cudaandamdgcn-amd-amdhsa. On theseplatforms, use of
-Cstack-protectorcauses an error.Summarize existing test coverage of this feature
The feature has tests that make sure that the LLVM heuristic gives reasonable
results for several functions, by checking for
__security_check_cookie(on Windows)or
__stack_chk_fail(on Linux). Seehttps://github.com/rust-lang/rust/tree/68baa87ba6f03f8b6af2a368690161f1601e4040/tests/assembly-llvm/stack-protector
Has a call-for-testing period been conducted? If so, what feedback was received?
No call-for-testing has been conducted, but the feature seems to be in use.
What outstanding bugs in the issue tracker involve this feature? Are they stabilization-blocking?
No reported bugs seem to exist.
Summarize contributors to the feature by name for recognition and assuredness that people involved in the feature agree with stabilization
-Zstack-protectortest for Windows targets #116037-C stack-protector=all#121742thanks @nikic!
thanks @antoyo!
What FIXMEs are still in the code for that feature and why is it ok to leave them there?
No FIXMEs related to this feature.
What static checks are done that are needed to prevent undefined behavior?
This feature cannot cause undefined behavior.
In what way does this feature interact with the reference/specification, and are those edits prepared?
No changes to reference/spec, docs added to the codegen docs as part of the stabilization PR.
Does this feature introduce new expressions and can they produce temporaries? What are the lifetimes of those temporaries?
No.
What other unstable features may be exposed by this feature?
None.
What is tooling support like for this feature, w.r.t rustdoc, clippy, rust-analzyer, rustfmt, etc.?
No support needed for rustdoc, clippy, rust-analyzer, rustfmt or rustup.
Cargo could expose this as an option in build profiles but I would expect the decision as to what version should be used would
be made for the entire crate graph at build time rather than by individual package authors.
-C stack-protectoris propagated to C compilers using cc-rs via rust-lang/cc-rs#1550Fixes #114903
r? @wesleywiser (feel free to reassign)