[RFC PATCH 2/3] WIP: rust: fs: mark data returned by inodes untrusted

From: Benno Lossin
Date: Fri Sep 13 2024 - 07:27:25 EST


This is only meant to show how one would use the untrusted data API, not
to be actually used in production, as I just added `Untrusted` where I
thought it might fit. I have no idea if this is actually the correct
place where the untrusted data path starts.
---
rust/kernel/fs/inode.rs | 33 +++++++++++++++++++++------------
1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/rust/kernel/fs/inode.rs b/rust/kernel/fs/inode.rs
index b2b7d000080e..349f7f1ab420 100644
--- a/rust/kernel/fs/inode.rs
+++ b/rust/kernel/fs/inode.rs
@@ -11,7 +11,9 @@
PageOffset, UnspecifiedFS,
};
use crate::error::{code::*, from_err_ptr, Result};
-use crate::types::{ARef, AlwaysRefCounted, Either, ForeignOwnable, Lockable, Locked, Opaque};
+use crate::types::{
+ ARef, AlwaysRefCounted, Either, ForeignOwnable, Lockable, Locked, Opaque, Untrusted,
+};
use crate::{
bindings, block, build_error, container_of, folio, folio::Folio, mem_cache::MemCache,
str::CStr, str::CString, time::Timespec,
@@ -133,21 +135,24 @@ pub unsafe fn mapper(&self) -> Mapper<T> {
pub unsafe fn mapped_folio(
&self,
offset: Offset,
- ) -> Result<folio::Mapped<'_, folio::PageCache<T>>> {
+ ) -> Result<Untrusted<folio::Mapped<'_, folio::PageCache<T>>>> {
let page_index = offset >> bindings::PAGE_SHIFT;
let page_offset = offset & ((bindings::PAGE_SIZE - 1) as Offset);
let folio = self.read_mapping_folio(page_index.try_into()?)?;
+ let folio = folio.into_inner_untrusted();

// SAFETY: The safety requirements guarantee that there are no concurrent mutable mappings
// of the folio.
- unsafe { Folio::map_owned(folio, page_offset.try_into()?) }
+ Ok(Untrusted::new_untrusted(unsafe {
+ Folio::map_owned(folio, page_offset.try_into()?)?
+ }))
}

/// Returns the folio at the given page index.
pub fn read_mapping_folio(
&self,
index: PageOffset,
- ) -> Result<ARef<Folio<folio::PageCache<T>>>> {
+ ) -> Result<Untrusted<ARef<Folio<folio::PageCache<T>>>>> {
let folio = from_err_ptr(unsafe {
bindings::read_mapping_folio(
(*self.0.get()).i_mapping,
@@ -159,7 +164,7 @@ pub fn read_mapping_folio(
.ok_or(EIO)?
.cast::<Folio<folio::PageCache<T>>>();
// SAFETY: The folio returned by read_mapping_folio has had its refcount incremented.
- Ok(unsafe { ARef::from_raw(ptr) })
+ Ok(Untrusted::new_untrusted(unsafe { ARef::from_raw(ptr) }))
}

/// Iterate over the given range, one folio at a time.
@@ -171,7 +176,7 @@ pub unsafe fn for_each_page<U>(
&self,
first: Offset,
len: Offset,
- mut cb: impl FnMut(&[u8]) -> Result<Option<U>>,
+ mut cb: impl FnMut(&Untrusted<[u8]>) -> Result<Option<U>>,
) -> Result<Option<U>> {
if first >= self.size() {
return Ok(None);
@@ -183,8 +188,9 @@ pub unsafe fn for_each_page<U>(
while remain > 0 {
// SAFETY: The safety requirements of this function satisfy those of `mapped_folio`.
let data = unsafe { self.mapped_folio(next)? };
+ let data = data.into_inner_untrusted();
let avail = cmp::min(data.len(), remain.try_into().unwrap_or(usize::MAX));
- let ret = cb(&data[..avail])?;
+ let ret = cb(Untrusted::new_untrusted_ref(&data[..avail]))?;
if ret.is_some() {
return Ok(ret);
}
@@ -297,7 +303,7 @@ impl<T: FileSystem + ?Sized, U: Deref<Target = INode<T>>> Locked<U, ReadSem> {
pub fn mapped_folio<'a>(
&'a self,
offset: Offset,
- ) -> Result<folio::Mapped<'a, folio::PageCache<T>>>
+ ) -> Result<Untrusted<folio::Mapped<'a, folio::PageCache<T>>>>
where
T: 'a,
{
@@ -315,7 +321,7 @@ pub fn for_each_page<V>(
&self,
first: Offset,
len: Offset,
- cb: impl FnMut(&[u8]) -> Result<Option<V>>,
+ cb: impl FnMut(&Untrusted<[u8]>) -> Result<Option<V>>,
) -> Result<Option<V>> {
if T::IS_UNSPECIFIED {
build_error!("unspecified file systems cannot safely map folios");
@@ -750,14 +756,17 @@ pub fn split_at(mut self, offset: Offset) -> (Self, Self) {
}

/// Returns a mapped folio at the given offset.
- pub fn mapped_folio(&self, offset: Offset) -> Result<folio::Mapped<'_, folio::PageCache<T>>> {
+ pub fn mapped_folio(
+ &self,
+ offset: Offset,
+ ) -> Result<Untrusted<folio::Mapped<'_, folio::PageCache<T>>>> {
if offset < self.begin || offset >= self.end {
return Err(ERANGE);
}

// SAFETY: By the type invariant, there are no other mutable mappings of the folio.
let mut map = unsafe { self.inode.mapped_folio(offset) }?;
- map.cap_len((self.end - offset).try_into()?);
+ map.untrusted_mut().cap_len((self.end - offset).try_into()?);
Ok(map)
}

@@ -766,7 +775,7 @@ pub fn for_each_page<U>(
&self,
first: Offset,
len: Offset,
- cb: impl FnMut(&[u8]) -> Result<Option<U>>,
+ cb: impl FnMut(&Untrusted<[u8]>) -> Result<Option<U>>,
) -> Result<Option<U>> {
if first < self.begin || first >= self.end {
return Err(ERANGE);
--
2.46.0