Unverified Commit a3df991d authored by Wedson Almeida Filho's avatar Wedson Almeida Filho Committed by Christian Brauner
Browse files

rust: cred: add Rust abstraction for `struct cred`



Add a wrapper around `struct cred` called `Credential`, and provide
functionality to get the `Credential` associated with a `File`.

Rust Binder must check the credentials of processes when they attempt to
perform various operations, and these checks usually take a
`&Credential` as parameter. The security_binder_set_context_mgr function
would be one example. This patch is necessary to access these security_*
methods from Rust.

This Rust abstraction makes the following assumptions about the C side:
* `struct cred` is refcounted with `get_cred`/`put_cred`.
* It's okay to transfer a `struct cred` across threads, that is, you do
  not need to call `put_cred` on the same thread as where you called
  `get_cred`.
* The `euid` field of a `struct cred` never changes after
  initialization.
* The `f_cred` field of a `struct file` never changes after
  initialization.

Signed-off-by: default avatarWedson Almeida Filho <wedsonaf@gmail.com>
Co-developed-by: default avatarAlice Ryhl <aliceryhl@google.com>
Reviewed-by: default avatarTrevor Gross <tmgross@umich.edu>
Reviewed-by: default avatarBenno Lossin <benno.lossin@proton.me>
Reviewed-by: default avatarMartin Rodriguez Reboredo <yakoyoku@gmail.com>
Reviewed-by: default avatarGary Guo <gary@garyguo.net>
Signed-off-by: default avatarAlice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240915-alice-file-v10-4-88484f7a3dcf@google.com


Reviewed-by: default avatarKees Cook <kees@kernel.org>
Reviewed-by: default avatarPaul Moore <paul@paul-moore.com>
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 85184982
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/blk-mq.h>
#include <linux/blk_types.h>
#include <linux/blkdev.h>
#include <linux/cred.h>
#include <linux/errname.h>
#include <linux/ethtool.h>
#include <linux/file.h>

rust/helpers/cred.c

0 → 100644
+13 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

#include <linux/cred.h>

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

void rust_helper_put_cred(const struct cred *cred)
{
	put_cred(cred);
}
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include "bug.c"
#include "build_assert.c"
#include "build_bug.c"
#include "cred.c"
#include "err.c"
#include "fs.c"
#include "kunit.c"

rust/kernel/cred.rs

0 → 100644
+76 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0

// Copyright (C) 2024 Google LLC.

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

use crate::{
    bindings,
    types::{AlwaysRefCounted, Opaque},
};

/// Wraps the kernel's `struct cred`.
///
/// Credentials are used for various security checks in the kernel.
///
/// Most fields of credentials are immutable. When things have their credentials changed, that
/// happens by replacing the credential instead of changing an existing credential. See the [kernel
/// documentation][ref] for more info on this.
///
/// # Invariants
///
/// Instances of this type are always ref-counted, that is, a call to `get_cred` ensures that the
/// allocation remains valid at least until the matching call to `put_cred`.
///
/// [ref]: https://www.kernel.org/doc/html/latest/security/credentials.html
#[repr(transparent)]
pub struct Credential(Opaque<bindings::cred>);

// SAFETY:
// - `Credential::dec_ref` can be called from any thread.
// - It is okay to send ownership of `Credential` across thread boundaries.
unsafe impl Send for Credential {}

// SAFETY: It's OK to access `Credential` through shared references from other threads because
// we're either accessing properties that don't change or that are properly synchronised by C code.
unsafe impl Sync for Credential {}

impl Credential {
    /// Creates a reference to a [`Credential`] from a valid pointer.
    ///
    /// # Safety
    ///
    /// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
    /// returned [`Credential`] reference.
    pub unsafe fn from_ptr<'a>(ptr: *const bindings::cred) -> &'a Credential {
        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
        // `Credential` type being transparent makes the cast ok.
        unsafe { &*ptr.cast() }
    }

    /// Returns the effective UID of the given credential.
    pub fn euid(&self) -> bindings::kuid_t {
        // SAFETY: By the type invariant, we know that `self.0` is valid. Furthermore, the `euid`
        // field of a credential is never changed after initialization, so there is no potential
        // for data races.
        unsafe { (*self.0.get()).euid }
    }
}

// SAFETY: The type invariants guarantee that `Credential` is always ref-counted.
unsafe impl AlwaysRefCounted for Credential {
    fn inc_ref(&self) {
        // SAFETY: The existence of a shared reference means that the refcount is nonzero.
        unsafe { bindings::get_cred(self.0.get()) };
    }

    unsafe fn dec_ref(obj: core::ptr::NonNull<Credential>) {
        // SAFETY: The safety requirements guarantee that the refcount is nonzero. The cast is okay
        // because `Credential` has the same representation as `struct cred`.
        unsafe { bindings::put_cred(obj.cast().as_ptr()) };
    }
}
+13 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@

use crate::{
    bindings,
    cred::Credential,
    error::{code::*, Error, Result},
    types::{ARef, AlwaysRefCounted, Opaque},
};
@@ -308,6 +309,18 @@ pub fn as_ptr(&self) -> *mut bindings::file {
        self.inner.get()
    }

    /// Returns the credentials of the task that originally opened the file.
    pub fn cred(&self) -> &Credential {
        // SAFETY: It's okay to read the `f_cred` field without synchronization because `f_cred` is
        // never changed after initialization of the file.
        let ptr = unsafe { (*self.as_ptr()).f_cred };

        // SAFETY: The signature of this function ensures that the caller will only access the
        // returned credential while the file is still valid, and the C side ensures that the
        // credential stays valid at least as long as the file.
        unsafe { Credential::from_ptr(ptr) }
    }

    /// Returns the flags associated with the file.
    ///
    /// The flags are a combination of the constants in [`flags`].
Loading