Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions rust/helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,17 @@ void rust_helper_chained_irq_exit(struct irq_chip *chip,
}
EXPORT_SYMBOL_GPL(rust_helper_chained_irq_exit);

const struct cred *rust_helper_get_cred(const struct cred *cred)
{
return get_cred(cred);
}
EXPORT_SYMBOL_GPL(rust_helper_get_cred);

void rust_helper_put_cred(const struct cred *cred) {
put_cred(cred);
}
EXPORT_SYMBOL_GPL(rust_helper_put_cred);

/* We use bindgen's --size_t-is-usize option to bind the C size_t type
* as the Rust usize type, so we can use it in contexts where Rust
* expects a usize like slice (array) indices. usize is defined to be
Expand Down
73 changes: 73 additions & 0 deletions rust/kernel/cred.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: GPL-2.0

//! Credentials management.
//!
//! C header: [`include/linux/cred.h`](../../../../include/linux/cred.h)
//!
//! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>

use crate::bindings;
use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref};

/// Wraps the kernel's `struct cred`.
///
/// # Invariants
///
/// The pointer `Credential::ptr` is non-null and valid. Its reference count is also non-zero.
pub struct Credential {
pub(crate) ptr: *const bindings::cred,
}

impl Clone for Credential {
fn clone(&self) -> Self {
// SAFETY: The type invariants guarantee that `self.ptr` has a non-zero reference count.
let ptr = unsafe { bindings::get_cred(self.ptr) };

// INVARIANT: We incremented the reference count to account for the new `Credential` being
// created.
Self { ptr }
}
}

impl Drop for Credential {
fn drop(&mut self) {
// SAFETY: The type invariants guarantee that `ptr` has a non-zero reference count.
unsafe { bindings::put_cred(self.ptr) };
}
}

/// A wrapper for [`Credential`] that doesn't automatically decrement the refcount when dropped.
///
/// We need the wrapper because [`ManuallyDrop`] alone would allow callers to call
/// [`ManuallyDrop::into_inner`]. This would allow an unsafe sequence to be triggered without
/// `unsafe` blocks because it would trigger an unbalanced call to `put_cred`.
///
/// # Invariants
///
/// The wrapped [`Credential`] remains valid for the lifetime of the object.
pub struct CredentialRef<'a> {
cred: ManuallyDrop<Credential>,
_p: PhantomData<&'a ()>,
}

impl CredentialRef<'_> {
/// Constructs a new [`struct cred`] wrapper that doesn't change its reference count.
///
/// # Safety
///
/// The pointer `ptr` must be non-null and valid for the lifetime of the object.
pub(crate) unsafe fn from_ptr(ptr: *const bindings::cred) -> Self {
Self {
cred: ManuallyDrop::new(Credential { ptr }),
_p: PhantomData,
}
}
}

impl Deref for CredentialRef<'_> {
type Target = Credential;

fn deref(&self) -> &Self::Target {
self.cred.deref()
}
}
12 changes: 11 additions & 1 deletion rust/kernel/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and
//! [`include/linux/file.h`](../../../../include/linux/file.h)

use crate::{bindings, error::Error, Result};
use crate::{bindings, cred::CredentialRef, error::Error, Result};
use core::{mem::ManuallyDrop, ops::Deref};

/// Wraps the kernel's `struct file`.
Expand Down Expand Up @@ -44,6 +44,16 @@ impl File {
// SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
unsafe { (*self.ptr).f_flags & bindings::O_NONBLOCK == 0 }
}

/// Returns the credentials of the task that originally opened the file.
pub fn cred(&self) -> CredentialRef<'_> {
// SAFETY: `File::ptr` is guaranteed to be valid by the type invariants.
let ptr = unsafe { (*self.ptr).f_cred };
// SAFETY: The lifetimes of `self` and `CredentialRef` are tied, so it is guaranteed that
// the credential pointer remains valid (because the file is still alive, and it doesn't
// change over the lifetime of a file).
unsafe { CredentialRef::from_ptr(ptr) }
}
}

impl Drop for File {
Expand Down
1 change: 1 addition & 0 deletions rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub mod amba;
pub mod buffer;
pub mod c_types;
pub mod chrdev;
pub mod cred;
pub mod device;
pub mod driver;
mod error;
Expand Down