kernel/processbuffer.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Data structures for passing application memory to the kernel.
6//!
7//! A Tock process can pass read-write or read-only buffers into the
8//! kernel for it to use. The kernel checks that read-write buffers
9//! exist within a process's RAM address space, and that read-only
10//! buffers exist either within its RAM or flash address space. These
11//! buffers are shared with the allow_read_write() and
12//! allow_read_only() system calls.
13//!
14//! A read-write and read-only call is mapped to the high-level Rust
15//! types [`ReadWriteProcessBuffer`] and [`ReadOnlyProcessBuffer`]
16//! respectively. The memory regions can be accessed through the
17//! [`ReadableProcessBuffer`] and [`WriteableProcessBuffer`] traits,
18//! implemented on the process buffer structs.
19//!
20//! Each access to the buffer structs requires a liveness check to ensure that
21//! the process memory is still valid. For a more traditional interface, users
22//! can convert buffers into [`ReadableProcessSlice`] or
23//! [`WriteableProcessSlice`] and use these for the lifetime of their
24//! operations. Users cannot hold live-lived references to these slices,
25//! however.
26
27use core::cell::Cell;
28use core::marker::PhantomData;
29use core::ops::{Deref, Index, Range, RangeFrom, RangeTo};
30
31use crate::ErrorCode;
32use crate::capabilities;
33use crate::process::{self, ProcessId};
34
35/// Convert a process buffer's internal pointer+length representation to a
36/// [`ReadableProcessSlice`].
37///
38/// This function will automatically convert zero-length process buffers into
39/// valid zero-sized Rust slices, regardless of the value of `ptr` (i.e., `ptr`
40/// is allowed to be null for these slices).
41///
42/// # Safety
43///
44/// In the case of `len != 0`, the memory `[ptr; ptr + len)` must be assigned to
45/// one or more processes, and `ptr` must be nonzero. This memory region must be
46/// mapped as _readable_, and optionally _writable_. It must remain a valid,
47/// readable allocation assigned to one or more processes for the entire
48/// lifetime `'a`, and must not be used as backing memory for any Rust
49/// allocations (apart from other process slices).
50///
51/// Callers must ensure that, for its lifetime `'a`, no other programs (other
52/// than this Tock kernel instance) modify the memory behind a
53/// [`ReadableProcessSlice`]. This includes userspace programs, which must not
54/// run in parallel to the Tock kernel holding a process slice reference, or
55/// other Tock kernel instances executing in parallel.
56///
57/// It is sound for multiple (partially) aliased [`ReadableProcessSlice`]s or
58/// [`WriteableProcessSlice`]s to be in scope at the same time, as they use
59/// interior mutability, and their memory is not accessed in parallel by
60/// userspace or other programs running concurrently.
61unsafe fn raw_processbuf_to_roprocessslice<'a>(
62 ptr: *const u8,
63 len: usize,
64) -> &'a ReadableProcessSlice {
65 let ptr: *const ReadableProcessByte = ptr.cast();
66
67 // Transmute a slice reference over readable (read-only or read-write, and
68 // potentially aliased) bytes into a `ReadableProcessSlice` reference.
69 //
70 // SAFETY: This is sound, as `ReadableProcessSlice` is merely a
71 // `#[repr(transparent)]` wrapper around `[ReadableProcessByte]`. However,
72 // we cannot build this struct safely from an intermediate
73 // `[ReadableProcessByte]` slice reference, as we cannot dereference this
74 // unsized type.
75 unsafe {
76 core::mem::transmute::<&[ReadableProcessByte], &ReadableProcessSlice>(
77 // Create a slice of `ReadableProcessByte`s from the supplied
78 // pointer. `ReadableProcessByte` itself permits interior mutability,
79 // and hence this intermediate reference is safe to construct given the
80 // safety contract of this function.
81 //
82 // Rust has very strict requirements on pointer validity[1] which also
83 // in part apply to accesses of length 0. We allow an application to
84 // supply arbitrary pointers if the buffer length is 0, but this is not
85 // allowed for Rust slices. For instance, a null pointer is _never_
86 // valid, not even for accesses of size zero.
87 //
88 // To get a pointer which does not point to valid (allocated) memory,
89 // but is safe to construct for accesses of size zero, we must call
90 // NonNull::dangling(). The resulting pointer is guaranteed to be
91 // well-aligned and uphold the guarantees required for accesses of size
92 // zero.
93 //
94 // [1]: https://doc.rust-lang.org/core/ptr/index.html#safety
95 match len {
96 0 => core::slice::from_raw_parts(
97 core::ptr::NonNull::<ReadableProcessByte>::dangling().as_ptr(),
98 0,
99 ),
100 _ => core::slice::from_raw_parts(ptr, len),
101 },
102 )
103 }
104}
105
106/// Convert a process buffer's internal pointer+length representation to a
107/// [`WriteableProcessSlice`].
108///
109/// This function will automatically convert zero-length process buffers into
110/// valid zero-sized Rust slices, regardless of the value of `ptr` (i.e., `ptr`
111/// is allowed to be null for these slices).
112///
113/// # Safety
114///
115/// In the case of `len != 0`, the memory `[ptr; ptr + len)` must be assigned to
116/// one or more processes, and `ptr` must be nonzero. This memory region must be
117/// mapped as _readable_ and _writable_. It must remain a valid, readable and
118/// writeable allocation assigned to one or more processes for the entire
119/// lifetime `'a`, and must not be used as backing memory for any Rust
120/// allocations (apart from other process slices).
121///
122/// Callers must ensure that, for its lifetime `'a`, no other programs (other
123/// than this Tock kernel instance) modify the memory behind a
124/// [`ReadableProcessSlice`]. This includes userspace programs, which must not
125/// run in parallel to the Tock kernel holding a process slice reference, or
126/// other Tock kernel instances executing in parallel.
127///
128/// It is sound for multiple (partially) aliased [`ReadableProcessSlice`]s or
129/// [`WriteableProcessSlice`]s to be in scope at the same time, as they use
130/// interior mutability, and their memory is not accessed in parallel by
131/// userspace or other programs running concurrently.
132unsafe fn raw_processbuf_to_rwprocessslice<'a>(
133 ptr: *mut u8,
134 len: usize,
135) -> &'a WriteableProcessSlice {
136 // Transmute a slice reference over writeable and potentially aliased bytes
137 // into a `WriteableProcessSlice` reference.
138 //
139 // SAFETY: This is sound, as `WriteableProcessSlice` is merely a
140 // `#[repr(transparent)]` wrapper around `[Cell<u8>]`. However, we cannot
141 // build this struct safely from an intermediate `[WriteableProcessByte]`
142 // slice reference, as we cannot dereference this unsized type.
143 unsafe {
144 core::mem::transmute::<&[Cell<u8>], &WriteableProcessSlice>(
145 // Create a slice of `Cell<u8>`s from the supplied pointer. `Cell<u8>`
146 // itself permits interior mutability, and hence this intermediate
147 // reference is safe to construct given the safety contract of this
148 // function.
149 //
150 // Rust has very strict requirements on pointer validity[1] which also
151 // in part apply to accesses of length 0. We allow an application to
152 // supply arbitrary pointers if the buffer length is 0, but this is not
153 // allowed for Rust slices. For instance, a null pointer is _never_
154 // valid, not even for accesses of size zero.
155 //
156 // To get a pointer which does not point to valid (allocated) memory,
157 // but is safe to construct for accesses of size zero, we must call
158 // NonNull::dangling(). The resulting pointer is guaranteed to be
159 // well-aligned and uphold the guarantees required for accesses of size
160 // zero.
161 //
162 // [1]: https://doc.rust-lang.org/core/ptr/index.html#safety
163 match len {
164 0 => core::slice::from_raw_parts(
165 core::ptr::NonNull::<Cell<u8>>::dangling().as_ptr(),
166 0,
167 ),
168 _ => core::slice::from_raw_parts(ptr as *const Cell<u8>, len),
169 },
170 )
171 }
172}
173
174/// A readable region of userspace process memory.
175///
176/// This trait can be used to gain read-only access to memory regions
177/// wrapped in either a [`ReadOnlyProcessBuffer`] or a
178/// [`ReadWriteProcessBuffer`] type.
179///
180/// # Safety
181///
182/// This is an `unsafe trait` as users of this trait need to trust that the
183/// implementation of [`ReadableProcessBuffer::ptr`] is correct. Implementors of
184/// this trait must ensure that the [`ReadableProcessBuffer::ptr`] method
185/// follows the semantics and invariants described in its documentation.
186pub unsafe trait ReadableProcessBuffer {
187 /// Length of the memory region.
188 ///
189 /// If the process is no longer alive and the memory has been
190 /// reclaimed, this method must return 0.
191 ///
192 /// # Default Process Buffer
193 ///
194 /// A default instance of a process buffer must return 0.
195 fn len(&self) -> usize;
196
197 /// Pointer to the first byte of the userspace-allowed memory region.
198 ///
199 /// If [`ReadableProcessBuffer::len`] returns a non-zero value,
200 /// then this method is guaranteed to return a pointer to the
201 /// start address of a memory region (of length returned by
202 /// `len`), allowable by a userspace process, and allowed to the
203 /// kernel for read operations. The memory region must not be
204 /// written to through this pointer.
205 ///
206 /// If the length of the initially shared memory region
207 /// (irrespective of the return value of
208 /// [`len`](ReadableProcessBuffer::len)) is 0, this function
209 /// returns a pointer to address `0x0`. This is because processes
210 /// may allow zero-length buffer to share no memory with the
211 /// kernel. Because these buffers have zero length, they may have
212 /// any arbitrary pointer value. However, these "dummy addresses"
213 /// should not be leaked, so this method returns 0 for zero-length
214 /// slices. Care must be taken to not create a Rust (slice)
215 /// reference over a null-pointer, as that is undefined behavior.
216 ///
217 /// Users of this pointer must not produce any mutable aliasing, such as by
218 /// creating a reference from this pointer concurrently with calling
219 /// [`WriteableProcessBuffer::mut_enter`].
220 ///
221 /// # Default Process Buffer
222 ///
223 /// A default instance of a process buffer must return a pointer
224 /// to address `0x0`.
225 fn ptr(&self) -> *const u8;
226
227 /// Applies a function to the (read only) process slice reference
228 /// pointed to by the process buffer.
229 ///
230 /// If the process is no longer alive and the memory has been
231 /// reclaimed, this method must return
232 /// `Err(process::Error::NoSuchApp)`.
233 ///
234 /// # Default Process Buffer
235 ///
236 /// A default instance of a process buffer must return
237 /// `Err(process::Error::NoSuchApp)` without executing the passed
238 /// closure.
239 fn enter<F, R>(&self, fun: F) -> Result<R, process::Error>
240 where
241 F: FnOnce(&ReadableProcessSlice) -> R;
242}
243
244/// A readable and writeable region of userspace process memory.
245///
246/// This trait can be used to gain read-write access to memory regions
247/// wrapped in a [`ReadWriteProcessBuffer`].
248///
249/// This is a supertrait of [`ReadableProcessBuffer`], which features
250/// methods allowing mutable access.
251///
252/// # Safety
253///
254/// This is an `unsafe trait` as users of this trait need to trust that the
255/// implementation of [`WriteableProcessBuffer::mut_ptr`] is
256/// correct.
257///
258/// Implementors of this trait must ensure that the
259/// [`WriteableProcessBuffer::mut_ptr`] method follows the semantics and
260/// invariants described in its documentation, and that the length of the
261/// [`WriteableProcessBuffer`] is identical to the value returned by the
262/// [`ReadableProcessBuffer::len`] supertrait method.
263///
264/// Additionally, when using the default implementation of `mut_ptr` provided by
265/// this trait, implementors guarantee that the readable pointer returned by
266/// [`ReadableProcessBuffer::ptr`] points to the same read-write allowed shared
267/// memory region as described by the [`WriteableProcessBuffer`], and that
268/// writes through the pointer returned by [`ReadableProcessBuffer::ptr`] are
269/// sound for [`ReadableProcessBuffer::len`] bytes, notwithstanding any aliasing
270/// requirements.
271pub unsafe trait WriteableProcessBuffer: ReadableProcessBuffer {
272 /// Pointer to the first byte of the userspace-allowed memory region.
273 ///
274 /// If [`ReadableProcessBuffer::len`] returns a non-zero value,
275 /// then this method is guaranteed to return a pointer to the
276 /// start address of a memory region (of length returned by
277 /// `len`), allowable by a userspace process, and allowed to the
278 /// kernel for read or write operations.
279 ///
280 /// If the length of the initially shared memory region
281 /// (irrespective of the return value of
282 /// [`len`](ReadableProcessBuffer::len)) is 0, this function
283 /// returns a pointer to address `0x0`. This is because processes
284 /// may allow zero-length buffer to share no memory with the
285 /// kernel. Because these buffers have zero length, they may have
286 /// any arbitrary pointer value. However, these "dummy addresses"
287 /// should not be leaked, so this method returns 0 for zero-length
288 /// slices. Care must be taken to not create a Rust (slice)
289 /// reference over a null-pointer, as that is undefined behavior.
290 ///
291 /// Users of this pointer must not produce any mutable aliasing, such as by
292 /// creating a reference from this pointer concurrently with calling
293 /// [`WriteableProcessBuffer::mut_enter`].
294 ///
295 /// # Default Process Buffer
296 ///
297 /// A default instance of a process buffer must return a pointer
298 /// to address `0x0`.
299 fn mut_ptr(&self) -> *mut u8 {
300 ReadableProcessBuffer::ptr(self).cast_mut()
301 }
302
303 /// Applies a function to the mutable process slice reference
304 /// pointed to by the [`ReadWriteProcessBuffer`].
305 ///
306 /// If the process is no longer alive and the memory has been
307 /// reclaimed, this method must return
308 /// `Err(process::Error::NoSuchApp)`.
309 ///
310 /// # Default Process Buffer
311 ///
312 /// A default instance of a process buffer must return
313 /// `Err(process::Error::NoSuchApp)` without executing the passed
314 /// closure.
315 fn mut_enter<F, R>(&self, fun: F) -> Result<R, process::Error>
316 where
317 F: FnOnce(&WriteableProcessSlice) -> R;
318}
319
320/// Read-only buffer shared by a userspace process.
321///
322/// This struct is provided to capsules when a process `allow`s a
323/// particular section of its memory to the kernel and gives the
324/// kernel read access to this memory.
325///
326/// It can be used to obtain a [`ReadableProcessSlice`], which is
327/// based around a slice of [`Cell`]s. This is because a userspace can
328/// `allow` overlapping sections of memory into different
329/// [`ReadableProcessSlice`]. Having at least one mutable Rust slice
330/// along with read-only slices to overlapping memory in Rust violates
331/// Rust's aliasing rules. A slice of [`Cell`]s avoids this issue by
332/// explicitly supporting interior mutability. Still, a memory barrier
333/// prior to switching to userspace is required, as the compiler is
334/// free to reorder reads and writes, even through [`Cell`]s.
335pub struct ReadOnlyProcessBuffer {
336 ptr: *const u8,
337 len: usize,
338 process_id: Option<ProcessId>,
339}
340
341impl ReadOnlyProcessBuffer {
342 /// Construct a new [`ReadOnlyProcessBuffer`] over a given pointer and
343 /// length.
344 ///
345 /// # Safety
346 ///
347 /// Refer to the safety requirements of
348 /// [`ReadOnlyProcessBuffer::new_external`].
349 pub(crate) unsafe fn new(ptr: *const u8, len: usize, process_id: ProcessId) -> Self {
350 ReadOnlyProcessBuffer {
351 ptr,
352 len,
353 process_id: Some(process_id),
354 }
355 }
356
357 /// Construct a new [`ReadOnlyProcessBuffer`] over a given pointer
358 /// and length.
359 ///
360 /// Publicly accessible constructor, which requires the
361 /// [`capabilities::ExternalProcessCapability`] capability. This
362 /// is provided to allow implementations of the
363 /// [`Process`](crate::process::Process) trait outside of the
364 /// `kernel` crate.
365 ///
366 /// # Safety
367 ///
368 /// If the length is `0`, an arbitrary pointer may be passed into
369 /// `ptr`. It does not necessarily have to point to allocated
370 /// memory, nor does it have to meet [Rust's pointer validity
371 /// requirements](https://doc.rust-lang.org/core/ptr/index.html#safety).
372 /// [`ReadOnlyProcessBuffer`] must ensure that all Rust slices
373 /// with a length of `0` must be constructed over a valid (but not
374 /// necessarily allocated) base pointer.
375 ///
376 /// If the length is not `0`, the memory region of `[ptr; ptr +
377 /// len)` must be valid memory of the process of the given
378 /// [`ProcessId`]. It must be allocated and and accessible over
379 /// the entire lifetime of the [`ReadOnlyProcessBuffer`]. It must
380 /// not point to memory outside of the process' accessible memory
381 /// range, or point (in part) to other processes or kernel
382 /// memory. The `ptr` must meet [Rust's requirements for pointer
383 /// validity](https://doc.rust-lang.org/core/ptr/index.html#safety),
384 /// in particular it must have a minimum alignment of
385 /// `core::mem::align_of::<u8>()` on the respective platform. It
386 /// must point to memory mapped as _readable_ and optionally
387 /// _writable_ and _executable_.
388 pub unsafe fn new_external(
389 ptr: *const u8,
390 len: usize,
391 process_id: ProcessId,
392 _cap: &dyn capabilities::ExternalProcessCapability,
393 ) -> Self {
394 // SAFETY: See function description.
395 unsafe { Self::new(ptr, len, process_id) }
396 }
397
398 /// Consumes the ReadOnlyProcessBuffer, returning its constituent
399 /// pointer and size. This ensures that there cannot
400 /// simultaneously be both a `ReadOnlyProcessBuffer` and a pointer
401 /// to its internal data.
402 ///
403 /// `consume` can be used when the kernel needs to pass the
404 /// underlying values across the kernel-to-user boundary (e.g., in
405 /// return values to system calls).
406 pub(crate) fn consume(self) -> (*const u8, usize) {
407 (self.ptr, self.len)
408 }
409}
410
411// SAFETY: This implementation must be correct. The implementation of `ptr()`
412// ensures that a null pointer is returned if `len()` is 0, and a pointer to the
413// allowed buffer otherwise.
414unsafe impl ReadableProcessBuffer for ReadOnlyProcessBuffer {
415 /// Return the length of the buffer in bytes.
416 fn len(&self) -> usize {
417 self.process_id
418 .map_or(0, |pid| pid.kernel.process_map_or(0, pid, |_| self.len))
419 }
420
421 /// Return the pointer to the start of the buffer.
422 fn ptr(&self) -> *const u8 {
423 if self.len == 0 {
424 core::ptr::null::<u8>()
425 } else {
426 self.ptr
427 }
428 }
429
430 /// Access the contents of the buffer in a closure.
431 ///
432 /// This verifies the process is still valid before accessing the underlying
433 /// memory.
434 fn enter<F, R>(&self, fun: F) -> Result<R, process::Error>
435 where
436 F: FnOnce(&ReadableProcessSlice) -> R,
437 {
438 match self.process_id {
439 None => Err(process::Error::NoSuchApp),
440 Some(pid) => pid
441 .kernel
442 .process_map_or(Err(process::Error::NoSuchApp), pid, |_| {
443 // SAFETY: `kernel.process_map_or()` validates that
444 // the process still exists and its memory is still
445 // valid. In particular, `Process` tracks the "high water
446 // mark" of memory that the process has `allow`ed to the
447 // kernel. Because `Process` does not feature an API to
448 // move the "high water mark" down again, which would be
449 // called once a `ProcessBuffer` has been passed back into
450 // the kernel, a given `Process` implementation must assume
451 // that the memory described by a once-allowed
452 // `ProcessBuffer` is still in use, and thus will not
453 // permit the process to free any memory after it has
454 // been `allow`ed to the kernel once. This guarantees
455 // that the buffer is safe to convert into a slice
456 // here. For more information, refer to the
457 // comment and subsequent discussion on tock/tock#2632:
458 // https://github.com/tock/tock/pull/2632#issuecomment-869974365
459 Ok(fun(unsafe {
460 raw_processbuf_to_roprocessslice(self.ptr, self.len)
461 }))
462 }),
463 }
464 }
465}
466
467impl Default for ReadOnlyProcessBuffer {
468 fn default() -> Self {
469 ReadOnlyProcessBuffer {
470 ptr: core::ptr::null_mut::<u8>(),
471 len: 0,
472 process_id: None,
473 }
474 }
475}
476
477/// Provides access to a [`ReadOnlyProcessBuffer`] with a restricted lifetime.
478/// This automatically dereferences into a ReadOnlyProcessBuffer
479pub struct ReadOnlyProcessBufferRef<'a> {
480 buf: ReadOnlyProcessBuffer,
481 _phantom: PhantomData<&'a ()>,
482}
483
484impl ReadOnlyProcessBufferRef<'_> {
485 /// Construct a new [`ReadOnlyProcessBufferRef`] over a given pointer and
486 /// length with a lifetime derived from the caller.
487 ///
488 /// # Safety
489 ///
490 /// Refer to the safety requirements of
491 /// [`ReadOnlyProcessBuffer::new_external`]. The derived lifetime can
492 /// help enforce the invariant that this incoming pointer may only
493 /// be access for a certain duration.
494 pub(crate) unsafe fn new(ptr: *const u8, len: usize, process_id: ProcessId) -> Self {
495 // SAFETY: See function description.
496 unsafe {
497 Self {
498 buf: ReadOnlyProcessBuffer::new(ptr, len, process_id),
499 _phantom: PhantomData,
500 }
501 }
502 }
503}
504
505impl Deref for ReadOnlyProcessBufferRef<'_> {
506 type Target = ReadOnlyProcessBuffer;
507 fn deref(&self) -> &Self::Target {
508 &self.buf
509 }
510}
511
512/// Read-writable buffer shared by a userspace process.
513///
514/// This struct is provided to capsules when a process `allows` a
515/// particular section of its memory to the kernel and gives the
516/// kernel read and write access to this memory.
517///
518/// It can be used to obtain a [`WriteableProcessSlice`], which is
519/// based around a slice of [`Cell`]s. This is because a userspace can
520/// `allow` overlapping sections of memory into different
521/// [`WriteableProcessSlice`]. Having at least one mutable Rust slice
522/// along with read-only or other mutable slices to overlapping memory
523/// in Rust violates Rust's aliasing rules. A slice of [`Cell`]s
524/// avoids this issue by explicitly supporting interior
525/// mutability. Still, a memory barrier prior to switching to
526/// userspace is required, as the compiler is free to reorder reads
527/// and writes, even through [`Cell`]s.
528pub struct ReadWriteProcessBuffer {
529 ptr: *mut u8,
530 len: usize,
531 process_id: Option<ProcessId>,
532}
533
534impl ReadWriteProcessBuffer {
535 /// Construct a new [`ReadWriteProcessBuffer`] over a given
536 /// pointer and length.
537 ///
538 /// # Safety
539 ///
540 /// Refer to the safety requirements of
541 /// [`ReadWriteProcessBuffer::new_external`].
542 pub(crate) unsafe fn new(ptr: *mut u8, len: usize, process_id: ProcessId) -> Self {
543 ReadWriteProcessBuffer {
544 ptr,
545 len,
546 process_id: Some(process_id),
547 }
548 }
549
550 /// Construct a new [`ReadWriteProcessBuffer`] over a given
551 /// pointer and length.
552 ///
553 /// Publicly accessible constructor, which requires the
554 /// [`capabilities::ExternalProcessCapability`] capability. This
555 /// is provided to allow implementations of the
556 /// [`Process`](crate::process::Process) trait outside of the
557 /// `kernel` crate.
558 ///
559 /// # Safety
560 ///
561 /// If the length is `0`, an arbitrary pointer may be passed into
562 /// `ptr`. It does not necessarily have to point to allocated
563 /// memory, nor does it have to meet [Rust's pointer validity
564 /// requirements](https://doc.rust-lang.org/core/ptr/index.html#safety).
565 /// [`ReadWriteProcessBuffer`] must ensure that all Rust slices
566 /// with a length of `0` must be constructed over a valid (but not
567 /// necessarily allocated) base pointer.
568 ///
569 /// If the length is not `0`, the memory region of `[ptr; ptr +
570 /// len)` must be valid memory of the process of the given
571 /// [`ProcessId`]. It must be allocated and and accessible over
572 /// the entire lifetime of the [`ReadWriteProcessBuffer`]. It must
573 /// not point to memory outside of the process' accessible memory
574 /// range, or point (in part) to other processes or kernel
575 /// memory. The `ptr` must meet [Rust's requirements for pointer
576 /// validity](https://doc.rust-lang.org/core/ptr/index.html#safety),
577 /// in particular it must have a minimum alignment of
578 /// `core::mem::align_of::<u8>()` on the respective platform. It
579 /// must point to memory mapped as _readable_ and optionally
580 /// _writable_ and _executable_.
581 pub unsafe fn new_external(
582 ptr: *mut u8,
583 len: usize,
584 process_id: ProcessId,
585 _cap: &dyn capabilities::ExternalProcessCapability,
586 ) -> Self {
587 // SAFETY: See function description.
588 unsafe { Self::new(ptr, len, process_id) }
589 }
590
591 /// Consumes the ReadWriteProcessBuffer, returning its constituent
592 /// pointer and size. This ensures that there cannot
593 /// simultaneously be both a `ReadWriteProcessBuffer` and a pointer to
594 /// its internal data.
595 ///
596 /// `consume` can be used when the kernel needs to pass the
597 /// underlying values across the kernel-to-user boundary (e.g., in
598 /// return values to system calls).
599 pub(crate) fn consume(self) -> (*mut u8, usize) {
600 (self.ptr, self.len)
601 }
602
603 /// This is a `const` version of `Default::default` with the same
604 /// semantics.
605 ///
606 /// Having a const initializer allows initializing a fixed-size
607 /// array with default values without the struct being marked
608 /// `Copy` as such:
609 ///
610 /// ```
611 /// use kernel::processbuffer::ReadWriteProcessBuffer;
612 /// const DEFAULT_RWPROCBUF_VAL: ReadWriteProcessBuffer
613 /// = ReadWriteProcessBuffer::const_default();
614 /// let my_array = [DEFAULT_RWPROCBUF_VAL; 12];
615 /// ```
616 pub const fn const_default() -> Self {
617 Self {
618 ptr: core::ptr::null_mut::<u8>(),
619 len: 0,
620 process_id: None,
621 }
622 }
623}
624
625// SAFETY: This implementation must be correct. The implementation of `ptr()`
626// ensures that a null pointer is returned if `len()` is 0, and a pointer to the
627// allowed buffer otherwise.
628unsafe impl ReadableProcessBuffer for ReadWriteProcessBuffer {
629 /// Return the length of the buffer in bytes.
630 fn len(&self) -> usize {
631 self.process_id
632 .map_or(0, |pid| pid.kernel.process_map_or(0, pid, |_| self.len))
633 }
634
635 /// Return the pointer to the start of the buffer.
636 fn ptr(&self) -> *const u8 {
637 if self.len == 0 {
638 core::ptr::null::<u8>()
639 } else {
640 self.ptr
641 }
642 }
643
644 /// Access the contents of the buffer in a closure.
645 ///
646 /// This verifies the process is still valid before accessing the underlying
647 /// memory.
648 fn enter<F, R>(&self, fun: F) -> Result<R, process::Error>
649 where
650 F: FnOnce(&ReadableProcessSlice) -> R,
651 {
652 match self.process_id {
653 None => Err(process::Error::NoSuchApp),
654 Some(pid) => pid
655 .kernel
656 .process_map_or(Err(process::Error::NoSuchApp), pid, |_| {
657 // SAFETY: `kernel.process_map_or()` validates that
658 // the process still exists and its memory is still
659 // valid. In particular, `Process` tracks the "high water
660 // mark" of memory that the process has `allow`ed to the
661 // kernel. Because `Process` does not feature an API to
662 // move the "high water mark" down again, which would be
663 // called once a `ProcessBuffer` has been passed back into
664 // the kernel, a given `Process` implementation must assume
665 // that the memory described by a once-allowed
666 // `ProcessBuffer` is still in use, and thus will not
667 // permit the process to free any memory after it has
668 // been `allow`ed to the kernel once. This guarantees
669 // that the buffer is safe to convert into a slice
670 // here. For more information, refer to the
671 // comment and subsequent discussion on tock/tock#2632:
672 // https://github.com/tock/tock/pull/2632#issuecomment-869974365
673 let ro_process_slice =
674 unsafe { raw_processbuf_to_roprocessslice(self.ptr, self.len) };
675 Ok(fun(ro_process_slice))
676 }),
677 }
678 }
679}
680
681// SAFETY: This implementation must be correct. We rely on the default
682// implementation and the correctness of the `ReadableProcessBuffer`
683// implementation.
684unsafe impl WriteableProcessBuffer for ReadWriteProcessBuffer {
685 fn mut_enter<F, R>(&self, fun: F) -> Result<R, process::Error>
686 where
687 F: FnOnce(&WriteableProcessSlice) -> R,
688 {
689 match self.process_id {
690 None => Err(process::Error::NoSuchApp),
691 Some(pid) => pid
692 .kernel
693 .process_map_or(Err(process::Error::NoSuchApp), pid, |_| {
694 // SAFETY: `kernel.process_map_or()` validates that
695 // the process still exists and its memory is still
696 // valid. In particular, `Process` tracks the "high water
697 // mark" of memory that the process has `allow`ed to the
698 // kernel. Because `Process` does not feature an API to
699 // move the "high water mark" down again, which would be
700 // called once a `ProcessBuffer` has been passed back into
701 // the kernel, a given `Process` implementation must assume
702 // that the memory described by a once-allowed
703 // `ProcessBuffer` is still in use, and thus will not
704 // permit the process to free any memory after it has
705 // been `allow`ed to the kernel once. This guarantees
706 // that the buffer is safe to convert into a slice
707 // here. For more information, refer to the
708 // comment and subsequent discussion on tock/tock#2632:
709 // https://github.com/tock/tock/pull/2632#issuecomment-869974365
710 let rw_process_slice =
711 unsafe { raw_processbuf_to_rwprocessslice(self.ptr, self.len) };
712 Ok(fun(rw_process_slice))
713 }),
714 }
715 }
716}
717
718impl Default for ReadWriteProcessBuffer {
719 fn default() -> Self {
720 Self::const_default()
721 }
722}
723
724/// Provides access to a [`ReadWriteProcessBuffer`] with a restricted lifetime.
725/// This automatically dereferences into a ReadWriteProcessBuffer
726pub struct ReadWriteProcessBufferRef<'a> {
727 buf: ReadWriteProcessBuffer,
728 _phantom: PhantomData<&'a ()>,
729}
730
731impl ReadWriteProcessBufferRef<'_> {
732 /// Construct a new [`ReadWriteProcessBufferRef`] over a given pointer and
733 /// length with a lifetime derived from the caller.
734 ///
735 /// # Safety
736 ///
737 /// Refer to the safety requirements of
738 /// [`ReadWriteProcessBuffer::new_external`]. The derived lifetime can
739 /// help enforce the invariant that this incoming pointer may only
740 /// be access for a certain duration.
741 pub(crate) unsafe fn new(ptr: *mut u8, len: usize, process_id: ProcessId) -> Self {
742 // SAFETY: See function description.
743 unsafe {
744 Self {
745 buf: ReadWriteProcessBuffer::new(ptr, len, process_id),
746 _phantom: PhantomData,
747 }
748 }
749 }
750}
751
752impl Deref for ReadWriteProcessBufferRef<'_> {
753 type Target = ReadWriteProcessBuffer;
754 fn deref(&self) -> &Self::Target {
755 &self.buf
756 }
757}
758
759/// A shareable region of userspace memory.
760///
761/// This trait can be used to gain read-write access to memory regions
762/// wrapped in a ProcessBuffer type.
763// We currently don't need any special functionality in the kernel for this
764// type so we alias it as `ReadWriteProcessBuffer`.
765pub type UserspaceReadableProcessBuffer = ReadWriteProcessBuffer;
766
767/// Equivalent of the Rust core library's
768/// [`SliceIndex`](core::slice::SliceIndex) type for process slices.
769///
770/// This helper trait is used to abstract over indexing operators into
771/// process slices, and is used to "overload" the `.get()` methods
772/// such that it can be called with multiple different indexing
773/// operators.
774///
775/// While we can use the core library's `SliceIndex` trait, parameterized over
776/// our own `ProcessSlice` types, this trait includes mandatory methods that are
777/// undesirable for the process buffer infrastructure, such as unchecked or
778/// mutable index operations. Furthermore, implementing it requires the
779/// `slice_index_methods` nightly feature. Thus we vendor our own, small variant
780/// of this trait.
781pub trait ProcessSliceIndex<PB: ?Sized>: private_process_slice_index::Sealed {
782 type Output: ?Sized;
783 fn get(self, slice: &PB) -> Option<&Self::Output>;
784 fn index(self, slice: &PB) -> &Self::Output;
785}
786
787// Analog to `private_slice_index` from
788// https://github.com/rust-lang/rust/blob/a1eceec00b2684f947481696ae2322e20d59db60/library/core/src/slice/index.rs#L149
789mod private_process_slice_index {
790 use core::ops::{Range, RangeFrom, RangeTo};
791
792 pub trait Sealed {}
793
794 impl Sealed for usize {}
795 impl Sealed for Range<usize> {}
796 impl Sealed for RangeFrom<usize> {}
797 impl Sealed for RangeTo<usize> {}
798}
799
800/// Read-only wrapper around a [`Cell`]
801///
802/// This type is used in providing the [`ReadableProcessSlice`]. The
803/// memory over which a [`ReadableProcessSlice`] exists must never be
804/// written to by the kernel. However, it may either exist in flash
805/// (read-only memory) or RAM (read-writeable memory). Consequently, a
806/// process may `allow` memory overlapping with a
807/// [`ReadOnlyProcessBuffer`] also simultaneously through a
808/// [`ReadWriteProcessBuffer`]. Hence, the kernel can have two
809/// references to the same memory, where one can lead to mutation of
810/// the memory contents. Therefore, the kernel must use [`Cell`]s
811/// around the bytes shared with userspace, to avoid violating Rust's
812/// aliasing rules.
813///
814/// This read-only wrapper around a [`Cell`] only exposes methods
815/// which are safe to call on a process-shared read-only `allow`
816/// memory.
817#[repr(transparent)]
818pub struct ReadableProcessByte {
819 cell: Cell<u8>,
820}
821
822impl ReadableProcessByte {
823 #[inline]
824 pub fn get(&self) -> u8 {
825 self.cell.get()
826 }
827}
828
829/// Readable and accessible slice of memory of a process buffer.
830///
831///
832/// The only way to obtain this struct is through a
833/// [`ReadWriteProcessBuffer`] or [`ReadOnlyProcessBuffer`].
834///
835/// Slices provide a more convenient, traditional interface to process
836/// memory. These slices are transient, as the underlying buffer must
837/// be checked each time a slice is created. This is usually enforced
838/// by the anonymous lifetime defined by the creation of the slice.
839#[repr(transparent)]
840pub struct ReadableProcessSlice {
841 slice: [ReadableProcessByte],
842}
843
844fn cast_byte_slice_to_process_slice(byte_slice: &[ReadableProcessByte]) -> &ReadableProcessSlice {
845 // SAFETY: As ReadableProcessSlice is a transparent wrapper around its inner type,
846 // [ReadableProcessByte], we can safely transmute a reference to the inner
847 // type as a reference to the outer type with the same lifetime.
848 unsafe { core::mem::transmute::<&[ReadableProcessByte], &ReadableProcessSlice>(byte_slice) }
849}
850
851// Allow a u8 slice to be viewed as a ReadableProcessSlice to allow client code
852// to be authored once and accept either [u8] or ReadableProcessSlice.
853impl<'a> From<&'a [u8]> for &'a ReadableProcessSlice {
854 fn from(val: &'a [u8]) -> Self {
855 // SAFETY: The layout of a [u8] and ReadableProcessSlice are guaranteed to be
856 // the same. This also extends the lifetime of the buffer, so aliasing
857 // rules are thus maintained properly.
858 unsafe { core::mem::transmute(val) }
859 }
860}
861
862// Allow a mutable u8 slice to be viewed as a ReadableProcessSlice to allow
863// client code to be authored once and accept either [u8] or
864// ReadableProcessSlice.
865impl<'a> From<&'a mut [u8]> for &'a ReadableProcessSlice {
866 fn from(val: &'a mut [u8]) -> Self {
867 // SAFETY: The layout of a [u8] and ReadableProcessSlice are guaranteed to be
868 // the same. This also extends the mutable lifetime of the buffer, so
869 // aliasing rules are thus maintained properly.
870 unsafe { core::mem::transmute(val) }
871 }
872}
873
874impl ReadableProcessSlice {
875 /// Copy the contents of a [`ReadableProcessSlice`] into a mutable
876 /// slice reference.
877 ///
878 /// The length of `self` must be the same as `dest`. Subslicing
879 /// can be used to obtain a slice of matching length.
880 ///
881 /// # Panics
882 ///
883 /// This function will panic if `self.len() != dest.len()`.
884 pub fn copy_to_slice(&self, dest: &mut [u8]) {
885 // The panic code path was put into a cold function to not
886 // bloat the call site.
887 #[inline(never)]
888 #[cold]
889 #[track_caller]
890 fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! {
891 panic!(
892 "source slice length ({}) does not match destination slice length ({})",
893 src_len, dst_len,
894 );
895 }
896
897 if self.copy_to_slice_or_err(dest).is_err() {
898 len_mismatch_fail(dest.len(), self.len());
899 }
900 }
901
902 /// Copy the contents of a [`ReadableProcessSlice`] into a mutable
903 /// slice reference.
904 ///
905 /// The length of `self` must be the same as `dest`. Subslicing
906 /// can be used to obtain a slice of matching length.
907 pub fn copy_to_slice_or_err(&self, dest: &mut [u8]) -> Result<(), ErrorCode> {
908 // Method implemetation adopted from the
909 // core::slice::copy_from_slice method implementation:
910 // https://doc.rust-lang.org/src/core/slice/mod.rs.html#3034-3036
911
912 if self.len() != dest.len() {
913 Err(ErrorCode::SIZE)
914 } else {
915 // _If_ this turns out to not be efficiently optimized, it
916 // should be possible to use a ptr::copy_nonoverlapping here
917 // given we have exclusive mutable access to the destination
918 // slice which will never be in process memory, and the layout
919 // of &[ReadableProcessByte] is guaranteed to be compatible to
920 // &[u8].
921 for (i, b) in self.slice.iter().enumerate() {
922 dest[i] = b.get();
923 }
924 Ok(())
925 }
926 }
927
928 /// Return the length of the slice in bytes.
929 pub fn len(&self) -> usize {
930 self.slice.len()
931 }
932
933 /// Return an iterator over the bytes of the slice.
934 pub fn iter(&self) -> core::slice::Iter<'_, ReadableProcessByte> {
935 self.slice.iter()
936 }
937
938 /// Iterate the slice in chunks.
939 pub fn chunks(
940 &self,
941 chunk_size: usize,
942 ) -> impl core::iter::Iterator<Item = &ReadableProcessSlice> {
943 self.slice
944 .chunks(chunk_size)
945 .map(cast_byte_slice_to_process_slice)
946 }
947
948 /// Access a portion of the slice with bounds checking. If the access is not
949 /// within the slice then `None` is returned.
950 pub fn get<I: ProcessSliceIndex<Self>>(
951 &self,
952 index: I,
953 ) -> Option<&<I as ProcessSliceIndex<Self>>::Output> {
954 index.get(self)
955 }
956
957 /// Access a portion of the slice with bounds checking. If the access is not
958 /// within the slice then `None` is returned.
959 #[deprecated(note = "Use ReadableProcessSlice::get instead", since = "2.2.0")]
960 pub fn get_from(&self, range: RangeFrom<usize>) -> Option<&ReadableProcessSlice> {
961 range.get(self)
962 }
963
964 /// Access a portion of the slice with bounds checking. If the access is not
965 /// within the slice then `None` is returned.
966 #[deprecated(note = "Use ReadableProcessSlice::get instead", since = "2.2.0")]
967 pub fn get_to(&self, range: RangeTo<usize>) -> Option<&ReadableProcessSlice> {
968 range.get(self)
969 }
970}
971
972impl ProcessSliceIndex<ReadableProcessSlice> for usize {
973 type Output = ReadableProcessByte;
974
975 fn get(self, slice: &ReadableProcessSlice) -> Option<&Self::Output> {
976 slice.slice.get(self)
977 }
978
979 fn index(self, slice: &ReadableProcessSlice) -> &Self::Output {
980 &slice.slice[self]
981 }
982}
983
984impl ProcessSliceIndex<ReadableProcessSlice> for Range<usize> {
985 type Output = ReadableProcessSlice;
986
987 fn get(self, slice: &ReadableProcessSlice) -> Option<&Self::Output> {
988 slice.slice.get(self).map(cast_byte_slice_to_process_slice)
989 }
990
991 fn index(self, slice: &ReadableProcessSlice) -> &Self::Output {
992 cast_byte_slice_to_process_slice(&slice.slice[self])
993 }
994}
995
996impl ProcessSliceIndex<ReadableProcessSlice> for RangeFrom<usize> {
997 type Output = ReadableProcessSlice;
998
999 fn get(self, slice: &ReadableProcessSlice) -> Option<&Self::Output> {
1000 slice.slice.get(self).map(cast_byte_slice_to_process_slice)
1001 }
1002
1003 fn index(self, slice: &ReadableProcessSlice) -> &Self::Output {
1004 cast_byte_slice_to_process_slice(&slice.slice[self])
1005 }
1006}
1007
1008impl ProcessSliceIndex<ReadableProcessSlice> for RangeTo<usize> {
1009 type Output = ReadableProcessSlice;
1010
1011 fn get(self, slice: &ReadableProcessSlice) -> Option<&Self::Output> {
1012 slice.slice.get(self).map(cast_byte_slice_to_process_slice)
1013 }
1014
1015 fn index(self, slice: &ReadableProcessSlice) -> &Self::Output {
1016 cast_byte_slice_to_process_slice(&slice.slice[self])
1017 }
1018}
1019
1020impl<I: ProcessSliceIndex<Self>> Index<I> for ReadableProcessSlice {
1021 type Output = I::Output;
1022
1023 fn index(&self, index: I) -> &Self::Output {
1024 index.index(self)
1025 }
1026}
1027
1028/// Read-writeable and accessible slice of memory of a process buffer
1029///
1030/// The only way to obtain this struct is through a
1031/// [`ReadWriteProcessBuffer`].
1032///
1033/// Slices provide a more convenient, traditional interface to process
1034/// memory. These slices are transient, as the underlying buffer must
1035/// be checked each time a slice is created. This is usually enforced
1036/// by the anonymous lifetime defined by the creation of the slice.
1037#[repr(transparent)]
1038pub struct WriteableProcessSlice {
1039 slice: [Cell<u8>],
1040}
1041
1042fn cast_cell_slice_to_process_slice(cell_slice: &[Cell<u8>]) -> &WriteableProcessSlice {
1043 // SAFETY: As WriteableProcessSlice is a transparent wrapper around its inner type,
1044 // [Cell<u8>], we can safely transmute a reference to the inner type as the
1045 // outer type with the same lifetime.
1046 unsafe { core::mem::transmute(cell_slice) }
1047}
1048
1049// Allow a mutable u8 slice to be viewed as a WritableProcessSlice to allow
1050// client code to be authored once and accept either [u8] or
1051// WriteableProcessSlice.
1052impl<'a> From<&'a mut [u8]> for &'a WriteableProcessSlice {
1053 fn from(val: &'a mut [u8]) -> Self {
1054 // SAFETY: The layout of a [u8] and WriteableProcessSlice are guaranteed to be
1055 // the same. This also extends the mutable lifetime of the buffer, so
1056 // aliasing rules are thus maintained properly.
1057 unsafe { core::mem::transmute(val) }
1058 }
1059}
1060
1061impl WriteableProcessSlice {
1062 /// Copy the contents of a [`WriteableProcessSlice`] into a mutable
1063 /// slice reference.
1064 ///
1065 /// The length of `self` must be the same as `dest`. Subslicing
1066 /// can be used to obtain a slice of matching length.
1067 ///
1068 /// # Panics
1069 ///
1070 /// This function will panic if `self.len() != dest.len()`.
1071 pub fn copy_to_slice(&self, dest: &mut [u8]) {
1072 // The panic code path was put into a cold function to not
1073 // bloat the call site.
1074 #[inline(never)]
1075 #[cold]
1076 #[track_caller]
1077 fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! {
1078 panic!(
1079 "source slice length ({}) does not match destination slice length ({})",
1080 src_len, dst_len,
1081 );
1082 }
1083
1084 if self.copy_to_slice_or_err(dest).is_err() {
1085 len_mismatch_fail(dest.len(), self.len());
1086 }
1087 }
1088
1089 /// Copy the contents of a [`WriteableProcessSlice`] into a mutable
1090 /// slice reference.
1091 ///
1092 /// The length of `self` must be the same as `dest`. Subslicing
1093 /// can be used to obtain a slice of matching length.
1094 pub fn copy_to_slice_or_err(&self, dest: &mut [u8]) -> Result<(), ErrorCode> {
1095 // Method implemetation adopted from the
1096 // core::slice::copy_from_slice method implementation:
1097 // https://doc.rust-lang.org/src/core/slice/mod.rs.html#3034-3036
1098
1099 if self.len() != dest.len() {
1100 Err(ErrorCode::SIZE)
1101 } else {
1102 // _If_ this turns out to not be efficiently optimized, it
1103 // should be possible to use a ptr::copy_nonoverlapping here
1104 // given we have exclusive mutable access to the destination
1105 // slice which will never be in process memory, and the layout
1106 // of &[Cell<u8>] is guaranteed to be compatible to &[u8].
1107 self.slice
1108 .iter()
1109 .zip(dest.iter_mut())
1110 .for_each(|(src, dst)| *dst = src.get());
1111 Ok(())
1112 }
1113 }
1114
1115 /// Copy the contents of a slice of bytes into a [`WriteableProcessSlice`].
1116 ///
1117 /// The length of `src` must be the same as `self`. Subslicing can
1118 /// be used to obtain a slice of matching length.
1119 ///
1120 /// # Panics
1121 ///
1122 /// This function will panic if `src.len() != self.len()`.
1123 pub fn copy_from_slice(&self, src: &[u8]) {
1124 // Method implemetation adopted from the
1125 // core::slice::copy_from_slice method implementation:
1126 // https://doc.rust-lang.org/src/core/slice/mod.rs.html#3034-3036
1127
1128 // The panic code path was put into a cold function to not
1129 // bloat the call site.
1130 #[inline(never)]
1131 #[cold]
1132 #[track_caller]
1133 fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! {
1134 panic!(
1135 "src slice len ({}) != dest slice len ({})",
1136 src_len, dst_len,
1137 );
1138 }
1139
1140 if self.copy_from_slice_or_err(src).is_err() {
1141 len_mismatch_fail(self.len(), src.len());
1142 }
1143 }
1144
1145 /// Copy the contents of a slice of bytes into a [`WriteableProcessSlice`].
1146 ///
1147 /// The length of `src` must be the same as `self`. Subslicing can
1148 /// be used to obtain a slice of matching length.
1149 pub fn copy_from_slice_or_err(&self, src: &[u8]) -> Result<(), ErrorCode> {
1150 // Method implemetation adopted from the
1151 // core::slice::copy_from_slice method implementation:
1152 // https://doc.rust-lang.org/src/core/slice/mod.rs.html#3034-3036
1153
1154 if self.len() != src.len() {
1155 Err(ErrorCode::SIZE)
1156 } else {
1157 // _If_ this turns out to not be efficiently optimized, it
1158 // should be possible to use a ptr::copy_nonoverlapping here
1159 // given we have exclusive mutable access to the destination
1160 // slice which will never be in process memory, and the layout
1161 // of &[Cell<u8>] is guaranteed to be compatible to &[u8].
1162 src.iter()
1163 .zip(self.slice.iter())
1164 .for_each(|(src, dst)| dst.set(*src));
1165 Ok(())
1166 }
1167 }
1168
1169 /// Return the length of the slice in bytes.
1170 pub fn len(&self) -> usize {
1171 self.slice.len()
1172 }
1173
1174 /// Return an iterator over the slice.
1175 pub fn iter(&self) -> core::slice::Iter<'_, Cell<u8>> {
1176 self.slice.iter()
1177 }
1178
1179 /// Iterate over the slice in chunks.
1180 pub fn chunks(
1181 &self,
1182 chunk_size: usize,
1183 ) -> impl core::iter::Iterator<Item = &WriteableProcessSlice> {
1184 self.slice
1185 .chunks(chunk_size)
1186 .map(cast_cell_slice_to_process_slice)
1187 }
1188
1189 /// Access a portion of the slice with bounds checking. If the access is not
1190 /// within the slice then `None` is returned.
1191 pub fn get<I: ProcessSliceIndex<Self>>(
1192 &self,
1193 index: I,
1194 ) -> Option<&<I as ProcessSliceIndex<Self>>::Output> {
1195 index.get(self)
1196 }
1197
1198 /// Access a portion of the slice with bounds checking. If the access is not
1199 /// within the slice then `None` is returned.
1200 #[deprecated(note = "Use WriteableProcessSlice::get instead", since = "2.2.0")]
1201 pub fn get_from(&self, range: RangeFrom<usize>) -> Option<&WriteableProcessSlice> {
1202 range.get(self)
1203 }
1204
1205 /// Access a portion of the slice with bounds checking. If the access is not
1206 /// within the slice then `None` is returned.
1207 #[deprecated(note = "Use WriteableProcessSlice::get instead", since = "2.2.0")]
1208 pub fn get_to(&self, range: RangeTo<usize>) -> Option<&WriteableProcessSlice> {
1209 range.get(self)
1210 }
1211}
1212
1213impl ProcessSliceIndex<WriteableProcessSlice> for usize {
1214 type Output = Cell<u8>;
1215
1216 fn get(self, slice: &WriteableProcessSlice) -> Option<&Self::Output> {
1217 slice.slice.get(self)
1218 }
1219
1220 fn index(self, slice: &WriteableProcessSlice) -> &Self::Output {
1221 &slice.slice[self]
1222 }
1223}
1224
1225impl ProcessSliceIndex<WriteableProcessSlice> for Range<usize> {
1226 type Output = WriteableProcessSlice;
1227
1228 fn get(self, slice: &WriteableProcessSlice) -> Option<&Self::Output> {
1229 slice.slice.get(self).map(cast_cell_slice_to_process_slice)
1230 }
1231
1232 fn index(self, slice: &WriteableProcessSlice) -> &Self::Output {
1233 cast_cell_slice_to_process_slice(&slice.slice[self])
1234 }
1235}
1236
1237impl ProcessSliceIndex<WriteableProcessSlice> for RangeFrom<usize> {
1238 type Output = WriteableProcessSlice;
1239
1240 fn get(self, slice: &WriteableProcessSlice) -> Option<&Self::Output> {
1241 slice.slice.get(self).map(cast_cell_slice_to_process_slice)
1242 }
1243
1244 fn index(self, slice: &WriteableProcessSlice) -> &Self::Output {
1245 cast_cell_slice_to_process_slice(&slice.slice[self])
1246 }
1247}
1248
1249impl ProcessSliceIndex<WriteableProcessSlice> for RangeTo<usize> {
1250 type Output = WriteableProcessSlice;
1251
1252 fn get(self, slice: &WriteableProcessSlice) -> Option<&Self::Output> {
1253 slice.slice.get(self).map(cast_cell_slice_to_process_slice)
1254 }
1255
1256 fn index(self, slice: &WriteableProcessSlice) -> &Self::Output {
1257 cast_cell_slice_to_process_slice(&slice.slice[self])
1258 }
1259}
1260
1261impl<I: ProcessSliceIndex<Self>> Index<I> for WriteableProcessSlice {
1262 type Output = I::Output;
1263
1264 fn index(&self, index: I) -> &Self::Output {
1265 index.index(self)
1266 }
1267}
1268
1269#[cfg(test)]
1270mod miri_tests {
1271 use super::*;
1272 use core::cell::UnsafeCell;
1273
1274 // Helper to get a raw mutable pointer to the backing memory we use to
1275 // create process slices over. This backing memory, though allocated by
1276 // Rust, contains only `UnsafeCell`s and thus is suitable for creating
1277 // process slice references over.
1278 fn get_backing_memory_ptr<const N: usize>(mem: &[UnsafeCell<u8>; N]) -> *mut u8 {
1279 mem as *const _ as *mut u8
1280 }
1281
1282 #[test]
1283 fn test_basic_read_write() {
1284 let memory = [const { UnsafeCell::new(0u8) }; 16];
1285 let ptr = get_backing_memory_ptr(&memory);
1286 let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, memory.len()) };
1287
1288 // Test writing via the slice
1289 slice[0].set(42);
1290 slice[5].set(100);
1291
1292 // Test reading back
1293 assert_eq!(slice[0].get(), 42);
1294 assert_eq!(slice[5].get(), 100);
1295
1296 // Verify backing memory was actually updated
1297 assert_eq!(unsafe { *memory[0].get() }, 42);
1298 }
1299
1300 #[test]
1301 fn test_concurrent_rw_rw_aliasing() {
1302 // Ensure multiple mutable slices to the same memory do not violate tree
1303 // borrows. This works because WriteableProcessSlice uses Cell
1304 // internally.
1305 let memory = [const { UnsafeCell::new(0u8) }; 16];
1306 let ptr = get_backing_memory_ptr(&memory);
1307
1308 // Create two overlapping slices
1309 let slice1 = unsafe { raw_processbuf_to_rwprocessslice(ptr, memory.len()) };
1310 let slice2 = unsafe { raw_processbuf_to_rwprocessslice(ptr, memory.len()) };
1311
1312 slice1[0].set(10);
1313 assert_eq!(slice2[0].get(), 10);
1314
1315 slice2[0].set(20);
1316 assert_eq!(slice1[0].get(), 20);
1317
1318 // Test interleaved access
1319 let sub1 = slice1.get(0..4).unwrap();
1320 let sub2 = slice2.get(2..6).unwrap();
1321
1322 // sub1: [0, 1, 2, 3]
1323 // sub2: [2, 3, 4, 5]
1324 // Intersection at indices 2 and 3 of the original buffer
1325
1326 sub1[2].set(55); // Index 2 of backing
1327 assert_eq!(sub2[0].get(), 55); // Idx 0 of sub2 is idx 2 of backing
1328 }
1329
1330 #[test]
1331 fn test_concurrent_ro_rw_aliasing() {
1332 // Ensure multiple mutable slices to the same memory do not violate tree
1333 // borrows. This works because ReadnableProcessSlice and
1334 // WriteableProcessSlice both use Cell internally.
1335 let memory = [const { UnsafeCell::new(0u8) }; 16];
1336 let ptr = get_backing_memory_ptr(&memory);
1337
1338 // Create two overlapping slices
1339 let slice1 = unsafe { raw_processbuf_to_roprocessslice(ptr, memory.len()) };
1340 let slice2 = unsafe { raw_processbuf_to_rwprocessslice(ptr, memory.len()) };
1341
1342 slice2[0].set(20);
1343 assert_eq!(slice1[0].get(), 20);
1344
1345 // Test interleaved access
1346 let sub1 = slice1.get(0..4).unwrap();
1347 let sub2 = slice2.get(2..6).unwrap();
1348
1349 // sub1: [0, 1, 2, 3]
1350 // sub2: [2, 3, 4, 5]
1351 // Intersection at indices 2 and 3 of the original buffer
1352
1353 sub2[0].set(55); // Index 0 of sub2 is index 2 of backing
1354 assert_eq!(sub1[2].get(), 55); // Index 2 of backing
1355 }
1356
1357 #[test]
1358 fn test_zero_length_null_ptr_ro() {
1359 // Should be safe to create a 0-len slice from a null pointer
1360 let slice = unsafe { raw_processbuf_to_roprocessslice(core::ptr::null_mut(), 0) };
1361 assert_eq!(slice.len(), 0);
1362 assert!(slice.get(0).is_none());
1363
1364 // Iteration should simply yield nothing
1365 let mut count = 0;
1366 for _ in slice.iter() {
1367 count += 1;
1368 }
1369 assert_eq!(count, 0);
1370
1371 // Slice should be created over a non-null pointer
1372 // (NonNull::dangling()):
1373 assert_eq!(
1374 slice as *const ReadableProcessSlice as *const u8,
1375 core::ptr::NonNull::<u8>::dangling().as_ptr(),
1376 );
1377 }
1378
1379 #[test]
1380 fn test_zero_length_non_null_ptr_ro() {
1381 // Should be safe to create a 0-len slice from any arbitrary
1382 // non-null pointer:
1383 let slice = unsafe {
1384 raw_processbuf_to_roprocessslice(
1385 // Under strict provenance, we cannot simply cast an arbitrary
1386 // integer into a pointer. However, with a zero-length process
1387 // slice, the pointer passed to this function must never be
1388 // dereferencable anyways. Thus we simply start from a
1389 // null-pointer, and derive another pointer from it (and its
1390 // provenance) at an offset.
1391 core::ptr::null_mut::<u8>().wrapping_byte_add(42),
1392 0,
1393 )
1394 };
1395 assert_eq!(slice.len(), 0);
1396 assert!(slice.get(0).is_none());
1397
1398 // Iteration should simply yield nothing
1399 let mut count = 0;
1400 for _ in slice.iter() {
1401 count += 1;
1402 }
1403 assert_eq!(count, 0);
1404
1405 // Slice should not retain its pointer, and return a non-null
1406 // (dangling) pointer instead:
1407 assert_eq!(
1408 slice as *const ReadableProcessSlice as *const u8,
1409 core::ptr::NonNull::<u8>::dangling().as_ptr()
1410 );
1411 }
1412
1413 #[test]
1414 fn test_zero_length_null_ptr_rw() {
1415 // Should be safe to create a 0-len slice from a null pointer
1416 let slice = unsafe { raw_processbuf_to_rwprocessslice(core::ptr::null_mut(), 0) };
1417 assert_eq!(slice.len(), 0);
1418 assert!(slice.get(0).is_none());
1419
1420 // Iteration should simply yield nothing
1421 let mut count = 0;
1422 for _ in slice.iter() {
1423 count += 1;
1424 }
1425 assert_eq!(count, 0);
1426
1427 // Slice should be created over a non-null pointer
1428 // (NonNull::dangling()):
1429 assert_eq!(
1430 slice as *const WriteableProcessSlice as *const u8,
1431 core::ptr::NonNull::<u8>::dangling().as_ptr(),
1432 );
1433 }
1434
1435 #[test]
1436 fn test_zero_length_non_null_ptr_rw() {
1437 // Should be safe to create a 0-len slice from any arbitrary
1438 // non-null pointer:
1439 let slice = unsafe {
1440 raw_processbuf_to_rwprocessslice(
1441 // Under strict provenance, we cannot simply cast an arbitrary
1442 // integer into a pointer. However, with a zero-length process
1443 // slice, the pointer passed to this function must never be
1444 // dereferencable anyways. Thus we simply start from a
1445 // null-pointer, and derive another pointer from it (and its
1446 // provenance) at an offset.
1447 core::ptr::null_mut::<u8>().wrapping_byte_add(42),
1448 0,
1449 )
1450 };
1451 assert_eq!(slice.len(), 0);
1452 assert!(slice.get(0).is_none());
1453
1454 // Iteration should simply yield nothing
1455 let mut count = 0;
1456 for _ in slice.iter() {
1457 count += 1;
1458 }
1459 assert_eq!(count, 0);
1460
1461 // Slice should not retain its pointer, and return a non-null
1462 // (dangling) pointer instead:
1463 assert_eq!(
1464 slice as *const WriteableProcessSlice as *const u8,
1465 core::ptr::NonNull::<u8>::dangling().as_ptr()
1466 );
1467 }
1468
1469 #[test]
1470 fn test_out_of_bounds_ro() {
1471 let memory = [const { UnsafeCell::new(0u8) }; 4];
1472 let ptr = get_backing_memory_ptr(&memory);
1473 let slice = unsafe { raw_processbuf_to_roprocessslice(ptr, 4) };
1474
1475 assert!(slice.get(3).is_some());
1476 assert!(slice.get(4).is_none());
1477 assert!(slice.get(100).is_none());
1478
1479 // Range OOB
1480 assert!(slice.get(2..5).is_none());
1481 }
1482
1483 #[test]
1484 #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
1485 fn test_out_of_bounds_panic_ro() {
1486 let memory = [const { UnsafeCell::new(0u8) }; 4];
1487 let ptr = get_backing_memory_ptr(&memory);
1488 let slice = unsafe { raw_processbuf_to_roprocessslice(ptr, 4) };
1489
1490 assert_eq!(slice[3].get(), 0);
1491
1492 // This is out of bounds and will panic:
1493 assert_eq!(slice[4].get(), 0);
1494 }
1495
1496 #[test]
1497 fn test_out_of_bounds_rw() {
1498 let memory = [const { UnsafeCell::new(0u8) }; 4];
1499 let ptr = get_backing_memory_ptr(&memory);
1500 let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, 4) };
1501
1502 assert!(slice.get(3).is_some());
1503 assert!(slice.get(4).is_none());
1504 assert!(slice.get(100).is_none());
1505
1506 // Range OOB
1507 assert!(slice.get(2..5).is_none());
1508 }
1509
1510 #[test]
1511 #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
1512 fn test_out_of_bounds_panic_rw() {
1513 let memory = [const { UnsafeCell::new(0u8) }; 4];
1514 let ptr = get_backing_memory_ptr(&memory);
1515 let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, 4) };
1516
1517 assert_eq!(slice[3].get(), 0);
1518
1519 // This is out of bounds and will panic:
1520 assert_eq!(slice[4].get(), 0);
1521 }
1522
1523 #[test]
1524 fn test_copy_logic() {
1525 let memory = [const { UnsafeCell::new(0u8) }; 4];
1526 let ptr = get_backing_memory_ptr(&memory);
1527 let src_data = [10, 20, 30, 40];
1528 let mut dst_data = [0u8; 4];
1529
1530 let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, 4) };
1531
1532 // Copy into slice
1533 slice.copy_from_slice(&src_data);
1534 assert_eq!(slice[0].get(), 10);
1535 assert_eq!(slice[3].get(), 40);
1536
1537 // Copy out of slice
1538 slice.copy_to_slice(&mut dst_data);
1539 assert_eq!(dst_data, src_data);
1540 }
1541
1542 #[test]
1543 #[should_panic(
1544 expected = "source slice length (4) does not match destination slice length (2)"
1545 )]
1546 fn test_copy_panic_len_mismatch() {
1547 let memory = [const { UnsafeCell::new(0u8) }; 4];
1548 let ptr = get_backing_memory_ptr(&memory);
1549 let mut small_dst = [0u8; 2];
1550
1551 let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, 4) };
1552 slice.copy_to_slice(&mut small_dst);
1553 }
1554
1555 #[test]
1556 fn test_transmute_from_immutable_slice() {
1557 // This test exercises the `From<&[u8]>` implementation for
1558 // ReadableProcessSlice.
1559 //
1560 // We take a standard, immutable Rust slice (`&[u8]`). This creates a
1561 // shared, read-only borrow of the stack memory. We then convert it
1562 // into a `&ReadableProcessSlice`. This struct wraps
1563 // `ReadableProcessByte`, which wraps `Cell<u8>`.
1564 //
1565 // This is problematic under stacked-borrows, as we are transmuting
1566 // `&[u8]` (immutable, noalias) to `&[Cell<u8>]` (shared, interior
1567 // mutability).
1568 //
1569 // Therefore, we expect the following results:
1570 //
1571 // - Stacked Borrows (Default Miri as of Jan 2026): FAIL.
1572 //
1573 // Stacked Borrows forbids "upgrading" a SharedReadOnly reference to
1574 // one that claims it can mutate (SharedReadWrite), even if we don't
1575 // actually write.
1576 //
1577 // - Tree Borrows (`-Zmiri-tree-borrows`): PASS.
1578 //
1579 // Tree Borrows is experimental and handles "retagging" differently.
1580 // It tolerates this transmute as long as we do not actually perform a
1581 // write operation through the Cell while the original data is frozen.
1582 //
1583 let data = [10u8, 20, 30, 40];
1584 let slice: &[u8] = &data;
1585
1586 // 1. Convert &u8 to &ReadableProcessSlice (which wraps Cell<u8>)
1587 let proc_slice: &ReadableProcessSlice = slice.into();
1588
1589 // 2. Read from it.
1590 //
1591 // Even though we only read, the type of `proc_slice` implies the
1592 // *capability* to mutate, which contradicts the provenance of `slice`.
1593 assert_eq!(proc_slice[0].get(), 10);
1594 assert_eq!(proc_slice[3].get(), 40);
1595 }
1596}