-
-
Notifications
You must be signed in to change notification settings - Fork 804
kernel/process_{standard,loading}: don't create &mut ref to app memory #4714
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
base: master
Are you sure you want to change the base?
kernel/process_{standard,loading}: don't create &mut ref to app memory #4714
Conversation
This changes `ProcessStandard::create` and its users in process loading to operate on app memory referenced by a raw slice pointer, instead of a unique (mutable) Rust reference. Currently, during process loading, Tock creates and stores Rust multiple shared and unique Rust references pointing into process memory. This is dangerous, for multiple reasons: first, the pointee may not be properly initialized memory, violating a basic Rust invariant [1]. Furthermore, the memory may be concurrently accessed and modified by the process, either directly (in the case of write-acessible RAM), or indirectly through system calls to a flash controller. We should avoid creating Rust references into process memory, except for rare, carefully reasoned about cases. This includes the process buffer infrastructure, to give capsules ephemeral access to select regions in process memory, and the kernel's grant region. Even if we would only use Rust reference _during_ process loading, and only on memory that was previously initialized, this is still hard to reason about. For instance, we would have to ensure that no process runs after all processes have been loaded, and all Rust references to process memory have gone out of scope. Additions like dynamic process loading make establishing and reasoning about these guarantees difficult. Instead, using raw slice pointers (`*mut [u8]`) is a more obviously safer choice, onto which Rust places much fewer safety requirements.
8a32455 to
15c17a9
Compare
This changes PR #4714 to avoid `as` casting pointers. Instead, this uses methods to perform the casts (mostly `cast` and `addr`), which IMO makes it easier to understand what the code is doing. This also changes `ProcessStandard::create` to derive the provenance of pointers from `remaining_memory` rather than picking it up from an exposed provenance. I *think* this is a bugfix.
Remove pointer `as` casts from PR #4714.
Also reported upstream as rust-lang/rust#150995.
| let load_result = load_process( | ||
| self.kernel, | ||
| self.chip, | ||
| process_binary, | ||
| self.app_memory.take(), | ||
| self.app_memory.get(), | ||
| short_app_id, | ||
| index, | ||
| self.fault_policy, | ||
| self.storage_policy, | ||
| ); |
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.
Why this change? Semantically, we are passing ownership of the remaining app memory to the load process function and then getting back the updated memory region when the function returns.
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.
Because *mut [u8] cannot not implement Default (it's missing pointer metadata) whereas &'static mut [u8] does (where the default value is an empty slice).
app_memory is a Cell<>, not an OptionalCell<> or TakeCell<>. I agree that what we're doing conceptually is taking and then replacing, but what the previous code did with take() is immediately replace app_memory with the empty slice. Which is probably actually not what we wanted to do.
I can change this to an OptionalCell if you prefer, and then restore the .take() semantics?
| return Err((ProcessLoadError::NotEnoughMemory, remaining_memory)); | ||
| } | ||
| }; | ||
|
|
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.
restore
Pull Request Overview
This changes
ProcessStandard::createand its users in process loading to operate on app memory referenced by a raw slice pointer, instead of a unique (mutable) Rust reference.Currently, during process loading, Tock creates and stores Rust multiple shared and unique Rust references pointing into process memory. This is dangerous, for multiple reasons: first, the pointee may not be properly initialized memory, violating a basic Rust invariant [1]. Furthermore, the memory may be concurrently accessed and modified by the process, either directly (in the case of write-acessible RAM), or indirectly through system calls to a flash controller.
We should avoid creating Rust references into process memory, except for rare, carefully reasoned about cases. This includes the process buffer infrastructure, to give capsules ephemeral access to select regions in process memory, and the kernel's grant region.
Even if we would only use Rust references during process loading, and only on memory that was previously initialized, this is still hard to reason about. For instance, we would have to ensure that no process runs after all processes have been loaded, and all Rust references to process memory have gone out of scope. Additions like dynamic process loading make establishing and reasoning about these guarantees difficult. Instead, using raw slice pointers (
*mut [u8]) is a more obviously safer choice, onto which Rust places much fewer safety requirements.Testing Strategy
Compiling and careful review?
TODO or Help Wanted
N/A
Documentation Updated
Updated the relevant files inno updates are required./docs, orFormatting
make prepush.