Merge patch series "File abstractions needed by Rust Binder"

Alice Ryhl <aliceryhl@google.com> says:

This patchset contains the file abstractions needed by the Rust
implementation of the Binder driver.

Please see the Rust Binder RFC for usage examples:
https://lore.kernel.org/rust-for-linux/20231101-rust-binder-v1-0-08ba9197f637@google.com

Users of "rust: types: add `NotThreadSafe`":
	[PATCH 5/9] rust: file: add `FileDescriptorReservation`

Users of "rust: task: add `Task::current_raw`":
	[PATCH 7/9] rust: file: add `Kuid` wrapper
	[PATCH 8/9] rust: file: add `DeferredFdCloser`

Users of "rust: file: add Rust abstraction for `struct file`":
	[PATCH RFC 02/20] rust_binder: add binderfs support to Rust binder
	[PATCH RFC 03/20] rust_binder: add threading support

Users of "rust: cred: add Rust abstraction for `struct cred`":
	[PATCH RFC 05/20] rust_binder: add nodes and context managers
	[PATCH RFC 06/20] rust_binder: add oneway transactions
	[PATCH RFC 11/20] rust_binder: send nodes in transaction
	[PATCH RFC 13/20] rust_binder: add BINDER_TYPE_FD support

Users of "rust: security: add abstraction for secctx":
	[PATCH RFC 06/20] rust_binder: add oneway transactions

Users of "rust: file: add `FileDescriptorReservation`":
	[PATCH RFC 13/20] rust_binder: add BINDER_TYPE_FD support
	[PATCH RFC 14/20] rust_binder: add BINDER_TYPE_FDA support

Users of "rust: file: add `Kuid` wrapper":
	[PATCH RFC 05/20] rust_binder: add nodes and context managers
	[PATCH RFC 06/20] rust_binder: add oneway transactions

Users of "rust: file: add abstraction for `poll_table`":
	[PATCH RFC 07/20] rust_binder: add epoll support

This patchset has some uses of read_volatile in place of READ_ONCE.
Please see the following rfc for context on this:
https://lore.kernel.org/all/20231025195339.1431894-1-boqun.feng@gmail.com/

* patches from https://lore.kernel.org/r/20240915-alice-file-v10-0-88484f7a3dcf@google.com:
  rust: file: add abstraction for `poll_table`
  rust: file: add `Kuid` wrapper
  rust: file: add `FileDescriptorReservation`
  rust: security: add abstraction for secctx
  rust: cred: add Rust abstraction for `struct cred`
  rust: file: add Rust abstraction for `struct file`
  rust: task: add `Task::current_raw`
  rust: types: add `NotThreadSafe`

Link: https://lore.kernel.org/r/20240915-alice-file-v10-0-88484f7a3dcf@google.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christian Brauner 2024-09-30 13:02:35 +02:00
commit 70d7f7dbd9
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
17 changed files with 965 additions and 12 deletions

View File

@ -1096,6 +1096,13 @@ EXPORT_SYMBOL(task_lookup_next_fdget_rcu);
* *
* The fput_needed flag returned by fget_light should be passed to the * The fput_needed flag returned by fget_light should be passed to the
* corresponding fput_light. * corresponding fput_light.
*
* (As an exception to rule 2, you can call filp_close between fget_light and
* fput_light provided that you capture a real refcount with get_file before
* the call to filp_close, and ensure that this real refcount is fput *after*
* the fput_light call.)
*
* See also the documentation in rust/kernel/file.rs.
*/ */
static inline struct fd __fget_light(unsigned int fd, fmode_t mask) static inline struct fd __fget_light(unsigned int fd, fmode_t mask)
{ {

View File

@ -10,14 +10,20 @@
#include <linux/blk-mq.h> #include <linux/blk-mq.h>
#include <linux/blk_types.h> #include <linux/blk_types.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/cred.h>
#include <linux/errname.h> #include <linux/errname.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/file.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/fs.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/mdio.h> #include <linux/mdio.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/pid_namespace.h>
#include <linux/poll.h>
#include <linux/refcount.h> #include <linux/refcount.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/security.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>

13
rust/helpers/cred.c Normal file
View File

@ -0,0 +1,13 @@
// 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);
}

12
rust/helpers/fs.c Normal file
View File

@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2024 Google LLC.
*/
#include <linux/fs.h>
struct file *rust_helper_get_file(struct file *f)
{
return get_file(f);
}

View File

@ -11,12 +11,15 @@
#include "bug.c" #include "bug.c"
#include "build_assert.c" #include "build_assert.c"
#include "build_bug.c" #include "build_bug.c"
#include "cred.c"
#include "err.c" #include "err.c"
#include "fs.c"
#include "kunit.c" #include "kunit.c"
#include "mutex.c" #include "mutex.c"
#include "page.c" #include "page.c"
#include "rbtree.c" #include "rbtree.c"
#include "refcount.c" #include "refcount.c"
#include "security.c"
#include "signal.c" #include "signal.c"
#include "slab.c" #include "slab.c"
#include "spinlock.c" #include "spinlock.c"

20
rust/helpers/security.c Normal file
View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/security.h>
#ifndef CONFIG_SECURITY
void rust_helper_security_cred_getsecid(const struct cred *c, u32 *secid)
{
security_cred_getsecid(c, secid);
}
int rust_helper_security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
return security_secid_to_secctx(secid, secdata, seclen);
}
void rust_helper_security_release_secctx(char *secdata, u32 seclen)
{
security_release_secctx(secdata, seclen);
}
#endif

View File

@ -17,3 +17,41 @@ void rust_helper_put_task_struct(struct task_struct *t)
{ {
put_task_struct(t); put_task_struct(t);
} }
kuid_t rust_helper_task_uid(struct task_struct *task)
{
return task_uid(task);
}
kuid_t rust_helper_task_euid(struct task_struct *task)
{
return task_euid(task);
}
#ifndef CONFIG_USER_NS
uid_t rust_helper_from_kuid(struct user_namespace *to, kuid_t uid)
{
return from_kuid(to, uid);
}
#endif /* CONFIG_USER_NS */
bool rust_helper_uid_eq(kuid_t left, kuid_t right)
{
return uid_eq(left, right);
}
kuid_t rust_helper_current_euid(void)
{
return current_euid();
}
struct user_namespace *rust_helper_current_user_ns(void)
{
return current_user_ns();
}
pid_t rust_helper_task_tgid_nr_ns(struct task_struct *tsk,
struct pid_namespace *ns)
{
return task_tgid_nr_ns(tsk, ns);
}

85
rust/kernel/cred.rs Normal file
View File

@ -0,0 +1,85 @@
// 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,
task::Kuid,
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() }
}
/// Get the id for this security context.
pub fn get_secid(&self) -> u32 {
let mut secid = 0;
// SAFETY: The invariants of this type ensures that the pointer is valid.
unsafe { bindings::security_cred_getsecid(self.0.get(), &mut secid) };
secid
}
/// Returns the effective UID of the given credential.
pub fn euid(&self) -> Kuid {
// 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.
Kuid::from_raw(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()) };
}
}

8
rust/kernel/fs.rs Normal file
View File

@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
//! Kernel file systems.
//!
//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h)
pub mod file;
pub use self::file::{File, LocalFile};

461
rust/kernel/fs/file.rs Normal file
View File

@ -0,0 +1,461 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2024 Google LLC.
//! Files and file descriptors.
//!
//! C headers: [`include/linux/fs.h`](srctree/include/linux/fs.h) and
//! [`include/linux/file.h`](srctree/include/linux/file.h)
use crate::{
bindings,
cred::Credential,
error::{code::*, Error, Result},
types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque},
};
use core::ptr;
/// Flags associated with a [`File`].
pub mod flags {
/// File is opened in append mode.
pub const O_APPEND: u32 = bindings::O_APPEND;
/// Signal-driven I/O is enabled.
pub const O_ASYNC: u32 = bindings::FASYNC;
/// Close-on-exec flag is set.
pub const O_CLOEXEC: u32 = bindings::O_CLOEXEC;
/// File was created if it didn't already exist.
pub const O_CREAT: u32 = bindings::O_CREAT;
/// Direct I/O is enabled for this file.
pub const O_DIRECT: u32 = bindings::O_DIRECT;
/// File must be a directory.
pub const O_DIRECTORY: u32 = bindings::O_DIRECTORY;
/// Like [`O_SYNC`] except metadata is not synced.
pub const O_DSYNC: u32 = bindings::O_DSYNC;
/// Ensure that this file is created with the `open(2)` call.
pub const O_EXCL: u32 = bindings::O_EXCL;
/// Large file size enabled (`off64_t` over `off_t`).
pub const O_LARGEFILE: u32 = bindings::O_LARGEFILE;
/// Do not update the file last access time.
pub const O_NOATIME: u32 = bindings::O_NOATIME;
/// File should not be used as process's controlling terminal.
pub const O_NOCTTY: u32 = bindings::O_NOCTTY;
/// If basename of path is a symbolic link, fail open.
pub const O_NOFOLLOW: u32 = bindings::O_NOFOLLOW;
/// File is using nonblocking I/O.
pub const O_NONBLOCK: u32 = bindings::O_NONBLOCK;
/// File is using nonblocking I/O.
///
/// This is effectively the same flag as [`O_NONBLOCK`] on all architectures
/// except SPARC64.
pub const O_NDELAY: u32 = bindings::O_NDELAY;
/// Used to obtain a path file descriptor.
pub const O_PATH: u32 = bindings::O_PATH;
/// Write operations on this file will flush data and metadata.
pub const O_SYNC: u32 = bindings::O_SYNC;
/// This file is an unnamed temporary regular file.
pub const O_TMPFILE: u32 = bindings::O_TMPFILE;
/// File should be truncated to length 0.
pub const O_TRUNC: u32 = bindings::O_TRUNC;
/// Bitmask for access mode flags.
///
/// # Examples
///
/// ```
/// use kernel::fs::file;
/// # fn do_something() {}
/// # let flags = 0;
/// if (flags & file::flags::O_ACCMODE) == file::flags::O_RDONLY {
/// do_something();
/// }
/// ```
pub const O_ACCMODE: u32 = bindings::O_ACCMODE;
/// File is read only.
pub const O_RDONLY: u32 = bindings::O_RDONLY;
/// File is write only.
pub const O_WRONLY: u32 = bindings::O_WRONLY;
/// File can be both read and written.
pub const O_RDWR: u32 = bindings::O_RDWR;
}
/// Wraps the kernel's `struct file`. Thread safe.
///
/// This represents an open file rather than a file on a filesystem. Processes generally reference
/// open files using file descriptors. However, file descriptors are not the same as files. A file
/// descriptor is just an integer that corresponds to a file, and a single file may be referenced
/// by multiple file descriptors.
///
/// # Refcounting
///
/// Instances of this type are reference-counted. The reference count is incremented by the
/// `fget`/`get_file` functions and decremented by `fput`. The Rust type `ARef<File>` represents a
/// pointer that owns a reference count on the file.
///
/// Whenever a process opens a file descriptor (fd), it stores a pointer to the file in its fd
/// table (`struct files_struct`). This pointer owns a reference count to the file, ensuring the
/// file isn't prematurely deleted while the file descriptor is open. In Rust terminology, the
/// pointers in `struct files_struct` are `ARef<File>` pointers.
///
/// ## Light refcounts
///
/// Whenever a process has an fd to a file, it may use something called a "light refcount" as a
/// performance optimization. Light refcounts are acquired by calling `fdget` and released with
/// `fdput`. The idea behind light refcounts is that if the fd is not closed between the calls to
/// `fdget` and `fdput`, then the refcount cannot hit zero during that time, as the `struct
/// files_struct` holds a reference until the fd is closed. This means that it's safe to access the
/// file even if `fdget` does not increment the refcount.
///
/// The requirement that the fd is not closed during a light refcount applies globally across all
/// threads - not just on the thread using the light refcount. For this reason, light refcounts are
/// only used when the `struct files_struct` is not shared with other threads, since this ensures
/// that other unrelated threads cannot suddenly start using the fd and close it. Therefore,
/// calling `fdget` on a shared `struct files_struct` creates a normal refcount instead of a light
/// refcount.
///
/// Light reference counts must be released with `fdput` before the system call returns to
/// userspace. This means that if you wait until the current system call returns to userspace, then
/// all light refcounts that existed at the time have gone away.
///
/// ### The file position
///
/// Each `struct file` has a position integer, which is protected by the `f_pos_lock` mutex.
/// However, if the `struct file` is not shared, then the kernel may avoid taking the lock as a
/// performance optimization.
///
/// The condition for avoiding the `f_pos_lock` mutex is different from the condition for using
/// `fdget`. With `fdget`, you may avoid incrementing the refcount as long as the current fd table
/// is not shared; it is okay if there are other fd tables that also reference the same `struct
/// file`. However, `fdget_pos` can only avoid taking the `f_pos_lock` if the entire `struct file`
/// is not shared, as different processes with an fd to the same `struct file` share the same
/// position.
///
/// To represent files that are not thread safe due to this optimization, the [`LocalFile`] type is
/// used.
///
/// ## Rust references
///
/// The reference type `&File` is similar to light refcounts:
///
/// * `&File` references don't own a reference count. They can only exist as long as the reference
/// count stays positive, and can only be created when there is some mechanism in place to ensure
/// this.
///
/// * The Rust borrow-checker normally ensures this by enforcing that the `ARef<File>` from which
/// a `&File` is created outlives the `&File`.
///
/// * Using the unsafe [`File::from_raw_file`] means that it is up to the caller to ensure that the
/// `&File` only exists while the reference count is positive.
///
/// * You can think of `fdget` as using an fd to look up an `ARef<File>` in the `struct
/// files_struct` and create an `&File` from it. The "fd cannot be closed" rule is like the Rust
/// rule "the `ARef<File>` must outlive the `&File`".
///
/// # Invariants
///
/// * All instances of this type are refcounted using the `f_count` field.
/// * There must not be any active calls to `fdget_pos` on this file that did not take the
/// `f_pos_lock` mutex.
#[repr(transparent)]
pub struct File {
inner: Opaque<bindings::file>,
}
// SAFETY: This file is known to not have any active `fdget_pos` calls that did not take the
// `f_pos_lock` mutex, so it is safe to transfer it between threads.
unsafe impl Send for File {}
// SAFETY: This file is known to not have any active `fdget_pos` calls that did not take the
// `f_pos_lock` mutex, so it is safe to access its methods from several threads in parallel.
unsafe impl Sync for File {}
// SAFETY: The type invariants guarantee that `File` is always ref-counted. This implementation
// makes `ARef<File>` own a normal refcount.
unsafe impl AlwaysRefCounted for File {
#[inline]
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
unsafe { bindings::get_file(self.as_ptr()) };
}
#[inline]
unsafe fn dec_ref(obj: ptr::NonNull<File>) {
// SAFETY: To call this method, the caller passes us ownership of a normal refcount, so we
// may drop it. The cast is okay since `File` has the same representation as `struct file`.
unsafe { bindings::fput(obj.cast().as_ptr()) }
}
}
/// Wraps the kernel's `struct file`. Not thread safe.
///
/// This type represents a file that is not known to be safe to transfer across thread boundaries.
/// To obtain a thread-safe [`File`], use the [`assume_no_fdget_pos`] conversion.
///
/// See the documentation for [`File`] for more information.
///
/// # Invariants
///
/// * All instances of this type are refcounted using the `f_count` field.
/// * If there is an active call to `fdget_pos` that did not take the `f_pos_lock` mutex, then it
/// must be on the same thread as this file.
///
/// [`assume_no_fdget_pos`]: LocalFile::assume_no_fdget_pos
pub struct LocalFile {
inner: Opaque<bindings::file>,
}
// SAFETY: The type invariants guarantee that `LocalFile` is always ref-counted. This implementation
// makes `ARef<File>` own a normal refcount.
unsafe impl AlwaysRefCounted for LocalFile {
#[inline]
fn inc_ref(&self) {
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
unsafe { bindings::get_file(self.as_ptr()) };
}
#[inline]
unsafe fn dec_ref(obj: ptr::NonNull<LocalFile>) {
// SAFETY: To call this method, the caller passes us ownership of a normal refcount, so we
// may drop it. The cast is okay since `File` has the same representation as `struct file`.
unsafe { bindings::fput(obj.cast().as_ptr()) }
}
}
impl LocalFile {
/// Constructs a new `struct file` wrapper from a file descriptor.
///
/// The file descriptor belongs to the current process, and there might be active local calls
/// to `fdget_pos` on the same file.
///
/// To obtain an `ARef<File>`, use the [`assume_no_fdget_pos`] function to convert.
///
/// [`assume_no_fdget_pos`]: LocalFile::assume_no_fdget_pos
#[inline]
pub fn fget(fd: u32) -> Result<ARef<LocalFile>, BadFdError> {
// SAFETY: FFI call, there are no requirements on `fd`.
let ptr = ptr::NonNull::new(unsafe { bindings::fget(fd) }).ok_or(BadFdError)?;
// SAFETY: `bindings::fget` created a refcount, and we pass ownership of it to the `ARef`.
//
// INVARIANT: This file is in the fd table on this thread, so either all `fdget_pos` calls
// are on this thread, or the file is shared, in which case `fdget_pos` calls took the
// `f_pos_lock` mutex.
Ok(unsafe { ARef::from_raw(ptr.cast()) })
}
/// Creates a reference to a [`LocalFile`] from a valid pointer.
///
/// # Safety
///
/// * The caller must ensure that `ptr` points at a valid file and that the file's refcount is
/// positive for the duration of 'a.
/// * The caller must ensure that if there is an active call to `fdget_pos` that did not take
/// the `f_pos_lock` mutex, then that call is on the current thread.
#[inline]
pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a LocalFile {
// SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the
// duration of 'a. The cast is okay because `File` is `repr(transparent)`.
//
// INVARIANT: The caller guarantees that there are no problematic `fdget_pos` calls.
unsafe { &*ptr.cast() }
}
/// Assume that there are no active `fdget_pos` calls that prevent us from sharing this file.
///
/// This makes it safe to transfer this file to other threads. No checks are performed, and
/// using it incorrectly may lead to a data race on the file position if the file is shared
/// with another thread.
///
/// This method is intended to be used together with [`LocalFile::fget`] when the caller knows
/// statically that there are no `fdget_pos` calls on the current thread. For example, you
/// might use it when calling `fget` from an ioctl, since ioctls usually do not touch the file
/// position.
///
/// # Safety
///
/// There must not be any active `fdget_pos` calls on the current thread.
#[inline]
pub unsafe fn assume_no_fdget_pos(me: ARef<LocalFile>) -> ARef<File> {
// INVARIANT: There are no `fdget_pos` calls on the current thread, and by the type
// invariants, if there is a `fdget_pos` call on another thread, then it took the
// `f_pos_lock` mutex.
//
// SAFETY: `LocalFile` and `File` have the same layout.
unsafe { ARef::from_raw(ARef::into_raw(me).cast()) }
}
/// Returns a raw pointer to the inner C struct.
#[inline]
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`].
#[inline]
pub fn flags(&self) -> u32 {
// This `read_volatile` is intended to correspond to a READ_ONCE call.
//
// SAFETY: The file is valid because the shared reference guarantees a nonzero refcount.
//
// FIXME(read_once): Replace with `read_once` when available on the Rust side.
unsafe { core::ptr::addr_of!((*self.as_ptr()).f_flags).read_volatile() }
}
}
impl File {
/// Creates a reference to a [`File`] from a valid pointer.
///
/// # Safety
///
/// * The caller must ensure that `ptr` points at a valid file and that the file's refcount is
/// positive for the duration of 'a.
/// * The caller must ensure that if there are active `fdget_pos` calls on this file, then they
/// took the `f_pos_lock` mutex.
#[inline]
pub unsafe fn from_raw_file<'a>(ptr: *const bindings::file) -> &'a File {
// SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the
// duration of 'a. The cast is okay because `File` is `repr(transparent)`.
//
// INVARIANT: The caller guarantees that there are no problematic `fdget_pos` calls.
unsafe { &*ptr.cast() }
}
}
// Make LocalFile methods available on File.
impl core::ops::Deref for File {
type Target = LocalFile;
#[inline]
fn deref(&self) -> &LocalFile {
// SAFETY: The caller provides a `&File`, and since it is a reference, it must point at a
// valid file for the desired duration.
//
// By the type invariants, there are no `fdget_pos` calls that did not take the
// `f_pos_lock` mutex.
unsafe { LocalFile::from_raw_file(self as *const File as *const bindings::file) }
}
}
/// A file descriptor reservation.
///
/// This allows the creation of a file descriptor in two steps: first, we reserve a slot for it,
/// then we commit or drop the reservation. The first step may fail (e.g., the current process ran
/// out of available slots), but commit and drop never fail (and are mutually exclusive).
///
/// Dropping the reservation happens in the destructor of this type.
///
/// # Invariants
///
/// The fd stored in this struct must correspond to a reserved file descriptor of the current task.
pub struct FileDescriptorReservation {
fd: u32,
/// Prevent values of this type from being moved to a different task.
///
/// The `fd_install` and `put_unused_fd` functions assume that the value of `current` is
/// unchanged since the call to `get_unused_fd_flags`. By adding this marker to this type, we
/// prevent it from being moved across task boundaries, which ensures that `current` does not
/// change while this value exists.
_not_send: NotThreadSafe,
}
impl FileDescriptorReservation {
/// Creates a new file descriptor reservation.
pub fn get_unused_fd_flags(flags: u32) -> Result<Self> {
// SAFETY: FFI call, there are no safety requirements on `flags`.
let fd: i32 = unsafe { bindings::get_unused_fd_flags(flags) };
if fd < 0 {
return Err(Error::from_errno(fd));
}
Ok(Self {
fd: fd as u32,
_not_send: NotThreadSafe,
})
}
/// Returns the file descriptor number that was reserved.
pub fn reserved_fd(&self) -> u32 {
self.fd
}
/// Commits the reservation.
///
/// The previously reserved file descriptor is bound to `file`. This method consumes the
/// [`FileDescriptorReservation`], so it will not be usable after this call.
pub fn fd_install(self, file: ARef<File>) {
// SAFETY: `self.fd` was previously returned by `get_unused_fd_flags`. We have not yet used
// the fd, so it is still valid, and `current` still refers to the same task, as this type
// cannot be moved across task boundaries.
//
// Furthermore, the file pointer is guaranteed to own a refcount by its type invariants,
// and we take ownership of that refcount by not running the destructor below.
// Additionally, the file is known to not have any non-shared `fdget_pos` calls, so even if
// this process starts using the file position, this will not result in a data race on the
// file position.
unsafe { bindings::fd_install(self.fd, file.as_ptr()) };
// `fd_install` consumes both the file descriptor and the file reference, so we cannot run
// the destructors.
core::mem::forget(self);
core::mem::forget(file);
}
}
impl Drop for FileDescriptorReservation {
fn drop(&mut self) {
// SAFETY: By the type invariants of this type, `self.fd` was previously returned by
// `get_unused_fd_flags`. We have not yet used the fd, so it is still valid, and `current`
// still refers to the same task, as this type cannot be moved across task boundaries.
unsafe { bindings::put_unused_fd(self.fd) };
}
}
/// Represents the `EBADF` error code.
///
/// Used for methods that can only fail with `EBADF`.
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct BadFdError;
impl From<BadFdError> for Error {
#[inline]
fn from(_: BadFdError) -> Error {
EBADF
}
}
impl core::fmt::Debug for BadFdError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.pad("EBADF")
}
}

View File

@ -30,10 +30,12 @@ pub mod alloc;
#[cfg(CONFIG_BLOCK)] #[cfg(CONFIG_BLOCK)]
pub mod block; pub mod block;
mod build_assert; mod build_assert;
pub mod cred;
pub mod device; pub mod device;
pub mod error; pub mod error;
#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
pub mod firmware; pub mod firmware;
pub mod fs;
pub mod init; pub mod init;
pub mod ioctl; pub mod ioctl;
#[cfg(CONFIG_KUNIT)] #[cfg(CONFIG_KUNIT)]
@ -45,6 +47,7 @@ pub mod page;
pub mod prelude; pub mod prelude;
pub mod print; pub mod print;
pub mod rbtree; pub mod rbtree;
pub mod security;
pub mod sizes; pub mod sizes;
mod static_assert; mod static_assert;
#[doc(hidden)] #[doc(hidden)]

74
rust/kernel/security.rs Normal file
View File

@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2024 Google LLC.
//! Linux Security Modules (LSM).
//!
//! C header: [`include/linux/security.h`](srctree/include/linux/security.h).
use crate::{
bindings,
error::{to_result, Result},
};
/// A security context string.
///
/// # Invariants
///
/// The `secdata` and `seclen` fields correspond to a valid security context as returned by a
/// successful call to `security_secid_to_secctx`, that has not yet been destroyed by calling
/// `security_release_secctx`.
pub struct SecurityCtx {
secdata: *mut core::ffi::c_char,
seclen: usize,
}
impl SecurityCtx {
/// Get the security context given its id.
pub fn from_secid(secid: u32) -> Result<Self> {
let mut secdata = core::ptr::null_mut();
let mut seclen = 0u32;
// SAFETY: Just a C FFI call. The pointers are valid for writes.
to_result(unsafe { bindings::security_secid_to_secctx(secid, &mut secdata, &mut seclen) })?;
// INVARIANT: If the above call did not fail, then we have a valid security context.
Ok(Self {
secdata,
seclen: seclen as usize,
})
}
/// Returns whether the security context is empty.
pub fn is_empty(&self) -> bool {
self.seclen == 0
}
/// Returns the length of this security context.
pub fn len(&self) -> usize {
self.seclen
}
/// Returns the bytes for this security context.
pub fn as_bytes(&self) -> &[u8] {
let ptr = self.secdata;
if ptr.is_null() {
debug_assert_eq!(self.seclen, 0);
// We can't pass a null pointer to `slice::from_raw_parts` even if the length is zero.
return &[];
}
// SAFETY: The call to `security_secid_to_secctx` guarantees that the pointer is valid for
// `seclen` bytes. Furthermore, if the length is zero, then we have ensured that the
// pointer is not null.
unsafe { core::slice::from_raw_parts(ptr.cast(), self.seclen) }
}
}
impl Drop for SecurityCtx {
fn drop(&mut self) {
// SAFETY: By the invariant of `Self`, this frees a pointer that came from a successful
// call to `security_secid_to_secctx` and has not yet been destroyed by
// `security_release_secctx`.
unsafe { bindings::security_release_secctx(self.secdata, self.seclen as u32) };
}
}

View File

@ -11,6 +11,7 @@ mod arc;
mod condvar; mod condvar;
pub mod lock; pub mod lock;
mod locked_by; mod locked_by;
pub mod poll;
pub use arc::{Arc, ArcBorrow, UniqueArc}; pub use arc::{Arc, ArcBorrow, UniqueArc};
pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};

View File

@ -6,8 +6,13 @@
//! spinlocks, raw spinlocks) to be provided with minimal effort. //! spinlocks, raw spinlocks) to be provided with minimal effort.
use super::LockClassKey; use super::LockClassKey;
use crate::{init::PinInit, pin_init, str::CStr, types::Opaque, types::ScopeGuard}; use crate::{
use core::{cell::UnsafeCell, marker::PhantomData, marker::PhantomPinned}; init::PinInit,
pin_init,
str::CStr,
types::{NotThreadSafe, Opaque, ScopeGuard},
};
use core::{cell::UnsafeCell, marker::PhantomPinned};
use macros::pin_data; use macros::pin_data;
pub mod mutex; pub mod mutex;
@ -139,7 +144,7 @@ impl<T: ?Sized, B: Backend> Lock<T, B> {
pub struct Guard<'a, T: ?Sized, B: Backend> { pub struct Guard<'a, T: ?Sized, B: Backend> {
pub(crate) lock: &'a Lock<T, B>, pub(crate) lock: &'a Lock<T, B>,
pub(crate) state: B::GuardState, pub(crate) state: B::GuardState,
_not_send: PhantomData<*mut ()>, _not_send: NotThreadSafe,
} }
// SAFETY: `Guard` is sync when the data protected by the lock is also sync. // SAFETY: `Guard` is sync when the data protected by the lock is also sync.
@ -191,7 +196,7 @@ impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
Self { Self {
lock, lock,
state, state,
_not_send: PhantomData, _not_send: NotThreadSafe,
} }
} }
} }

121
rust/kernel/sync/poll.rs Normal file
View File

@ -0,0 +1,121 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2024 Google LLC.
//! Utilities for working with `struct poll_table`.
use crate::{
bindings,
fs::File,
prelude::*,
sync::{CondVar, LockClassKey},
types::Opaque,
};
use core::ops::Deref;
/// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class.
#[macro_export]
macro_rules! new_poll_condvar {
($($name:literal)?) => {
$crate::sync::poll::PollCondVar::new(
$crate::optional_name!($($name)?), $crate::static_lock_class!()
)
};
}
/// Wraps the kernel's `struct poll_table`.
///
/// # Invariants
///
/// This struct contains a valid `struct poll_table`.
///
/// For a `struct poll_table` to be valid, its `_qproc` function must follow the safety
/// requirements of `_qproc` functions:
///
/// * The `_qproc` function is given permission to enqueue a waiter to the provided `poll_table`
/// during the call. Once the waiter is removed and an rcu grace period has passed, it must no
/// longer access the `wait_queue_head`.
#[repr(transparent)]
pub struct PollTable(Opaque<bindings::poll_table>);
impl PollTable {
/// Creates a reference to a [`PollTable`] from a valid pointer.
///
/// # Safety
///
/// The caller must ensure that for the duration of 'a, the pointer will point at a valid poll
/// table (as defined in the type invariants).
///
/// The caller must also ensure that the `poll_table` is only accessed via the returned
/// reference for the duration of 'a.
pub unsafe fn from_ptr<'a>(ptr: *mut bindings::poll_table) -> &'a mut PollTable {
// SAFETY: The safety requirements guarantee the validity of the dereference, while the
// `PollTable` type being transparent makes the cast ok.
unsafe { &mut *ptr.cast() }
}
fn get_qproc(&self) -> bindings::poll_queue_proc {
let ptr = self.0.get();
// SAFETY: The `ptr` is valid because it originates from a reference, and the `_qproc`
// field is not modified concurrently with this call since we have an immutable reference.
unsafe { (*ptr)._qproc }
}
/// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified
/// using the condition variable.
pub fn register_wait(&mut self, file: &File, cv: &PollCondVar) {
if let Some(qproc) = self.get_qproc() {
// SAFETY: The pointers to `file` and `self` need to be valid for the duration of this
// call to `qproc`, which they are because they are references.
//
// The `cv.wait_queue_head` pointer must be valid until an rcu grace period after the
// waiter is removed. The `PollCondVar` is pinned, so before `cv.wait_queue_head` can
// be destroyed, the destructor must run. That destructor first removes all waiters,
// and then waits for an rcu grace period. Therefore, `cv.wait_queue_head` is valid for
// long enough.
unsafe { qproc(file.as_ptr() as _, cv.wait_queue_head.get(), self.0.get()) };
}
}
}
/// A wrapper around [`CondVar`] that makes it usable with [`PollTable`].
///
/// [`CondVar`]: crate::sync::CondVar
#[pin_data(PinnedDrop)]
pub struct PollCondVar {
#[pin]
inner: CondVar,
}
impl PollCondVar {
/// Constructs a new condvar initialiser.
pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
pin_init!(Self {
inner <- CondVar::new(name, key),
})
}
}
// Make the `CondVar` methods callable on `PollCondVar`.
impl Deref for PollCondVar {
type Target = CondVar;
fn deref(&self) -> &CondVar {
&self.inner
}
}
#[pinned_drop]
impl PinnedDrop for PollCondVar {
fn drop(self: Pin<&mut Self>) {
// Clear anything registered using `register_wait`.
//
// SAFETY: The pointer points at a valid `wait_queue_head`.
unsafe { bindings::__wake_up_pollfree(self.inner.wait_queue_head.get()) };
// Wait for epoll items to be properly removed.
//
// SAFETY: Just an FFI call.
unsafe { bindings::synchronize_rcu() };
}
}

View File

@ -4,10 +4,13 @@
//! //!
//! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h). //! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h).
use crate::types::Opaque; use crate::{
bindings,
types::{NotThreadSafe, Opaque},
};
use core::{ use core::{
cmp::{Eq, PartialEq},
ffi::{c_int, c_long, c_uint}, ffi::{c_int, c_long, c_uint},
marker::PhantomData,
ops::Deref, ops::Deref,
ptr, ptr,
}; };
@ -94,7 +97,22 @@ unsafe impl Sync for Task {}
/// The type of process identifiers (PIDs). /// The type of process identifiers (PIDs).
type Pid = bindings::pid_t; type Pid = bindings::pid_t;
/// The type of user identifiers (UIDs).
#[derive(Copy, Clone)]
pub struct Kuid {
kuid: bindings::kuid_t,
}
impl Task { impl Task {
/// Returns a raw pointer to the current task.
///
/// It is up to the user to use the pointer correctly.
#[inline]
pub fn current_raw() -> *mut bindings::task_struct {
// SAFETY: Getting the current pointer is always safe.
unsafe { bindings::get_current() }
}
/// Returns a task reference for the currently executing task/thread. /// Returns a task reference for the currently executing task/thread.
/// ///
/// The recommended way to get the current task/thread is to use the /// The recommended way to get the current task/thread is to use the
@ -106,7 +124,7 @@ impl Task {
pub unsafe fn current() -> impl Deref<Target = Task> { pub unsafe fn current() -> impl Deref<Target = Task> {
struct TaskRef<'a> { struct TaskRef<'a> {
task: &'a Task, task: &'a Task,
_not_send: PhantomData<*mut ()>, _not_send: NotThreadSafe,
} }
impl Deref for TaskRef<'_> { impl Deref for TaskRef<'_> {
@ -117,15 +135,13 @@ impl Task {
} }
} }
// SAFETY: Just an FFI call with no additional safety requirements. let current = Task::current_raw();
let ptr = unsafe { bindings::get_current() };
TaskRef { TaskRef {
// SAFETY: If the current thread is still running, the current task is valid. Given // SAFETY: If the current thread is still running, the current task is valid. Given
// that `TaskRef` is not `Send`, we know it cannot be transferred to another thread // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread
// (where it could potentially outlive the caller). // (where it could potentially outlive the caller).
task: unsafe { &*ptr.cast() }, task: unsafe { &*current.cast() },
_not_send: PhantomData, _not_send: NotThreadSafe,
} }
} }
@ -148,12 +164,31 @@ impl Task {
unsafe { *ptr::addr_of!((*self.0.get()).pid) } unsafe { *ptr::addr_of!((*self.0.get()).pid) }
} }
/// Returns the UID of the given task.
pub fn uid(&self) -> Kuid {
// SAFETY: By the type invariant, we know that `self.0` is valid.
Kuid::from_raw(unsafe { bindings::task_uid(self.0.get()) })
}
/// Returns the effective UID of the given task.
pub fn euid(&self) -> Kuid {
// SAFETY: By the type invariant, we know that `self.0` is valid.
Kuid::from_raw(unsafe { bindings::task_euid(self.0.get()) })
}
/// Determines whether the given task has pending signals. /// Determines whether the given task has pending signals.
pub fn signal_pending(&self) -> bool { pub fn signal_pending(&self) -> bool {
// SAFETY: By the type invariant, we know that `self.0` is valid. // SAFETY: By the type invariant, we know that `self.0` is valid.
unsafe { bindings::signal_pending(self.0.get()) != 0 } unsafe { bindings::signal_pending(self.0.get()) != 0 }
} }
/// Returns the given task's pid in the current pid namespace.
pub fn pid_in_current_ns(&self) -> Pid {
// SAFETY: We know that `self.0.get()` is valid by the type invariant, and passing a null
// pointer as the namespace is correct for using the current namespace.
unsafe { bindings::task_tgid_nr_ns(self.0.get(), ptr::null_mut()) }
}
/// Wakes up the task. /// Wakes up the task.
pub fn wake_up(&self) { pub fn wake_up(&self) {
// SAFETY: By the type invariant, we know that `self.0.get()` is non-null and valid. // SAFETY: By the type invariant, we know that `self.0.get()` is non-null and valid.
@ -175,3 +210,43 @@ unsafe impl crate::types::AlwaysRefCounted for Task {
unsafe { bindings::put_task_struct(obj.cast().as_ptr()) } unsafe { bindings::put_task_struct(obj.cast().as_ptr()) }
} }
} }
impl Kuid {
/// Get the current euid.
#[inline]
pub fn current_euid() -> Kuid {
// SAFETY: Just an FFI call.
Self::from_raw(unsafe { bindings::current_euid() })
}
/// Create a `Kuid` given the raw C type.
#[inline]
pub fn from_raw(kuid: bindings::kuid_t) -> Self {
Self { kuid }
}
/// Turn this kuid into the raw C type.
#[inline]
pub fn into_raw(self) -> bindings::kuid_t {
self.kuid
}
/// Converts this kernel UID into a userspace UID.
///
/// Uses the namespace of the current task.
#[inline]
pub fn into_uid_in_current_ns(self) -> bindings::uid_t {
// SAFETY: Just an FFI call.
unsafe { bindings::from_kuid(bindings::current_user_ns(), self.kuid) }
}
}
impl PartialEq for Kuid {
#[inline]
fn eq(&self, other: &Kuid) -> bool {
// SAFETY: Just an FFI call.
unsafe { bindings::uid_eq(self.kuid, other.kuid) }
}
}
impl Eq for Kuid {}

View File

@ -532,3 +532,24 @@ unsafe impl AsBytes for str {}
// does not have any uninitialized portions either. // does not have any uninitialized portions either.
unsafe impl<T: AsBytes> AsBytes for [T] {} unsafe impl<T: AsBytes> AsBytes for [T] {}
unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {} unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {}
/// Zero-sized type to mark types not [`Send`].
///
/// Add this type as a field to your struct if your type should not be sent to a different task.
/// Since [`Send`] is an auto trait, adding a single field that is `!Send` will ensure that the
/// whole type is `!Send`.
///
/// If a type is `!Send` it is impossible to give control over an instance of the type to another
/// task. This is useful to include in types that store or reference task-local information. A file
/// descriptor is an example of such task-local information.
///
/// This type also makes the type `!Sync`, which prevents immutable access to the value from
/// several threads in parallel.
pub type NotThreadSafe = PhantomData<*mut ()>;
/// Used to construct instances of type [`NotThreadSafe`] similar to how `PhantomData` is
/// constructed.
///
/// [`NotThreadSafe`]: type@NotThreadSafe
#[allow(non_upper_case_globals)]
pub const NotThreadSafe: NotThreadSafe = PhantomData;