-
-
Notifications
You must be signed in to change notification settings - Fork 15.4k
SGX UnsafeList is unsound, WaitQueue can execute UB #160603
Copy link
Copy link
Open
Labels
C-bugCategory: This is a bug.Category: This is a bug.I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}Issue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessO-SGXTarget: SGXTarget: SGXT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.This issue may need triage. Remove it if it has been sufficiently triaged.
Description
Metadata
Metadata
Assignees
Labels
C-bugCategory: This is a bug.Category: This is a bug.I-prioritizeIssue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}Issue needs a team member to assess the impact. Will be replaced by P-{low,medium,high,critical}I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessO-SGXTarget: SGXTarget: SGXT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.This issue may need triage. Remove it if it has been sufficiently triaged.
I was looking at this SGX code: https://github.com/rust-lang/rust/blob/0312931d8c0ba1a28268a12c06202b68cbc65f76/library/std/src/sys/pal/sgx/waitqueue/unsafe_list.rs
It's a linked-list implementation that freely mixes pointers and references, which is a recipe for disastrous UB. Indeed, simply pushing and popping an element executes UB, as detected by Miri even with Tree Borrows.
Here's a playground based on the SGX code which executes UB: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=2655d6852f717956f2555a6688dd86c2
Since
removetakes an exclusive/mutable reference, the fallback path ofWaitQueue::wait_timeoutcan execute UB as far as I can tell:rust/library/std/src/sys/pal/sgx/waitqueue/mod.rs
Line 180 in 0312931
(To be precise, creating the new mutable reference and passing it into a function invalidates any pointers to
entryalready in the list. Ifentrywas the first entry, that includesself.head_tail. Then,assert!(!self.is_empty())executes UB. Maybe I need to add an "unlessT: !Unpin" carve-out, not sure.)Solution
Two things: avoid taking exclusive/mutable references as inputs to the
UnsafeList, and exclusively use raw pointers in the linked list.SGX's
waitqueuecode pushes internally mutable types into the list, so taking mutable references to entries should be unnecessary. Shared references should work fine.Instead of creating mutable references for the sake of doing writes... just write using the raw pointers. Same for reads, don't create temporary references. Reference->pointer conversion should happen as soon as possible after taking an input, and pointer->reference conversion should happen as late possible just before returning an output.