Skip to content

Fix unsoundness issues in std::sys::pal::sgx::waitqueue::unsafe_list - #160641

Closed
jethrogb wants to merge 1 commit into
rust-lang:mainfrom
jethrogb:fix-sgx-unsafe-list
Closed

Fix unsoundness issues in std::sys::pal::sgx::waitqueue::unsafe_list#160641
jethrogb wants to merge 1 commit into
rust-lang:mainfrom
jethrogb:fix-sgx-unsafe-list

Conversation

@jethrogb

@jethrogb jethrogb commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
  • I did not use an LLM to create a change in this PR.
  • I used an LLM to create a change in this PR, and I have explained below how it was used.

Replace invalid uses of references in std::sys::pal::sgx::waitqueue::unsafe_list internals with raw pointers. I tried to keep the code structure the same as much as possible, this required adding interior mutability to be able to keep the ”public” API the same, since it passes mutable references to things that may be accessed concurrently in other threads (the linked list entry).

In addition to the use of references flagged in the original issue, it turns out the head/tail (raw) pointer stored in the linked list caused provenance issues in miri. Added a mechanism to always use the current receiver's provenance for that pointer.

This PR was developed with Claude Fable 5 through extensive interactive use, where I directed a detailed plan for making the changes needed for this fix. My input includes keeping the structure the same and the new internal abstraction for dealing with raw pointers. I'm not familiar with miri, I used Claude to test the changes with miri and didn't verify the test setup. It said the test suite was failing before the changes (both stacked borrows and tree borrows) but passing after. The head/tail pointer provenance issue was found with Claude. I thoroughly reviewed all the code, including comments, and made manual changes/deletions where necessary/appropriate. The PR description was written by me.

Fixes #114581 (maybe?)
Fixes #160603

@rustbot rustbot added O-SGX Target: SGX S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Aug 6, 2026
@rustbot

rustbot commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

r? @nia-e

rustbot has assigned @nia-e.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 13 candidates
  • Random selection from JohnTitor, Mark-Simulacrum, clarfonthey, nia-e

@rust-log-analyzer

This comment has been minimized.

@nia-e

This comment was marked as resolved.

@rustbot rustbot assigned JohnTitor and unassigned nia-e Aug 6, 2026
@jethrogb
jethrogb force-pushed the fix-sgx-unsafe-list branch from 129fea0 to 599d150 Compare August 6, 2026 14:16
/// The caller must make sure to synchronize ending the borrow of the
/// return value and deallocation of the containing entry.
pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> {
unsafe { self.init() };

@jethrogb jethrogb Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wasn't needed in the original code either - this function does nothing if is_empty and is_empty doesn't require init to have run.

View changes since the review

/// currently in `self`. That should be the case for any pointer that is
/// currently stored in the list.
unsafe fn launder(&mut self, ptr: EntryPtr<T>) -> DerefPtr<'_, T> {
let ptr = if ptr.addr() == self.head_tail { EntryPtr::from(self.head_tail()) } else { ptr };

@jethrogb jethrogb Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is rather unfortunate. It should optimize to a no-op, but it doesn't.

This is what Claude says about it:

The LLVM IR shows why it can't go to zero: each launder becomes select i1 (icmp eq ptr %loaded, %derived), ptr %derived, ptr %loaded where %derived is a GEP off the &mut self argument. Both arms have the same address under the condition, but they are distinct pointer values with different provenance, and LLVM deliberately refuses to substitute one pointer for another based on icmp eq ptr (doing so is exactly the class of provenance-breaking miscompile LLVM has been tightening up). So the select survives as a cmov, or, where only the address ends up mattering, folds but strands its dead cmp. This cost is inherent to any conditional re-derivation approach — the compare must exist in the IR, and the optimizer is not allowed to prove the arms equal.

View changes since the review

@robofinch

Copy link
Copy Markdown

Replace invalid uses of references in std::sys::pal::sgx::waitqueue::unsafe_list internals with raw pointers. I tried to keep the code structure the same as much as possible, this required adding interior mutability to be able to keep the ”public” API the same, since it passes mutable references to things that may be accessed concurrently in other threads (the linked list entry).

I don't think that public API accepting mutable references is correct.... the caller would need to use UnsafePinned or whatever to disable &mut noalias, which can be avoided by just accepting & references to entries as input.

I don't have time right now to look closer at the code.

@joboet

joboet commented Aug 6, 2026

Copy link
Copy Markdown
Member

This PR was developed with Claude Fable 5 through extensive interactive use, where I directed a detailed plan for making the changes needed for this fix. My input includes keeping the structure the same and the new internal abstraction for dealing with raw pointers. [...] I thoroughly reviewed all the code, including comments, and made manual changes/deletions where necessary/appropriate. The PR description was written by me.

Thank you for your honesty! However, under our very newly adopted LLM policy, you need to pre-arrange reviews for LLM-assisted PRs before opening a PR – and soundness-critical fixes (I think this one qualifies) are entirely disallowed. I'll close this PR until you have found such a reviewer (try asking in #t-libs on Zulip) or rewritten the PR manually.

I'm not familiar with miri, I used Claude to test the changes with miri and didn't verify the test setup. It said the test suite was failing before the changes (both stacked borrows and tree borrows) but passing after.

I highly doubt that claim as miri cannot currently test the SGX target. Please review the test setup manually.

In general, I think you could avoid a lot of the complication here by just using an UnsafePinned wrapper around the dummy node to make the aliasing sound.

@joboet joboet closed this Aug 6, 2026
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 6, 2026
@jethrogb

jethrogb commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

rewritten the PR manually

Good luck with that. I don't think I can improve upon this code.

Please review the test setup manually.

Can you provide any miri reference that I can look at?

I don't think that public API accepting mutable references is correct....

Why not? All aliasing is done through interior mutability. Please review the (pre-existing) safety comments on UnsafeList::{push, pop, remove}. The new aliasing comment at the top of the file describes everything in more detail.

In general, I think you could avoid a lot of the complication here by just using an UnsafePinned wrapper around the dummy node to make the aliasing sound.

It's possible to write this code with less safe abstractions and more use of unsafe. But that would be counterproductive. The abstractions here have been designed to exactly cover what's needed while avoiding the full flexibility that directly using raw pointers everywhere would have. This greatly reduces the cognitive load for the reviewer and the chances of new bugs.

@theemathas

theemathas commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

For advice to how to proceed, please open a new thread in the #llm-mentoring channel on zulip. Thank you.

Edit: Oh, you already posted at #t-libs > Code review

@hanna-kruppe hanna-kruppe added the llm-assisted An LLM-assisted PR as defined by the LLM policy. Requires ahead-of-time consent by assignee. label Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llm-assisted An LLM-assisted PR as defined by the LLM policy. Requires ahead-of-time consent by assignee. O-SGX Target: SGX T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SGX UnsafeList is unsound, WaitQueue can execute UB Miri violation in std/src/sys/sgx/waitqueue/unsafe_list.rs

9 participants