Compile libraries with cf-protection=branch on x64#156612
Conversation
The CET control-flow enforcement technology feature on x64 prevents control-flow hijacking via corrupted vtables and similar. It requires a special NOP at all entry points that are targeted by indirect branches/calls. For an executable to be protected, all object files linked into it have to have support. Until now, any rust object file would disable support for the entire executable. This adds the flag (if available) so that rust system libraries do not poison the protection when linked in. Note: This doesn't do anything for shadow stack support. The two features can be enabled separately, so it's valuable in itself. tracking issue: rust-lang#93754
|
cc @tgross35 |
|
r? @jieyouxu rustbot has assigned @jieyouxu. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
Perhaps @abrown is a better reviewer for this? |
|
V8 and LLVM have support for -fcf-protection=branch, which is a great security feature, and actually very simple. It merely bans indirect jumps to locations that are not marked with the ENDBR64 instruction (which is just a NOP if the feature is not enabled on your CPU). This prevents a whole class of program-counter hijacking attacks (ROP). However, currently you have to disable the parts of V8 written in rust for it to work, because the rust code pulls in artifacts that don't have the support (those NOP/ENDBR64 instructions at entry points). As more of V8 gets written in rust this problem is only going to get worse. Effectively, having part of your program written in rust means you can't get this performance-neutral defense-in-depth feature. I also work on Cloudflare Workers, which embed V8 and have the same problem. The LLVM support for cf-protection=branch is not considered experimental, but in rust the discussion (see linked bug) has been mostly about how to activate it. A flag is available in nightly, but currently doesn't work because of this issue. |
|
I fixed it so that it only changes the artifacts on the non-stable build, but not sure how to do the same for the change in build.rs. This is for the optimized builtins which are in C, so it's a flag for the C compiler. I could perhaps do something tricky with environment, unless you have a better idea? |
|
Can't you build std yourself with the unstable flag for now? If you have spare cycles to spend on improving the situation, it's probably better to work toward moving the relevant flags toward stabilization. That way once we have build-std, which is in progress, you'll be able to do what is needed from stable Rust. |
|
IIUC, the flag is entirely useless without build-std, so there would be no point in stabilizing it alone. |
|
I think it's still useful to indicate that the design work has been done and it's a flag that can be relied on. But it could also be made effectively stabilization-ready even if stabilization itself is blocked on build-std, 🤷♂️. |
|
I wouldn't be against stabilizing that flag (given the usual well-testedness and no-blocking-bugs) even if its effectively useless without build-std, as long as we are clear about that limitation on stabilization with intent to change the prebuilt dist artifacts to flip the default to w/ protection in the future. That would be a step that I would like to see so we have some stronger confidence in this flag's impl and behavior. Basically, IMO we should not and cannot be building and distributing artifacts built with this flag while its unstable. Feel free to discuss this further in https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler. @rustbot blocked (should not be building stable dist artifacts while this flag is still unstable) |
|
Reminder, once the PR becomes ready for a review, use |
The CET control-flow enforcement technology feature on x64 prevents control-flow hijacking via corrupted vtables and similar. It requires a special NOP at all entry points that are targeted by indirect branches/calls.
For an executable to be protected, all object files linked into it have to have support. Until now, any rust object file would disable support for the entire executable. This adds the flag (if available) so that rust system libraries do not poison the protection when linked in.
Note: This doesn't do anything for shadow stack support. The two features can be enabled separately, so it's valuable in itself.
tracking issue: #93754