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}