-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes soundness bug 18510 by aborting on unwind from safe extern "C" functions only #64315
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
r? @RalfJung |
Still on vacation, sorry. |
This seems rather inadequate. We still don't properly insert the shims for all functions then, we in particular we do not do anything about mozjpeg and rlua being UB. |
I think I am of mixed mind about this change. It's a hack, but it does turn some UB into guaranteed abort which is nice, but it also doesn't really help to solve what I consider to be the main problem with the current unwind situation. So, I am not necessarily opposed to landing this if there is general support. But I do think that we should definitely keep #52652 open (so the "closes" line should be removed from the PR description). @gnzlbg assuming your goal here is to "agree on and fix what seems uncontroversial", there is also some other "low-hanging fruit" around unwind, I think? Such as #63883 and the fact that Also, this PR should come with a test (we already have a test for |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
I think your PR (#63909) fixes most of this other low-hanging fruit correctly. We should do that, maybe without the part that removes
Sure, done.
Well, that's on purpose. Right now the status quo is that we have a soundness bug open on safe Rust but we can't fix it because around 2 crates are relying on undefined behavior. Until now our strategy has been to block the soundness bug solution until we figure out which problems those crates actually need solving, word RFCs, merge them, implement them, and only after these features are stabilized and these crates migrated to use them, only then can we fix the soundness bug. This PR fixes the soundness bug without breaking nor fixing those crates. This allow us to close the soundness hole and to solve the problems these crate have without any time pressure nor need to come up with quick temporary features.
I've removed the "closes" but if we merge this we probably should rename / refocus that issue to reflect what remains to be done. I understood #52652 to be about safe Rust code being able to invoke undefined behavior which is what this PR fixes, but that issue has evolved into how to solve the problems these other crates have because that is believed to be a blocker for fixing the soundness hole.
This is kind off-topic but it has reminded me that this PR might actually trigger a different unrelated bug. First, AFAICT, rlua currently does not have any undefined behavior of this kind. How could it? It never "unwinds" as in panics or throws exceptions that require cleanup code. Instead, rlua only
Clang has a correctness bug in which trying to @kyren do the rlua bindings use any "safe" Does anyone has any idea about what is causing the build errors? |
@@ -491,6 +491,7 @@ fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: DefId, abi: Abi) -> bool { | |||
|
|||
// Validate `#[unwind]` syntax regardless of platform-specific panic strategy | |||
let attrs = &tcx.get_attrs(fn_def_id); | |||
let unsafety = &tcx.fn_sig(fn_def_id).skip_binder().unsafety.clone(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eddyb I don't know if this is the best way to do this. I'm not sure what the binder is for and just ended up playing type tetris here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If i am correct, the binder is the for<'a>
part of for<'a> fn(&'a ())
. This seems correct, as the safety of a function doesnt depend on lifetimes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just... call .unsafety()
? There should be a method for every component of ty::FnSig
, on the binder-wrapped version.
As @RalfJung mentioned in one of the other issues: I don't believe that we should make code generation depend on the presence or absence of This is also missing an explanation of the advantages of this proposal over |
Then your understanding widely differs from mine. I was not even aware of the soundness bug until you raised it, which was after this recent burst of activity on this issue started. |
You might be confusing this with the recently reported miscompilation due to the soundness bug, because the soundness bug was discovered at least in 2017, with the first attempted fix landing in December 2017, and people have been trying to fix it ever since. The first comment in the #52652 explains this, and developing new language features to allow programs to unwind through FFI has been discussed pretty much since the start, but it only became "time critical" on March 2019 when it was decided by T-Lang that a fix to the soundness bug shall break no crates.
This isn't a proposal over
It is unnecessary to assume that
It isn't clear whether we can avoid emitting nounwind yet as @alexcrichton raised here.
T-Lang agreed that the right fix for this is to both |
In other words, this PR implements the solution that @rust-lang/lang agreed is the right thing to do for Rust's safe |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
All of that discussion was about turning UB into a defined abort, and how that broke stuff, but AFAIK never was it mentioned that it is possible to cause this UB from safe code only. There was never a soundness bug until 14 days ago. |
See #52652 (comment) for a comment explaining that that bug is not a soundness bug in the usual sense of the word. Emphasis mine:
You are misreading history here.
T-lang agreed that the right fix is to do this for all |
That's the only reason #52652 is tagged with I-Unsound: extern "C" fn foo() { panic() } // Safe Rust invokes UB
That's just a miscompilation caused by that unsoundness.
See these comments refuting that comment, starting at this one: #52652 (comment) and the couple that follow showing UB in safe Rust. Particularly this comment: #52652 (comment) which shows the same UB that leads to the miscompilation I filled two weeks ago. |
Sure, as I mentioned, this PR implements the part of that required to fix the soundness hole, leaving the rest for later.
On stable Rust, there is no attribute, so it is unclear to me how this PR could replace that with anything. On nightly Rust, there is an attribute, but this PR does not replace it. |
Fair, I had missed that. (It's not "the first comment though" as you had claimed.) But #52652 was marked I-unsound before that already. It is not, primarily, a soundness bug. It primarily is about letting people write FFI code like mozjpeg does. The issue description does not even mention (un)soundness.
It's conceptually replacing it, as in, it is doing the same thing. |
It's linked in the first comment (in the original comment part, not the updated part at the top), which links to the PR that fixed this for the first time, where this was discussed, and the announcement of Rust 1.24.0 which mentions that we fix a case where you could invoke undefined behavior in safe Rust: https://blog.rust-lang.org/2018/02/15/Rust-1.24.html#other-good-stuff The reason that this issue was marked with I-Unsound initially is that the first and only report of this that one can find is the PR that actually fixed it for the first time. If there were any other issues filled before that, I can't find them. That PR was merged, stuff broke, reverted, and this issue was filled at some point after.. with I-Unsound, by somebody else that wasn't the PR author. I guess this is another reason to not use PRs as bug reports =/ (EDIT: #18510)
Right now, even if we stop emitting You might see fixing the safe function case as making the unsafe case the opt out of safety, but that's already the case. Sure, until a proper solution lands, this might make users that are invoking undefined behavior in safe Rust code change their code to "only" invoke undefined behavior in unsafe Rust code. Not a great improvement, but IMO an improvement nevertheless. That can be seen as an opt-out on stable, but there is no need to do that on nightly because one has |
No, absolutely all rust functions marked |
@gnzlbg I don't recall a distinction between safe and unsafe functions ever coming up in the language team discussions, and it certainly wasn't in the conclusion from the lang team meeting. The conclusion from the language team meeting is that the state we'd like to get to is a consistent one in which all functions (safe or unsafe) not marked as unwinding are both marked
Are you referring to the lack of specification for how Rust unwinding interacts with other languages? If so: RFC 2753 is trying to address that through some minimal additions of specification/definition. In the meantime, I personally am inclined to merge Ralf's PR at #63909 to fix potential miscompilation, and that was the lang team consensus as well, though I'm going to go confirm that again. With that PR merged, we shouldn't generate any further miscompilation. We would miss some optimization opportunities, but we can get those optimization opportunities back once we introduce This PR, on the other hand, introduces some additional semantics to |
I see. I was not aware the lang team talked about the soundness issue back then. Sorry for my misunderstandings here.
But here you are contradicting yourself... "The Rust language does not allow extern "C" functions to unwind", and hence there is no miscompilation in #63943 (after this PR lands, and replacing |
@RalfJung you are completely right: #63943 is not a miscompilation.
I consider the soundness bug and the ""miscompilation"" to be separate issues, but the actual reason I called #63943 a miscompilation is because this optimization ""breaks"" code that has undefined behavior. The lang team has set as a hard constraint that solutions to the soundness bug shall not break code that exhibits undefined behavior. I'm open to renaming the issue to something that clarifies that (e.g. "unsound optimization for unsound code" or something like that) since apparently this is the new normal. |
I feel that allowing |
I agree that we should fix this for all functions, and I also agree that having different code generation between safe and unsafe Rust functions is bad, but I also think that unnecessarily exposing safe Rust code to undefined behavior is way way worse than having slightly different codegen between safe and unsafe Rust functions. We make no guarantees about codegen, so I personally find the codegen argument very weak. In particular, because it is built on the assumption that people will just re-write their safe |
@BatmanAoD has helped me investigate the current situation, and just as a clarification since rlua keeps coming up in these issues, it appears rlua is not actually currently affected by the abort on unwind through extern "C" behavior at all! I was a bit unsure of the current state of things after the 1.24.1 reversion due to #48251, but it appears that since #48572 is merged that rlua no longer affected by rustc's unwind abort behavior. This was tested by running rlua tests on windows with the MSVC toolchain using the nightly compiler version 2019-09-20 97e58c0 and observing no failures due to improper aborts. @BatmanAoD informed me that this version of the compiler should contain the new unwind abort behavior. Sorry for the confusion, I wasn't quite sure of the full resolution following #48251 until now. |
That compiler does not abort when |
☔ The latest upstream changes (presumably #65388) made this pull request unmergeable. Please resolve the merge conflicts. |
from triaging, this PR has been idle for 1 month. Could the @rust-lang/lang team decide on this please? thanks! |
To refresh everyone's memory, there are three proposals, including this one, for fixing the soundness hole immediately:
As one of the co-shepherds of the project group, I don't know if the lang team expects or wants me to weigh in on the options listed above, but I do think that the decision cannot rely on the assumption that the opt-out mechanism mentioned above will be ready "soon". The project group does not currently have a design recommendation ready, nor any estimated timeline for delivering such a recommendation. I therefore think (speaking personally, not as a representative of the project group) that it is in the Rust project's best interest that one of the three approaches above be stabilized as soon as possible. |
@rfcbot fcp close I am going to move to close this proposal. I don't think there is much appetite to make unsafe semantically meaningful in this way. I think the main goal should be to produce a final decision on the semantics of the C ABI (and whether it should permit unwinding, or whether some alternate means should be added). We are working towards that goal -- the real question then becomes whether, in the meantime, we wish to remove the UB and -- if so -- how. I guess we can discuss that particular question in the Zulip, but it seems like most times that we have done so we've reached a sort of stalemate. I'm not sure yet what I think about it -- I guess I think I'd prefer to try to finish up the debate about our overall direction (which seems to me to be close to the point where we can make a call) than to spend energy debating the pros/cons here. |
Team member @nikomatsakis has proposed to close 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. |
@rfcbot reviewed |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Im fine with closing this, as long as there is a near term alternative in
the very near future for closing the soundness bug (eg another PR would
do). So as concern I’d like to raise out the issue: what’s the albternative?
AFAIK this PR closes the soundness bug and is compatible with all
alternatives I know of.
I also believe that it would be unfortunate to make the unsafe keyword have
an impact on code generation. But according to this PR, that would only be
temporary until the underlying issues are solved. Those issues do not have
an RFC right now, so AFAICT it might take a couple of years to solve them.
If that were the case, I’d prefer to close the soundness bug now with this
PR, and leave it up to future RFCs not re-open it.
|
Also, this is forward compatible with all soundness fixes to the soundness
bug. So I’d like to hear why should we leave a soundness bug open in safe
Rust when there is a patch to close such but without any kind of perf or
usability drawback for anybody.
What’s the value of leaving programmers using safe Rust code exposed to
undefined behavior when there is a way to protect them from UB?
This PR protects such programmers.
It’s IMO quite hard to argue that we should allow safe Rust to exhibit UB
for consistency with unsafe Rust code. The whole point of using safe Rust
is to not be exposed to UB in the first place.
|
The final comment period, with a disposition to close, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. |
This fixes the soundness bug #18510 from November 2014 which allows safe Rust code to invoke undefined behavior:
by implementing the behavior defined in the reference for all
extern "C"
functions, which is to abort when a panic! tries to unwind out of them, for safe extern "C" functions only.That is, unlike previous attempts at fixing this soundness hole, this PR does not make
unsafe extern "C"
functions abort, since that is not required for soundness, and has been shown to break a lot of code (see #52652 top comment for a brief history of the breakage).That is, after this PR, it is still possible to invoke undefined behavior by unwinding out of an
unsafe extern "C"
function like here:but doing so requires unsafe code, and is an implementation-bug, but not a soundness bug.
There is a PR open (#63909) that removes the
nounwind
attribute fromunsafe extern "C"
functions to try to prevent them from being optimized if they exhibit undefined behavior.Note: this PR only closes #18510, which has been closed and and then re-opened as #52652. It was pointed out, that a lot of people do not interpret #52652 to be about a soundness bug, even though the top comment points to 18510, and the first couple of comments in the issue clarify that. It was also pointed out that people would prefer to re-purpose #52652 for discussing future language features instead.