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