lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250918144356.28585-3-manerakai@protonmail.com>
Date: Thu, 18 Sep 2025 14:45:36 +0000
From: ManeraKai <manerakai@...tonmail.com>
To: "aliceryhl@...gle.com" <aliceryhl@...gle.com>, "gregkh@...uxfoundation.org" <gregkh@...uxfoundation.org>, "arnd@...db.de" <arnd@...db.de>
Cc: "rust-for-linux@...r.kernel.org" <rust-for-linux@...r.kernel.org>, "linux-fsdevel@...r.kernel.org" <linux-fsdevel@...r.kernel.org>, "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>, "manerakai@...tonmail.com" <manerakai@...tonmail.com>
Subject: [PATCH 2/3] rust: miscdevice: Implemented `read` and `write`

Added the general declaration in `FileOperations`. And implemented the
safe wrapping for misc.

Note: Renamed some raw pointer variables to `raw_<name>`. I'm not sure
this way of naming is good or not. I would like your opinion.

Signed-off-by: ManeraKai <manerakai@...tonmail.com>
---
 rust/kernel/fs/file_operations.rs |  20 +++++-
 rust/kernel/miscdevice.rs         | 108 +++++++++++++++++++++++-------
 2 files changed, 104 insertions(+), 24 deletions(-)

diff --git a/rust/kernel/fs/file_operations.rs b/rust/kernel/fs/file_operations.rs
index aa60cd46a012..b21a2bae4803 100644
--- a/rust/kernel/fs/file_operations.rs
+++ b/rust/kernel/fs/file_operations.rs
@@ -14,7 +14,7 @@
     miscdevice::MiscDeviceRegistration,
     mm::virt::VmaNew,
     seq_file::SeqFile,
-    types::ForeignOwnable,
+    types::ForeignOwnable, uaccess::{UserSliceReader, UserSliceWriter},
 };
 
 /// Trait implemented by the private data of an open misc device.
@@ -23,6 +23,24 @@ pub trait FileOperations: Sized {
     /// What kind of pointer should `Self` be wrapped in.
     type Ptr: ForeignOwnable + Send + Sync;
 
+    /// Handler for read.
+    fn read(
+        _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+        _buf: UserSliceWriter,
+        _offset: &mut i64,
+    ) -> Result<i64> {
+        build_error!(VTABLE_DEFAULT_ERROR)
+    }
+
+    /// Handler for write.
+    fn write(
+        _device: <Self::Ptr as ForeignOwnable>::Borrowed<'_>,
+        mut _buf: UserSliceReader,
+        _offset: &mut i64,
+    ) -> Result<i64> {
+        build_error!(VTABLE_DEFAULT_ERROR)
+    }
+
     /// Called when the misc device is opened.
     ///
     /// The returned pointer will be stored as the private data for the file.
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
index 578f33383ce6..f4b6388a3742 100644
--- a/rust/kernel/miscdevice.rs
+++ b/rust/kernel/miscdevice.rs
@@ -8,6 +8,8 @@
 //!
 //! Reference: <https://www.kernel.org/doc/html/latest/driver-api/misc_devices.html>
 
+use bindings::loff_t;
+
 use crate::{
     bindings,
     device::Device,
@@ -17,7 +19,7 @@
     mm::virt::VmaNew,
     prelude::*,
     seq_file::SeqFile,
-    types::{ForeignOwnable, Opaque},
+    types::{ForeignOwnable, Opaque}, uaccess::UserSlice,
 };
 use core::{marker::PhantomData, mem::MaybeUninit, pin::Pin};
 
@@ -112,6 +114,54 @@ fn drop(self: Pin<&mut Self>) {
 struct MiscdeviceVTable<T: FileOperations>(PhantomData<T>);
 
 impl<T: FileOperations> MiscdeviceVTable<T> {
+    unsafe extern "C" fn read(
+        raw_file: *mut bindings::file,
+        raw_buf: *mut ffi::c_char,
+        size: usize,
+        raw_offset: *mut loff_t,
+    ) -> c_long {
+        // SAFETY: The read call of a file can access file and its private_data.
+        let raw_device = unsafe { (*raw_file).private_data };
+
+        // SAFETY: The read call of a file can borrow the private_data of the file.
+        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
+
+        let user_slice = UserSlice::new(UserPtr::from_ptr(raw_buf as *mut c_void), size);
+        let user_slice_writer = user_slice.writer();
+
+        // SAFETY: The read call of a file can access and modify the offset pointer value.
+        let offset = unsafe { &mut *raw_offset };
+
+        match T::read(device, user_slice_writer, offset) {
+            Ok(ret) => ret as c_long,
+            Err(err) => err.to_errno() as c_long,
+        }
+    }
+
+    unsafe extern "C" fn write(
+        raw_file: *mut bindings::file,
+        raw_buf: *const ffi::c_char,
+        size: usize,
+        raw_offset: *mut loff_t,
+    ) -> c_long {
+        // SAFETY: The read call of a file can access file and its private_data.
+        let raw_device = unsafe { (*raw_file).private_data };
+
+        // SAFETY: The read call of a file can borrow the private_data of the file.
+        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
+
+        let user_slice = UserSlice::new(UserPtr::from_ptr(raw_buf as *mut c_void), size);
+        let user_slice_reader = user_slice.reader();
+
+        // SAFETY: The read call of a file can access and modify the offset pointer value.
+        let offset = unsafe { &mut *raw_offset };
+
+        match T::write(device, user_slice_reader, offset) {
+            Ok(ret) => ret as c_long,
+            Err(err) => err.to_errno() as c_long,
+        }
+    }
+
     /// # Safety
     ///
     /// `file` and `inode` must be the file and inode for a file that is undergoing initialization.
@@ -124,13 +174,13 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
         }
 
         // SAFETY: The open call of a file can access the private data.
-        let misc_ptr = unsafe { (*raw_file).private_data };
+        let raw_misc = unsafe { (*raw_file).private_data };
 
         // SAFETY: This is a miscdevice, so `misc_open()` set the private data to a pointer to the
         // associated `struct miscdevice` before calling into this method. Furthermore,
         // `misc_open()` ensures that the miscdevice can't be unregistered and freed during this
         // call to `fops_open`.
-        let misc = unsafe { &*misc_ptr.cast::<MiscDeviceRegistration<T>>() };
+        let misc = unsafe { &*raw_misc.cast::<MiscDeviceRegistration<T>>() };
 
         // SAFETY:
         // * This underlying file is valid for (much longer than) the duration of `T::open`.
@@ -157,16 +207,19 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
     ///
     /// `file` and `inode` must be the file and inode for a file that is being released. The file
     /// must be associated with a `MiscDeviceRegistration<T>`.
-    unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int {
+    unsafe extern "C" fn release(
+        _inode: *mut bindings::inode,
+        raw_file: *mut bindings::file,
+    ) -> c_int {
         // SAFETY: The release call of a file owns the private data.
-        let private = unsafe { (*file).private_data };
+        let raw_device = unsafe { (*raw_file).private_data };
         // SAFETY: The release call of a file owns the private data.
-        let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) };
+        let device = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(raw_device) };
 
         // SAFETY:
         // * The file is valid for the duration of this call.
         // * There is no active fdget_pos region on the file on this thread.
-        T::release(ptr, unsafe { File::from_raw_file(file) });
+        T::release(device, unsafe { File::from_raw_file(raw_file) });
 
         0
     }
@@ -176,21 +229,21 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
     /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
     /// `vma` must be a vma that is currently being mmap'ed with this file.
     unsafe extern "C" fn mmap(
-        file: *mut bindings::file,
+        raw_file: *mut bindings::file,
         vma: *mut bindings::vm_area_struct,
     ) -> c_int {
         // SAFETY: The mmap call of a file can access the private data.
-        let private = unsafe { (*file).private_data };
+        let raw_device = unsafe { (*raw_file).private_data };
         // SAFETY: This is a Rust Miscdevice, so we call `into_foreign` in `open` and
         // `from_foreign` in `release`, and `fops_mmap` is guaranteed to be called between those
         // two operations.
-        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private.cast()) };
+        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
         // SAFETY: The caller provides a vma that is undergoing initial VMA setup.
         let area = unsafe { VmaNew::from_raw(vma) };
         // SAFETY:
         // * The file is valid for the duration of this call.
         // * There is no active fdget_pos region on the file on this thread.
-        let file = unsafe { File::from_raw_file(file) };
+        let file = unsafe { File::from_raw_file(raw_file) };
 
         match T::mmap(device, file, area) {
             Ok(()) => 0,
@@ -201,16 +254,16 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
     /// # Safety
     ///
     /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
-    unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long {
+    unsafe extern "C" fn ioctl(raw_file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long {
         // SAFETY: The ioctl call of a file can access the private data.
-        let private = unsafe { (*file).private_data };
+        let raw_device = unsafe { (*raw_file).private_data };
         // SAFETY: Ioctl calls can borrow the private data of the file.
-        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
+        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
 
         // SAFETY:
         // * The file is valid for the duration of this call.
         // * There is no active fdget_pos region on the file on this thread.
-        let file = unsafe { File::from_raw_file(file) };
+        let file = unsafe { File::from_raw_file(raw_file) };
 
         match T::ioctl(device, file, cmd, arg) {
             Ok(ret) => ret as c_long,
@@ -223,19 +276,19 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
     /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
     #[cfg(CONFIG_COMPAT)]
     unsafe extern "C" fn compat_ioctl(
-        file: *mut bindings::file,
+        raw_file: *mut bindings::file,
         cmd: c_uint,
         arg: c_ulong,
     ) -> c_long {
         // SAFETY: The compat ioctl call of a file can access the private data.
-        let private = unsafe { (*file).private_data };
+        let raw_device = unsafe { (*raw_file).private_data };
         // SAFETY: Ioctl calls can borrow the private data of the file.
-        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
+        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
 
         // SAFETY:
         // * The file is valid for the duration of this call.
         // * There is no active fdget_pos region on the file on this thread.
-        let file = unsafe { File::from_raw_file(file) };
+        let file = unsafe { File::from_raw_file(raw_file) };
 
         match T::compat_ioctl(device, file, cmd, arg) {
             Ok(ret) => ret as c_long,
@@ -247,15 +300,18 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
     ///
     /// - `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
     /// - `seq_file` must be a valid `struct seq_file` that we can write to.
-    unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) {
+    unsafe extern "C" fn show_fdinfo(
+        seq_file: *mut bindings::seq_file,
+        raw_file: *mut bindings::file,
+    ) {
         // SAFETY: The release call of a file owns the private data.
-        let private = unsafe { (*file).private_data };
+        let raw_device = unsafe { (*raw_file).private_data };
         // SAFETY: Ioctl calls can borrow the private data of the file.
-        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
+        let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(raw_device) };
         // SAFETY:
         // * The file is valid for the duration of this call.
         // * There is no active fdget_pos region on the file on this thread.
-        let file = unsafe { File::from_raw_file(file) };
+        let file = unsafe { File::from_raw_file(raw_file) };
         // SAFETY: The caller ensures that the pointer is valid and exclusive for the duration in
         // which this method is called.
         let m = unsafe { SeqFile::from_raw(seq_file) };
@@ -264,6 +320,12 @@ impl<T: FileOperations> MiscdeviceVTable<T> {
     }
 
     const VTABLE: bindings::file_operations = bindings::file_operations {
+        read: if T::HAS_READ { Some(Self::read) } else { None },
+        write: if T::HAS_WRITE {
+            Some(Self::write)
+        } else {
+            None
+        },
         open: Some(Self::open),
         release: Some(Self::release),
         mmap: if T::HAS_MMAP { Some(Self::mmap) } else { None },
-- 
2.43.0



Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ