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
411unsafe impl ReadableProcessBuffer for ReadOnlyProcessBuffer {
412    /// Return the length of the buffer in bytes.
413    fn len(&self) -> usize {
414        self.process_id
415            .map_or(0, |pid| pid.kernel.process_map_or(0, pid, |_| self.len))
416    }
417
418    /// Return the pointer to the start of the buffer.
419    fn ptr(&self) -> *const u8 {
420        if self.len == 0 {
421            core::ptr::null::<u8>()
422        } else {
423            self.ptr
424        }
425    }
426
427    /// Access the contents of the buffer in a closure.
428    ///
429    /// This verifies the process is still valid before accessing the underlying
430    /// memory.
431    fn enter<F, R>(&self, fun: F) -> Result<R, process::Error>
432    where
433        F: FnOnce(&ReadableProcessSlice) -> R,
434    {
435        match self.process_id {
436            None => Err(process::Error::NoSuchApp),
437            Some(pid) => pid
438                .kernel
439                .process_map_or(Err(process::Error::NoSuchApp), pid, |_| {
440                    // SAFETY: `kernel.process_map_or()` validates that
441                    // the process still exists and its memory is still
442                    // valid. In particular, `Process` tracks the "high water
443                    // mark" of memory that the process has `allow`ed to the
444                    // kernel. Because `Process` does not feature an API to
445                    // move the "high water mark" down again, which would be
446                    // called once a `ProcessBuffer` has been passed back into
447                    // the kernel, a given `Process` implementation must assume
448                    // that the memory described by a once-allowed
449                    // `ProcessBuffer` is still in use, and thus will not
450                    // permit the process to free any memory after it has
451                    // been `allow`ed to the kernel once. This guarantees
452                    // that the buffer is safe to convert into a slice
453                    // here. For more information, refer to the
454                    // comment and subsequent discussion on tock/tock#2632:
455                    // https://github.com/tock/tock/pull/2632#issuecomment-869974365
456                    Ok(fun(unsafe {
457                        raw_processbuf_to_roprocessslice(self.ptr, self.len)
458                    }))
459                }),
460        }
461    }
462}
463
464impl Default for ReadOnlyProcessBuffer {
465    fn default() -> Self {
466        ReadOnlyProcessBuffer {
467            ptr: core::ptr::null_mut::<u8>(),
468            len: 0,
469            process_id: None,
470        }
471    }
472}
473
474/// Provides access to a [`ReadOnlyProcessBuffer`] with a restricted lifetime.
475/// This automatically dereferences into a ReadOnlyProcessBuffer
476pub struct ReadOnlyProcessBufferRef<'a> {
477    buf: ReadOnlyProcessBuffer,
478    _phantom: PhantomData<&'a ()>,
479}
480
481impl ReadOnlyProcessBufferRef<'_> {
482    /// Construct a new [`ReadOnlyProcessBufferRef`] over a given pointer and
483    /// length with a lifetime derived from the caller.
484    ///
485    /// # Safety
486    ///
487    /// Refer to the safety requirements of
488    /// [`ReadOnlyProcessBuffer::new_external`]. The derived lifetime can
489    /// help enforce the invariant that this incoming pointer may only
490    /// be access for a certain duration.
491    pub(crate) unsafe fn new(ptr: *const u8, len: usize, process_id: ProcessId) -> Self {
492        // SAFETY: See function description.
493        unsafe {
494            Self {
495                buf: ReadOnlyProcessBuffer::new(ptr, len, process_id),
496                _phantom: PhantomData,
497            }
498        }
499    }
500}
501
502impl Deref for ReadOnlyProcessBufferRef<'_> {
503    type Target = ReadOnlyProcessBuffer;
504    fn deref(&self) -> &Self::Target {
505        &self.buf
506    }
507}
508
509/// Read-writable buffer shared by a userspace process.
510///
511/// This struct is provided to capsules when a process `allows` a
512/// particular section of its memory to the kernel and gives the
513/// kernel read and write access to this memory.
514///
515/// It can be used to obtain a [`WriteableProcessSlice`], which is
516/// based around a slice of [`Cell`]s. This is because a userspace can
517/// `allow` overlapping sections of memory into different
518/// [`WriteableProcessSlice`]. Having at least one mutable Rust slice
519/// along with read-only or other mutable slices to overlapping memory
520/// in Rust violates Rust's aliasing rules. A slice of [`Cell`]s
521/// avoids this issue by explicitly supporting interior
522/// mutability. Still, a memory barrier prior to switching to
523/// userspace is required, as the compiler is free to reorder reads
524/// and writes, even through [`Cell`]s.
525pub struct ReadWriteProcessBuffer {
526    ptr: *mut u8,
527    len: usize,
528    process_id: Option<ProcessId>,
529}
530
531impl ReadWriteProcessBuffer {
532    /// Construct a new [`ReadWriteProcessBuffer`] over a given
533    /// pointer and length.
534    ///
535    /// # Safety
536    ///
537    /// Refer to the safety requirements of
538    /// [`ReadWriteProcessBuffer::new_external`].
539    pub(crate) unsafe fn new(ptr: *mut u8, len: usize, process_id: ProcessId) -> Self {
540        ReadWriteProcessBuffer {
541            ptr,
542            len,
543            process_id: Some(process_id),
544        }
545    }
546
547    /// Construct a new [`ReadWriteProcessBuffer`] over a given
548    /// pointer and length.
549    ///
550    /// Publicly accessible constructor, which requires the
551    /// [`capabilities::ExternalProcessCapability`] capability. This
552    /// is provided to allow implementations of the
553    /// [`Process`](crate::process::Process) trait outside of the
554    /// `kernel` crate.
555    ///
556    /// # Safety
557    ///
558    /// If the length is `0`, an arbitrary pointer may be passed into
559    /// `ptr`. It does not necessarily have to point to allocated
560    /// memory, nor does it have to meet [Rust's pointer validity
561    /// requirements](https://doc.rust-lang.org/core/ptr/index.html#safety).
562    /// [`ReadWriteProcessBuffer`] must ensure that all Rust slices
563    /// with a length of `0` must be constructed over a valid (but not
564    /// necessarily allocated) base pointer.
565    ///
566    /// If the length is not `0`, the memory region of `[ptr; ptr +
567    /// len)` must be valid memory of the process of the given
568    /// [`ProcessId`]. It must be allocated and and accessible over
569    /// the entire lifetime of the [`ReadWriteProcessBuffer`]. It must
570    /// not point to memory outside of the process' accessible memory
571    /// range, or point (in part) to other processes or kernel
572    /// memory. The `ptr` must meet [Rust's requirements for pointer
573    /// validity](https://doc.rust-lang.org/core/ptr/index.html#safety),
574    /// in particular it must have a minimum alignment of
575    /// `core::mem::align_of::<u8>()` on the respective platform. It
576    /// must point to memory mapped as _readable_ and optionally
577    /// _writable_ and _executable_.
578    pub unsafe fn new_external(
579        ptr: *mut u8,
580        len: usize,
581        process_id: ProcessId,
582        _cap: &dyn capabilities::ExternalProcessCapability,
583    ) -> Self {
584        // SAFETY: See function description.
585        unsafe { Self::new(ptr, len, process_id) }
586    }
587
588    /// Consumes the ReadWriteProcessBuffer, returning its constituent
589    /// pointer and size. This ensures that there cannot
590    /// simultaneously be both a `ReadWriteProcessBuffer` and a pointer to
591    /// its internal data.
592    ///
593    /// `consume` can be used when the kernel needs to pass the
594    /// underlying values across the kernel-to-user boundary (e.g., in
595    /// return values to system calls).
596    pub(crate) fn consume(self) -> (*mut u8, usize) {
597        (self.ptr, self.len)
598    }
599
600    /// This is a `const` version of `Default::default` with the same
601    /// semantics.
602    ///
603    /// Having a const initializer allows initializing a fixed-size
604    /// array with default values without the struct being marked
605    /// `Copy` as such:
606    ///
607    /// ```
608    /// use kernel::processbuffer::ReadWriteProcessBuffer;
609    /// const DEFAULT_RWPROCBUF_VAL: ReadWriteProcessBuffer
610    ///     = ReadWriteProcessBuffer::const_default();
611    /// let my_array = [DEFAULT_RWPROCBUF_VAL; 12];
612    /// ```
613    pub const fn const_default() -> Self {
614        Self {
615            ptr: core::ptr::null_mut::<u8>(),
616            len: 0,
617            process_id: None,
618        }
619    }
620}
621
622unsafe impl ReadableProcessBuffer for ReadWriteProcessBuffer {
623    /// Return the length of the buffer in bytes.
624    fn len(&self) -> usize {
625        self.process_id
626            .map_or(0, |pid| pid.kernel.process_map_or(0, pid, |_| self.len))
627    }
628
629    /// Return the pointer to the start of the buffer.
630    fn ptr(&self) -> *const u8 {
631        if self.len == 0 {
632            core::ptr::null::<u8>()
633        } else {
634            self.ptr
635        }
636    }
637
638    /// Access the contents of the buffer in a closure.
639    ///
640    /// This verifies the process is still valid before accessing the underlying
641    /// memory.
642    fn enter<F, R>(&self, fun: F) -> Result<R, process::Error>
643    where
644        F: FnOnce(&ReadableProcessSlice) -> R,
645    {
646        match self.process_id {
647            None => Err(process::Error::NoSuchApp),
648            Some(pid) => pid
649                .kernel
650                .process_map_or(Err(process::Error::NoSuchApp), pid, |_| {
651                    // SAFETY: `kernel.process_map_or()` validates that
652                    // the process still exists and its memory is still
653                    // valid. In particular, `Process` tracks the "high water
654                    // mark" of memory that the process has `allow`ed to the
655                    // kernel. Because `Process` does not feature an API to
656                    // move the "high water mark" down again, which would be
657                    // called once a `ProcessBuffer` has been passed back into
658                    // the kernel, a given `Process` implementation must assume
659                    // that the memory described by a once-allowed
660                    // `ProcessBuffer` is still in use, and thus will not
661                    // permit the process to free any memory after it has
662                    // been `allow`ed to the kernel once. This guarantees
663                    // that the buffer is safe to convert into a slice
664                    // here. For more information, refer to the
665                    // comment and subsequent discussion on tock/tock#2632:
666                    // https://github.com/tock/tock/pull/2632#issuecomment-869974365
667                    Ok(fun(unsafe {
668                        raw_processbuf_to_roprocessslice(self.ptr, self.len)
669                    }))
670                }),
671        }
672    }
673}
674
675unsafe impl WriteableProcessBuffer for ReadWriteProcessBuffer {
676    fn mut_enter<F, R>(&self, fun: F) -> Result<R, process::Error>
677    where
678        F: FnOnce(&WriteableProcessSlice) -> R,
679    {
680        match self.process_id {
681            None => Err(process::Error::NoSuchApp),
682            Some(pid) => pid
683                .kernel
684                .process_map_or(Err(process::Error::NoSuchApp), pid, |_| {
685                    // SAFETY: `kernel.process_map_or()` validates that
686                    // the process still exists and its memory is still
687                    // valid. In particular, `Process` tracks the "high water
688                    // mark" of memory that the process has `allow`ed to the
689                    // kernel. Because `Process` does not feature an API to
690                    // move the "high water mark" down again, which would be
691                    // called once a `ProcessBuffer` has been passed back into
692                    // the kernel, a given `Process` implementation must assume
693                    // that the memory described by a once-allowed
694                    // `ProcessBuffer` is still in use, and thus will not
695                    // permit the process to free any memory after it has
696                    // been `allow`ed to the kernel once. This guarantees
697                    // that the buffer is safe to convert into a slice
698                    // here. For more information, refer to the
699                    // comment and subsequent discussion on tock/tock#2632:
700                    // https://github.com/tock/tock/pull/2632#issuecomment-869974365
701                    Ok(fun(unsafe {
702                        raw_processbuf_to_rwprocessslice(self.ptr, self.len)
703                    }))
704                }),
705        }
706    }
707}
708
709impl Default for ReadWriteProcessBuffer {
710    fn default() -> Self {
711        Self::const_default()
712    }
713}
714
715/// Provides access to a [`ReadWriteProcessBuffer`] with a restricted lifetime.
716/// This automatically dereferences into a ReadWriteProcessBuffer
717pub struct ReadWriteProcessBufferRef<'a> {
718    buf: ReadWriteProcessBuffer,
719    _phantom: PhantomData<&'a ()>,
720}
721
722impl ReadWriteProcessBufferRef<'_> {
723    /// Construct a new [`ReadWriteProcessBufferRef`] over a given pointer and
724    /// length with a lifetime derived from the caller.
725    ///
726    /// # Safety
727    ///
728    /// Refer to the safety requirements of
729    /// [`ReadWriteProcessBuffer::new_external`]. The derived lifetime can
730    /// help enforce the invariant that this incoming pointer may only
731    /// be access for a certain duration.
732    pub(crate) unsafe fn new(ptr: *mut u8, len: usize, process_id: ProcessId) -> Self {
733        // SAFETY: See function description.
734        unsafe {
735            Self {
736                buf: ReadWriteProcessBuffer::new(ptr, len, process_id),
737                _phantom: PhantomData,
738            }
739        }
740    }
741}
742
743impl Deref for ReadWriteProcessBufferRef<'_> {
744    type Target = ReadWriteProcessBuffer;
745    fn deref(&self) -> &Self::Target {
746        &self.buf
747    }
748}
749
750/// A shareable region of userspace memory.
751///
752/// This trait can be used to gain read-write access to memory regions
753/// wrapped in a ProcessBuffer type.
754// We currently don't need any special functionality in the kernel for this
755// type so we alias it as `ReadWriteProcessBuffer`.
756pub type UserspaceReadableProcessBuffer = ReadWriteProcessBuffer;
757
758/// Equivalent of the Rust core library's
759/// [`SliceIndex`](core::slice::SliceIndex) type for process slices.
760///
761/// This helper trait is used to abstract over indexing operators into
762/// process slices, and is used to "overload" the `.get()` methods
763/// such that it can be called with multiple different indexing
764/// operators.
765///
766/// While we can use the core library's `SliceIndex` trait, parameterized over
767/// our own `ProcessSlice` types, this trait includes mandatory methods that are
768/// undesirable for the process buffer infrastructure, such as unchecked or
769/// mutable index operations. Furthermore, implementing it requires the
770/// `slice_index_methods` nightly feature. Thus we vendor our own, small variant
771/// of this trait.
772pub trait ProcessSliceIndex<PB: ?Sized>: private_process_slice_index::Sealed {
773    type Output: ?Sized;
774    fn get(self, slice: &PB) -> Option<&Self::Output>;
775    fn index(self, slice: &PB) -> &Self::Output;
776}
777
778// Analog to `private_slice_index` from
779// https://github.com/rust-lang/rust/blob/a1eceec00b2684f947481696ae2322e20d59db60/library/core/src/slice/index.rs#L149
780mod private_process_slice_index {
781    use core::ops::{Range, RangeFrom, RangeTo};
782
783    pub trait Sealed {}
784
785    impl Sealed for usize {}
786    impl Sealed for Range<usize> {}
787    impl Sealed for RangeFrom<usize> {}
788    impl Sealed for RangeTo<usize> {}
789}
790
791/// Read-only wrapper around a [`Cell`]
792///
793/// This type is used in providing the [`ReadableProcessSlice`]. The
794/// memory over which a [`ReadableProcessSlice`] exists must never be
795/// written to by the kernel. However, it may either exist in flash
796/// (read-only memory) or RAM (read-writeable memory). Consequently, a
797/// process may `allow` memory overlapping with a
798/// [`ReadOnlyProcessBuffer`] also simultaneously through a
799/// [`ReadWriteProcessBuffer`]. Hence, the kernel can have two
800/// references to the same memory, where one can lead to mutation of
801/// the memory contents. Therefore, the kernel must use [`Cell`]s
802/// around the bytes shared with userspace, to avoid violating Rust's
803/// aliasing rules.
804///
805/// This read-only wrapper around a [`Cell`] only exposes methods
806/// which are safe to call on a process-shared read-only `allow`
807/// memory.
808#[repr(transparent)]
809pub struct ReadableProcessByte {
810    cell: Cell<u8>,
811}
812
813impl ReadableProcessByte {
814    #[inline]
815    pub fn get(&self) -> u8 {
816        self.cell.get()
817    }
818}
819
820/// Readable and accessible slice of memory of a process buffer.
821///
822///
823/// The only way to obtain this struct is through a
824/// [`ReadWriteProcessBuffer`] or [`ReadOnlyProcessBuffer`].
825///
826/// Slices provide a more convenient, traditional interface to process
827/// memory. These slices are transient, as the underlying buffer must
828/// be checked each time a slice is created. This is usually enforced
829/// by the anonymous lifetime defined by the creation of the slice.
830#[repr(transparent)]
831pub struct ReadableProcessSlice {
832    slice: [ReadableProcessByte],
833}
834
835fn cast_byte_slice_to_process_slice(byte_slice: &[ReadableProcessByte]) -> &ReadableProcessSlice {
836    // As ReadableProcessSlice is a transparent wrapper around its inner type,
837    // [ReadableProcessByte], we can safely transmute a reference to the inner
838    // type as a reference to the outer type with the same lifetime.
839    unsafe { core::mem::transmute::<&[ReadableProcessByte], &ReadableProcessSlice>(byte_slice) }
840}
841
842// Allow a u8 slice to be viewed as a ReadableProcessSlice to allow client code
843// to be authored once and accept either [u8] or ReadableProcessSlice.
844impl<'a> From<&'a [u8]> for &'a ReadableProcessSlice {
845    fn from(val: &'a [u8]) -> Self {
846        // SAFETY: The layout of a [u8] and ReadableProcessSlice are guaranteed to be
847        // the same. This also extends the lifetime of the buffer, so aliasing
848        // rules are thus maintained properly.
849        unsafe { core::mem::transmute(val) }
850    }
851}
852
853// Allow a mutable u8 slice to be viewed as a ReadableProcessSlice to allow
854// client code to be authored once and accept either [u8] or
855// ReadableProcessSlice.
856impl<'a> From<&'a mut [u8]> for &'a ReadableProcessSlice {
857    fn from(val: &'a mut [u8]) -> Self {
858        // SAFETY: The layout of a [u8] and ReadableProcessSlice are guaranteed to be
859        // the same. This also extends the mutable lifetime of the buffer, so
860        // aliasing rules are thus maintained properly.
861        unsafe { core::mem::transmute(val) }
862    }
863}
864
865impl ReadableProcessSlice {
866    /// Copy the contents of a [`ReadableProcessSlice`] into a mutable
867    /// slice reference.
868    ///
869    /// The length of `self` must be the same as `dest`. Subslicing
870    /// can be used to obtain a slice of matching length.
871    ///
872    /// # Panics
873    ///
874    /// This function will panic if `self.len() != dest.len()`.
875    pub fn copy_to_slice(&self, dest: &mut [u8]) {
876        // The panic code path was put into a cold function to not
877        // bloat the call site.
878        #[inline(never)]
879        #[cold]
880        #[track_caller]
881        fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! {
882            panic!(
883                "source slice length ({}) does not match destination slice length ({})",
884                src_len, dst_len,
885            );
886        }
887
888        if self.copy_to_slice_or_err(dest).is_err() {
889            len_mismatch_fail(dest.len(), self.len());
890        }
891    }
892
893    /// Copy the contents of a [`ReadableProcessSlice`] into a mutable
894    /// slice reference.
895    ///
896    /// The length of `self` must be the same as `dest`. Subslicing
897    /// can be used to obtain a slice of matching length.
898    pub fn copy_to_slice_or_err(&self, dest: &mut [u8]) -> Result<(), ErrorCode> {
899        // Method implemetation adopted from the
900        // core::slice::copy_from_slice method implementation:
901        // https://doc.rust-lang.org/src/core/slice/mod.rs.html#3034-3036
902
903        if self.len() != dest.len() {
904            Err(ErrorCode::SIZE)
905        } else {
906            // _If_ this turns out to not be efficiently optimized, it
907            // should be possible to use a ptr::copy_nonoverlapping here
908            // given we have exclusive mutable access to the destination
909            // slice which will never be in process memory, and the layout
910            // of &[ReadableProcessByte] is guaranteed to be compatible to
911            // &[u8].
912            for (i, b) in self.slice.iter().enumerate() {
913                dest[i] = b.get();
914            }
915            Ok(())
916        }
917    }
918
919    /// Return the length of the slice in bytes.
920    pub fn len(&self) -> usize {
921        self.slice.len()
922    }
923
924    /// Return an iterator over the bytes of the slice.
925    pub fn iter(&self) -> core::slice::Iter<'_, ReadableProcessByte> {
926        self.slice.iter()
927    }
928
929    /// Iterate the slice in chunks.
930    pub fn chunks(
931        &self,
932        chunk_size: usize,
933    ) -> impl core::iter::Iterator<Item = &ReadableProcessSlice> {
934        self.slice
935            .chunks(chunk_size)
936            .map(cast_byte_slice_to_process_slice)
937    }
938
939    /// Access a portion of the slice with bounds checking. If the access is not
940    /// within the slice then `None` is returned.
941    pub fn get<I: ProcessSliceIndex<Self>>(
942        &self,
943        index: I,
944    ) -> Option<&<I as ProcessSliceIndex<Self>>::Output> {
945        index.get(self)
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    #[deprecated = "Use ReadableProcessSlice::get instead"]
951    pub fn get_from(&self, range: RangeFrom<usize>) -> Option<&ReadableProcessSlice> {
952        range.get(self)
953    }
954
955    /// Access a portion of the slice with bounds checking. If the access is not
956    /// within the slice then `None` is returned.
957    #[deprecated = "Use ReadableProcessSlice::get instead"]
958    pub fn get_to(&self, range: RangeTo<usize>) -> Option<&ReadableProcessSlice> {
959        range.get(self)
960    }
961}
962
963impl ProcessSliceIndex<ReadableProcessSlice> for usize {
964    type Output = ReadableProcessByte;
965
966    fn get(self, slice: &ReadableProcessSlice) -> Option<&Self::Output> {
967        slice.slice.get(self)
968    }
969
970    fn index(self, slice: &ReadableProcessSlice) -> &Self::Output {
971        &slice.slice[self]
972    }
973}
974
975impl ProcessSliceIndex<ReadableProcessSlice> for Range<usize> {
976    type Output = ReadableProcessSlice;
977
978    fn get(self, slice: &ReadableProcessSlice) -> Option<&Self::Output> {
979        slice.slice.get(self).map(cast_byte_slice_to_process_slice)
980    }
981
982    fn index(self, slice: &ReadableProcessSlice) -> &Self::Output {
983        cast_byte_slice_to_process_slice(&slice.slice[self])
984    }
985}
986
987impl ProcessSliceIndex<ReadableProcessSlice> for RangeFrom<usize> {
988    type Output = ReadableProcessSlice;
989
990    fn get(self, slice: &ReadableProcessSlice) -> Option<&Self::Output> {
991        slice.slice.get(self).map(cast_byte_slice_to_process_slice)
992    }
993
994    fn index(self, slice: &ReadableProcessSlice) -> &Self::Output {
995        cast_byte_slice_to_process_slice(&slice.slice[self])
996    }
997}
998
999impl ProcessSliceIndex<ReadableProcessSlice> for RangeTo<usize> {
1000    type Output = ReadableProcessSlice;
1001
1002    fn get(self, slice: &ReadableProcessSlice) -> Option<&Self::Output> {
1003        slice.slice.get(self).map(cast_byte_slice_to_process_slice)
1004    }
1005
1006    fn index(self, slice: &ReadableProcessSlice) -> &Self::Output {
1007        cast_byte_slice_to_process_slice(&slice.slice[self])
1008    }
1009}
1010
1011impl<I: ProcessSliceIndex<Self>> Index<I> for ReadableProcessSlice {
1012    type Output = I::Output;
1013
1014    fn index(&self, index: I) -> &Self::Output {
1015        index.index(self)
1016    }
1017}
1018
1019/// Read-writeable and accessible slice of memory of a process buffer
1020///
1021/// The only way to obtain this struct is through a
1022/// [`ReadWriteProcessBuffer`].
1023///
1024/// Slices provide a more convenient, traditional interface to process
1025/// memory. These slices are transient, as the underlying buffer must
1026/// be checked each time a slice is created. This is usually enforced
1027/// by the anonymous lifetime defined by the creation of the slice.
1028#[repr(transparent)]
1029pub struct WriteableProcessSlice {
1030    slice: [Cell<u8>],
1031}
1032
1033fn cast_cell_slice_to_process_slice(cell_slice: &[Cell<u8>]) -> &WriteableProcessSlice {
1034    // SAFETY: As WriteableProcessSlice is a transparent wrapper around its inner type,
1035    // [Cell<u8>], we can safely transmute a reference to the inner type as the
1036    // outer type with the same lifetime.
1037    unsafe { core::mem::transmute(cell_slice) }
1038}
1039
1040// Allow a mutable u8 slice to be viewed as a WritableProcessSlice to allow
1041// client code to be authored once and accept either [u8] or
1042// WriteableProcessSlice.
1043impl<'a> From<&'a mut [u8]> for &'a WriteableProcessSlice {
1044    fn from(val: &'a mut [u8]) -> Self {
1045        // SAFETY: The layout of a [u8] and WriteableProcessSlice are guaranteed to be
1046        // the same. This also extends the mutable lifetime of the buffer, so
1047        // aliasing rules are thus maintained properly.
1048        unsafe { core::mem::transmute(val) }
1049    }
1050}
1051
1052impl WriteableProcessSlice {
1053    /// Copy the contents of a [`WriteableProcessSlice`] into a mutable
1054    /// slice reference.
1055    ///
1056    /// The length of `self` must be the same as `dest`. Subslicing
1057    /// can be used to obtain a slice of matching length.
1058    ///
1059    /// # Panics
1060    ///
1061    /// This function will panic if `self.len() != dest.len()`.
1062    pub fn copy_to_slice(&self, dest: &mut [u8]) {
1063        // The panic code path was put into a cold function to not
1064        // bloat the call site.
1065        #[inline(never)]
1066        #[cold]
1067        #[track_caller]
1068        fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! {
1069            panic!(
1070                "source slice length ({}) does not match destination slice length ({})",
1071                src_len, dst_len,
1072            );
1073        }
1074
1075        if self.copy_to_slice_or_err(dest).is_err() {
1076            len_mismatch_fail(dest.len(), self.len());
1077        }
1078    }
1079
1080    /// Copy the contents of a [`WriteableProcessSlice`] into a mutable
1081    /// slice reference.
1082    ///
1083    /// The length of `self` must be the same as `dest`. Subslicing
1084    /// can be used to obtain a slice of matching length.
1085    pub fn copy_to_slice_or_err(&self, dest: &mut [u8]) -> Result<(), ErrorCode> {
1086        // Method implemetation adopted from the
1087        // core::slice::copy_from_slice method implementation:
1088        // https://doc.rust-lang.org/src/core/slice/mod.rs.html#3034-3036
1089
1090        if self.len() != dest.len() {
1091            Err(ErrorCode::SIZE)
1092        } else {
1093            // _If_ this turns out to not be efficiently optimized, it
1094            // should be possible to use a ptr::copy_nonoverlapping here
1095            // given we have exclusive mutable access to the destination
1096            // slice which will never be in process memory, and the layout
1097            // of &[Cell<u8>] is guaranteed to be compatible to &[u8].
1098            self.slice
1099                .iter()
1100                .zip(dest.iter_mut())
1101                .for_each(|(src, dst)| *dst = src.get());
1102            Ok(())
1103        }
1104    }
1105
1106    /// Copy the contents of a slice of bytes into a [`WriteableProcessSlice`].
1107    ///
1108    /// The length of `src` must be the same as `self`. Subslicing can
1109    /// be used to obtain a slice of matching length.
1110    ///
1111    /// # Panics
1112    ///
1113    /// This function will panic if `src.len() != self.len()`.
1114    pub fn copy_from_slice(&self, src: &[u8]) {
1115        // Method implemetation adopted from the
1116        // core::slice::copy_from_slice method implementation:
1117        // https://doc.rust-lang.org/src/core/slice/mod.rs.html#3034-3036
1118
1119        // The panic code path was put into a cold function to not
1120        // bloat the call site.
1121        #[inline(never)]
1122        #[cold]
1123        #[track_caller]
1124        fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! {
1125            panic!(
1126                "src slice len ({}) != dest slice len ({})",
1127                src_len, dst_len,
1128            );
1129        }
1130
1131        if self.copy_from_slice_or_err(src).is_err() {
1132            len_mismatch_fail(self.len(), src.len());
1133        }
1134    }
1135
1136    /// Copy the contents of a slice of bytes into a [`WriteableProcessSlice`].
1137    ///
1138    /// The length of `src` must be the same as `self`. Subslicing can
1139    /// be used to obtain a slice of matching length.
1140    pub fn copy_from_slice_or_err(&self, src: &[u8]) -> Result<(), ErrorCode> {
1141        // Method implemetation adopted from the
1142        // core::slice::copy_from_slice method implementation:
1143        // https://doc.rust-lang.org/src/core/slice/mod.rs.html#3034-3036
1144
1145        if self.len() != src.len() {
1146            Err(ErrorCode::SIZE)
1147        } else {
1148            // _If_ this turns out to not be efficiently optimized, it
1149            // should be possible to use a ptr::copy_nonoverlapping here
1150            // given we have exclusive mutable access to the destination
1151            // slice which will never be in process memory, and the layout
1152            // of &[Cell<u8>] is guaranteed to be compatible to &[u8].
1153            src.iter()
1154                .zip(self.slice.iter())
1155                .for_each(|(src, dst)| dst.set(*src));
1156            Ok(())
1157        }
1158    }
1159
1160    /// Return the length of the slice in bytes.
1161    pub fn len(&self) -> usize {
1162        self.slice.len()
1163    }
1164
1165    /// Return an iterator over the slice.
1166    pub fn iter(&self) -> core::slice::Iter<'_, Cell<u8>> {
1167        self.slice.iter()
1168    }
1169
1170    /// Iterate over the slice in chunks.
1171    pub fn chunks(
1172        &self,
1173        chunk_size: usize,
1174    ) -> impl core::iter::Iterator<Item = &WriteableProcessSlice> {
1175        self.slice
1176            .chunks(chunk_size)
1177            .map(cast_cell_slice_to_process_slice)
1178    }
1179
1180    /// Access a portion of the slice with bounds checking. If the access is not
1181    /// within the slice then `None` is returned.
1182    pub fn get<I: ProcessSliceIndex<Self>>(
1183        &self,
1184        index: I,
1185    ) -> Option<&<I as ProcessSliceIndex<Self>>::Output> {
1186        index.get(self)
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    #[deprecated = "Use WriteableProcessSlice::get instead"]
1192    pub fn get_from(&self, range: RangeFrom<usize>) -> Option<&WriteableProcessSlice> {
1193        range.get(self)
1194    }
1195
1196    /// Access a portion of the slice with bounds checking. If the access is not
1197    /// within the slice then `None` is returned.
1198    #[deprecated = "Use WriteableProcessSlice::get instead"]
1199    pub fn get_to(&self, range: RangeTo<usize>) -> Option<&WriteableProcessSlice> {
1200        range.get(self)
1201    }
1202}
1203
1204impl ProcessSliceIndex<WriteableProcessSlice> for usize {
1205    type Output = Cell<u8>;
1206
1207    fn get(self, slice: &WriteableProcessSlice) -> Option<&Self::Output> {
1208        slice.slice.get(self)
1209    }
1210
1211    fn index(self, slice: &WriteableProcessSlice) -> &Self::Output {
1212        &slice.slice[self]
1213    }
1214}
1215
1216impl ProcessSliceIndex<WriteableProcessSlice> for Range<usize> {
1217    type Output = WriteableProcessSlice;
1218
1219    fn get(self, slice: &WriteableProcessSlice) -> Option<&Self::Output> {
1220        slice.slice.get(self).map(cast_cell_slice_to_process_slice)
1221    }
1222
1223    fn index(self, slice: &WriteableProcessSlice) -> &Self::Output {
1224        cast_cell_slice_to_process_slice(&slice.slice[self])
1225    }
1226}
1227
1228impl ProcessSliceIndex<WriteableProcessSlice> for RangeFrom<usize> {
1229    type Output = WriteableProcessSlice;
1230
1231    fn get(self, slice: &WriteableProcessSlice) -> Option<&Self::Output> {
1232        slice.slice.get(self).map(cast_cell_slice_to_process_slice)
1233    }
1234
1235    fn index(self, slice: &WriteableProcessSlice) -> &Self::Output {
1236        cast_cell_slice_to_process_slice(&slice.slice[self])
1237    }
1238}
1239
1240impl ProcessSliceIndex<WriteableProcessSlice> for RangeTo<usize> {
1241    type Output = WriteableProcessSlice;
1242
1243    fn get(self, slice: &WriteableProcessSlice) -> Option<&Self::Output> {
1244        slice.slice.get(self).map(cast_cell_slice_to_process_slice)
1245    }
1246
1247    fn index(self, slice: &WriteableProcessSlice) -> &Self::Output {
1248        cast_cell_slice_to_process_slice(&slice.slice[self])
1249    }
1250}
1251
1252impl<I: ProcessSliceIndex<Self>> Index<I> for WriteableProcessSlice {
1253    type Output = I::Output;
1254
1255    fn index(&self, index: I) -> &Self::Output {
1256        index.index(self)
1257    }
1258}
1259
1260#[cfg(test)]
1261mod miri_tests {
1262    use super::*;
1263    use core::cell::UnsafeCell;
1264
1265    // Helper to get a raw mutable pointer to the backing memory we use to
1266    // create process slices over. This backing memory, though allocated by
1267    // Rust, contains only `UnsafeCell`s and thus is suitable for creating
1268    // process slice references over.
1269    fn get_backing_memory_ptr<const N: usize>(mem: &[UnsafeCell<u8>; N]) -> *mut u8 {
1270        mem as *const _ as *mut u8
1271    }
1272
1273    #[test]
1274    fn test_basic_read_write() {
1275        let memory = [const { UnsafeCell::new(0u8) }; 16];
1276        let ptr = get_backing_memory_ptr(&memory);
1277        let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, memory.len()) };
1278
1279        // Test writing via the slice
1280        slice[0].set(42);
1281        slice[5].set(100);
1282
1283        // Test reading back
1284        assert_eq!(slice[0].get(), 42);
1285        assert_eq!(slice[5].get(), 100);
1286
1287        // Verify backing memory was actually updated
1288        assert_eq!(unsafe { *memory[0].get() }, 42);
1289    }
1290
1291    #[test]
1292    fn test_concurrent_rw_rw_aliasing() {
1293        // Ensure multiple mutable slices to the same memory do not violate tree
1294        // borrows. This works because WriteableProcessSlice uses Cell
1295        // internally.
1296        let memory = [const { UnsafeCell::new(0u8) }; 16];
1297        let ptr = get_backing_memory_ptr(&memory);
1298
1299        // Create two overlapping slices
1300        let slice1 = unsafe { raw_processbuf_to_rwprocessslice(ptr, memory.len()) };
1301        let slice2 = unsafe { raw_processbuf_to_rwprocessslice(ptr, memory.len()) };
1302
1303        slice1[0].set(10);
1304        assert_eq!(slice2[0].get(), 10);
1305
1306        slice2[0].set(20);
1307        assert_eq!(slice1[0].get(), 20);
1308
1309        // Test interleaved access
1310        let sub1 = slice1.get(0..4).unwrap();
1311        let sub2 = slice2.get(2..6).unwrap();
1312
1313        // sub1: [0, 1, 2, 3]
1314        // sub2:       [2, 3, 4, 5]
1315        // Intersection at indices 2 and 3 of the original buffer
1316
1317        sub1[2].set(55); // Index 2 of backing
1318        assert_eq!(sub2[0].get(), 55); // Idx 0 of sub2 is idx 2 of backing
1319    }
1320
1321    #[test]
1322    fn test_concurrent_ro_rw_aliasing() {
1323        // Ensure multiple mutable slices to the same memory do not violate tree
1324        // borrows. This works because ReadnableProcessSlice and
1325        // WriteableProcessSlice both use Cell internally.
1326        let memory = [const { UnsafeCell::new(0u8) }; 16];
1327        let ptr = get_backing_memory_ptr(&memory);
1328
1329        // Create two overlapping slices
1330        let slice1 = unsafe { raw_processbuf_to_roprocessslice(ptr, memory.len()) };
1331        let slice2 = unsafe { raw_processbuf_to_rwprocessslice(ptr, memory.len()) };
1332
1333        slice2[0].set(20);
1334        assert_eq!(slice1[0].get(), 20);
1335
1336        // Test interleaved access
1337        let sub1 = slice1.get(0..4).unwrap();
1338        let sub2 = slice2.get(2..6).unwrap();
1339
1340        // sub1: [0, 1, 2, 3]
1341        // sub2:       [2, 3, 4, 5]
1342        // Intersection at indices 2 and 3 of the original buffer
1343
1344        sub2[0].set(55); // Index 0 of sub2 is index 2 of backing
1345        assert_eq!(sub1[2].get(), 55); // Index 2 of backing
1346    }
1347
1348    #[test]
1349    fn test_zero_length_null_ptr_ro() {
1350        // Should be safe to create a 0-len slice from a null pointer
1351        let slice = unsafe { raw_processbuf_to_roprocessslice(core::ptr::null_mut(), 0) };
1352        assert_eq!(slice.len(), 0);
1353        assert!(slice.get(0).is_none());
1354
1355        // Iteration should simply yield nothing
1356        let mut count = 0;
1357        for _ in slice.iter() {
1358            count += 1;
1359        }
1360        assert_eq!(count, 0);
1361
1362        // Slice should be created over a non-null pointer
1363        // (NonNull::dangling()):
1364        assert_eq!(
1365            slice as *const ReadableProcessSlice as *const u8,
1366            core::ptr::NonNull::<u8>::dangling().as_ptr(),
1367        );
1368    }
1369
1370    #[test]
1371    fn test_zero_length_non_null_ptr_ro() {
1372        // Should be safe to create a 0-len slice from any arbitrary
1373        // non-null pointer:
1374        let slice = unsafe {
1375            raw_processbuf_to_roprocessslice(
1376                // Under strict provenance, we cannot simply cast an arbitrary
1377                // integer into a pointer. However, with a zero-length process
1378                // slice, the pointer passed to this function must never be
1379                // dereferencable anyways. Thus we simply start from a
1380                // null-pointer, and derive another pointer from it (and its
1381                // provenance) at an offset.
1382                core::ptr::null_mut::<u8>().wrapping_byte_add(42),
1383                0,
1384            )
1385        };
1386        assert_eq!(slice.len(), 0);
1387        assert!(slice.get(0).is_none());
1388
1389        // Iteration should simply yield nothing
1390        let mut count = 0;
1391        for _ in slice.iter() {
1392            count += 1;
1393        }
1394        assert_eq!(count, 0);
1395
1396        // Slice should not retain its pointer, and return a non-null
1397        // (dangling) pointer instead:
1398        assert_eq!(
1399            slice as *const ReadableProcessSlice as *const u8,
1400            core::ptr::NonNull::<u8>::dangling().as_ptr()
1401        );
1402    }
1403
1404    #[test]
1405    fn test_zero_length_null_ptr_rw() {
1406        // Should be safe to create a 0-len slice from a null pointer
1407        let slice = unsafe { raw_processbuf_to_rwprocessslice(core::ptr::null_mut(), 0) };
1408        assert_eq!(slice.len(), 0);
1409        assert!(slice.get(0).is_none());
1410
1411        // Iteration should simply yield nothing
1412        let mut count = 0;
1413        for _ in slice.iter() {
1414            count += 1;
1415        }
1416        assert_eq!(count, 0);
1417
1418        // Slice should be created over a non-null pointer
1419        // (NonNull::dangling()):
1420        assert_eq!(
1421            slice as *const WriteableProcessSlice as *const u8,
1422            core::ptr::NonNull::<u8>::dangling().as_ptr(),
1423        );
1424    }
1425
1426    #[test]
1427    fn test_zero_length_non_null_ptr_rw() {
1428        // Should be safe to create a 0-len slice from any arbitrary
1429        // non-null pointer:
1430        let slice = unsafe {
1431            raw_processbuf_to_rwprocessslice(
1432                // Under strict provenance, we cannot simply cast an arbitrary
1433                // integer into a pointer. However, with a zero-length process
1434                // slice, the pointer passed to this function must never be
1435                // dereferencable anyways. Thus we simply start from a
1436                // null-pointer, and derive another pointer from it (and its
1437                // provenance) at an offset.
1438                core::ptr::null_mut::<u8>().wrapping_byte_add(42),
1439                0,
1440            )
1441        };
1442        assert_eq!(slice.len(), 0);
1443        assert!(slice.get(0).is_none());
1444
1445        // Iteration should simply yield nothing
1446        let mut count = 0;
1447        for _ in slice.iter() {
1448            count += 1;
1449        }
1450        assert_eq!(count, 0);
1451
1452        // Slice should not retain its pointer, and return a non-null
1453        // (dangling) pointer instead:
1454        assert_eq!(
1455            slice as *const WriteableProcessSlice as *const u8,
1456            core::ptr::NonNull::<u8>::dangling().as_ptr()
1457        );
1458    }
1459
1460    #[test]
1461    fn test_out_of_bounds_ro() {
1462        let memory = [const { UnsafeCell::new(0u8) }; 4];
1463        let ptr = get_backing_memory_ptr(&memory);
1464        let slice = unsafe { raw_processbuf_to_roprocessslice(ptr, 4) };
1465
1466        assert!(slice.get(3).is_some());
1467        assert!(slice.get(4).is_none());
1468        assert!(slice.get(100).is_none());
1469
1470        // Range OOB
1471        assert!(slice.get(2..5).is_none());
1472    }
1473
1474    #[test]
1475    #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
1476    fn test_out_of_bounds_panic_ro() {
1477        let memory = [const { UnsafeCell::new(0u8) }; 4];
1478        let ptr = get_backing_memory_ptr(&memory);
1479        let slice = unsafe { raw_processbuf_to_roprocessslice(ptr, 4) };
1480
1481        assert_eq!(slice[3].get(), 0);
1482
1483        // This is out of bounds and will panic:
1484        assert_eq!(slice[4].get(), 0);
1485    }
1486
1487    #[test]
1488    fn test_out_of_bounds_rw() {
1489        let memory = [const { UnsafeCell::new(0u8) }; 4];
1490        let ptr = get_backing_memory_ptr(&memory);
1491        let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, 4) };
1492
1493        assert!(slice.get(3).is_some());
1494        assert!(slice.get(4).is_none());
1495        assert!(slice.get(100).is_none());
1496
1497        // Range OOB
1498        assert!(slice.get(2..5).is_none());
1499    }
1500
1501    #[test]
1502    #[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
1503    fn test_out_of_bounds_panic_rw() {
1504        let memory = [const { UnsafeCell::new(0u8) }; 4];
1505        let ptr = get_backing_memory_ptr(&memory);
1506        let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, 4) };
1507
1508        assert_eq!(slice[3].get(), 0);
1509
1510        // This is out of bounds and will panic:
1511        assert_eq!(slice[4].get(), 0);
1512    }
1513
1514    #[test]
1515    fn test_copy_logic() {
1516        let memory = [const { UnsafeCell::new(0u8) }; 4];
1517        let ptr = get_backing_memory_ptr(&memory);
1518        let src_data = [10, 20, 30, 40];
1519        let mut dst_data = [0u8; 4];
1520
1521        let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, 4) };
1522
1523        // Copy into slice
1524        slice.copy_from_slice(&src_data);
1525        assert_eq!(slice[0].get(), 10);
1526        assert_eq!(slice[3].get(), 40);
1527
1528        // Copy out of slice
1529        slice.copy_to_slice(&mut dst_data);
1530        assert_eq!(dst_data, src_data);
1531    }
1532
1533    #[test]
1534    #[should_panic(
1535        expected = "source slice length (4) does not match destination slice length (2)"
1536    )]
1537    fn test_copy_panic_len_mismatch() {
1538        let memory = [const { UnsafeCell::new(0u8) }; 4];
1539        let ptr = get_backing_memory_ptr(&memory);
1540        let mut small_dst = [0u8; 2];
1541
1542        let slice = unsafe { raw_processbuf_to_rwprocessslice(ptr, 4) };
1543        slice.copy_to_slice(&mut small_dst);
1544    }
1545
1546    #[test]
1547    fn test_transmute_from_immutable_slice() {
1548        // This test exercises the `From<&[u8]>` implementation for
1549        // ReadableProcessSlice.
1550        //
1551        // We take a standard, immutable Rust slice (`&[u8]`). This creates a
1552        // shared, read-only borrow of the stack memory.  We then convert it
1553        // into a `&ReadableProcessSlice`. This struct wraps
1554        // `ReadableProcessByte`, which wraps `Cell<u8>`.
1555        //
1556        // This is problematic under stacked-borrows, as we are transmuting
1557        // `&[u8]` (immutable, noalias) to `&[Cell<u8>]` (shared, interior
1558        // mutability).
1559        //
1560        // Therefore, we expect the following results:
1561        //
1562        // - Stacked Borrows (Default Miri as of Jan 2026): FAIL.
1563        //
1564        //   Stacked Borrows forbids "upgrading" a SharedReadOnly reference to
1565        //   one that claims it can mutate (SharedReadWrite), even if we don't
1566        //   actually write.
1567        //
1568        // - Tree Borrows (`-Zmiri-tree-borrows`): PASS.
1569        //
1570        //   Tree Borrows is experimental and handles "retagging" differently.
1571        //   It tolerates this transmute as long as we do not actually perform a
1572        //   write operation through the Cell while the original data is frozen.
1573        //
1574        let data = [10u8, 20, 30, 40];
1575        let slice: &[u8] = &data;
1576
1577        // 1. Convert &u8 to &ReadableProcessSlice (which wraps Cell<u8>)
1578        let proc_slice: &ReadableProcessSlice = slice.into();
1579
1580        // 2. Read from it.
1581        //
1582        // Even though we only read, the type of `proc_slice` implies the
1583        // *capability* to mutate, which contradicts the provenance of `slice`.
1584        assert_eq!(proc_slice[0].get(), 10);
1585        assert_eq!(proc_slice[3].get(), 40);
1586    }
1587}