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