Skip to content
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

Implement read_buf and vectored read/write for SGX stdio #137355

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

thaliaarchi
Copy link
Contributor

@thaliaarchi thaliaarchi commented Feb 21, 2025

Implement read_buf, read_vectored, and write_vectored for the SGX stdio types.

Additionally, extend User<T>::copy_to_enclave to work for copying to uninitialized values and fix unsoundness in UserRef<[T]>::copy_to_enclave_vec.

cc @jethrogb

Tracked in #136756

@rustbot
Copy link
Collaborator

rustbot commented Feb 21, 2025

r? @ChrisDenton

rustbot has assigned @ChrisDenton.
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

@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 Feb 21, 2025
@thaliaarchi
Copy link
Contributor Author

thaliaarchi commented Feb 25, 2025

@rustbot blocked (on #136780)

@rustbot rustbot added S-blocked Status: Blocked on something else such as an RFC or other implementation work. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 25, 2025
@jethrogb
Copy link
Contributor

cc @raoulstrackx

/// # Panics
/// This function panics if the destination doesn't have the same length as
/// the source.
pub fn copy_to_enclave_uninit(&self, dest: &mut [MaybeUninit<T>]) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Needing this “feels” wrong to me. You could do impl<T: UserSafeSized> UserSafeSized for MaybeUninit<T> and then just create a [MaybeUninit<u8>] in read_buf. However, of course the whole point of UserSafe is that you want to explicitly assume everything you copy out of userspace is initialized, so that would kind of defeat the point.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If both of those options are unsatisfying to you, what would you recommend I do so this can impl read_buf?

@jethrogb
Copy link
Contributor

jethrogb commented Feb 25, 2025

The versions of read and write in usercalls are vectored

This was explicitly requested by the T-libs reviewer.

@thaliaarchi
Copy link
Contributor Author

The versions of read and write in usercalls are vectored

This was explicitly requested by the T-libs reviewer.

I'm fine with reverting my change to this. Since new_from_enclave just defers to new_uninit_bytes and copy_from_enclave, which is what the vectored version uses, the only difference is saving a few arithmetic ops.

@thaliaarchi thaliaarchi force-pushed the io-optional-methods/sgx branch 2 times, most recently from b81e9d2 to 4cfdd68 Compare February 26, 2025 19:57
@thaliaarchi
Copy link
Contributor Author

I noticed that UserRef<[T]>::copy_to_enclave_vec reinterprets uninitialized memory as initialized and does not drop existing elements of the Vec, so I pushed a fix for it which uses the new copy_to_enclave_uninit. I think this supports the need for such a routine.

@jethrogb
Copy link
Contributor

Perhaps copy_to_enclave needs to be replaced in its entirety with your version?

@thaliaarchi
Copy link
Contributor Author

thaliaarchi commented Feb 27, 2025

Perhaps copy_to_enclave needs to be replaced in its entirety with your version?

I think the two would actually be better coexisting, since they serve slightly different purposes. copy_to_enclave copies from a UserRef<T> to a &mut T, whereas copy_to_enclave_uninit copies from a UserRef<[T]> to a &mut [MaybeUninit<T>]. Since MaybeUninit<T> requires T: Sized, a routine which copies from a UserRef<T> to a &mut MaybeUninit<T> wouldn't work for slices.

@jethrogb
Copy link
Contributor

jethrogb commented Feb 28, 2025

How about this?

// SAFETY: Requires that `T` is contained within `Self` using transparent representation
unsafe trait UserSafeCopyDestination<T: ?Sized> {
    fn as_mut_ptr(&mut self) -> *mut T;
}

unsafe impl<T> UserSafeCopyDestination<T> for T {
    fn as_mut_ptr(&mut self) -> *mut T {
        self as _
    }
}

unsafe impl<T> UserSafeCopyDestination<[T]> for [T] {
    fn as_mut_ptr(&mut self) -> *mut [T] {
        self as _
    }
}

unsafe impl<T> UserSafeCopyDestination<T> for MaybeUninit<T> {
    fn as_mut_ptr(&mut self) -> *mut T {
        self as *mut Self as _
    }
}

unsafe impl<T> UserSafeCopyDestination<[T]> for [MaybeUninit<T>] {
    fn as_mut_ptr(&mut self) -> *mut [T] {
        self as *mut Self as _
    }
}

impl<T: ?Sized> UserRef<T> {
    pub fn copy_to_enclave<V: ?Sized + UserSafeCopyDestination<T>>(&self, dest: &mut V) {
        unsafe {
            assert_eq!(mem::size_of_val(dest), mem::size_of_val(&*self.0.get()));
            copy_from_userspace(
                self.0.get() as *const T as *const u8,
                dest.as_mut_ptr() as *mut u8,
                mem::size_of_val(dest),
            );
        }
    }
}

@thaliaarchi thaliaarchi force-pushed the io-optional-methods/sgx branch from 4cfdd68 to da0fbf6 Compare March 1, 2025 02:55
@thaliaarchi
Copy link
Contributor Author

thaliaarchi commented Mar 1, 2025

That's much more flexible! I've added a commit with your patch, which I attributed to you. You might want to double-check that the metadata looks good.

(FYI, it looks like your fortanix.com email isn't connected to your GitHub account, so you're not linked.)

@thaliaarchi
Copy link
Contributor Author

thaliaarchi commented Mar 1, 2025

And since we've been talking about SGX copying APIs, I think UserRef<[T]>::copy_to_enclave_vec would be slightly better if it didn't clear existing elements and instead just appended. It's easy for the caller to .clear(), if they want, and this seems to better match other APIs that take a &mut Vec<T>.

That would be a breaking change, but I see no use of it outside of std.

@bors
Copy link
Contributor

bors commented Mar 7, 2025

☔ The latest upstream changes (presumably #138155) made this pull request unmergeable. Please resolve the merge conflicts.

@thaliaarchi thaliaarchi force-pushed the io-optional-methods/sgx branch from da0fbf6 to 0ec7397 Compare March 7, 2025 18:39
Jethro Beekman and others added 2 commits March 10, 2025 00:45
@thaliaarchi thaliaarchi force-pushed the io-optional-methods/sgx branch from 0ec7397 to d34c289 Compare March 10, 2025 07:50
@thaliaarchi
Copy link
Contributor Author

Now that #136780 has merged, we're good to go!

@rustbot review

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-blocked Status: Blocked on something else such as an RFC or other implementation work. labels Mar 10, 2025
@jethrogb
Copy link
Contributor

And since we've been talking about SGX copying APIs, I think UserRef<[T]>::copy_to_enclave_vec would be slightly better if it didn't clear existing elements and instead just appended. It's easy for the caller to .clear(), if they want, and this seems to better match other APIs that take a &mut Vec.

Good idea. But then let's also change the name to better describe the behavior.

@thaliaarchi thaliaarchi force-pushed the io-optional-methods/sgx branch from d34c289 to e80df9c Compare March 10, 2025 18:49
@thaliaarchi
Copy link
Contributor Author

I've now done so and renamed it to append_to_enclave_vec.

@ChrisDenton
Copy link
Member

r=me if @jethrogb is happy with this PR.

@jethrogb
Copy link
Contributor

@ChrisDenton yes please approve

@ChrisDenton
Copy link
Member

Thanks!

@bors r+

@bors
Copy link
Contributor

bors commented Mar 11, 2025

📌 Commit e80df9c has been approved by ChrisDenton

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 11, 2025
It reinterprets uninitialized memory as initialized and does not drop
existing elements of the Vec. Fix that.

Additionally, make it more general by appending, instead of overwriting
existing elements, and rename it to `append_to_enclave_vec`. A caller
can simply call `.clear()` before, for the old behavior.
@thaliaarchi thaliaarchi force-pushed the io-optional-methods/sgx branch from e80df9c to c62aa0b Compare March 12, 2025 03:19
@thaliaarchi
Copy link
Contributor Author

I had neglected to update the set_len for the append-style logic. I've pushed a fix for that (so it needs a reapproval).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
O-SGX Target: SGX S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. 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.

5 participants