Skip to main content

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}