diff options
Diffstat (limited to 'rust/kernel/task.rs')
| -rw-r--r-- | rust/kernel/task.rs | 120 | 
1 files changed, 100 insertions, 20 deletions
| diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 55dff7e088bf..080599075875 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -4,10 +4,13 @@  //!  //! C header: [`include/linux/sched.h`](srctree/include/linux/sched.h). -use crate::types::Opaque; +use crate::{ +    bindings, +    types::{NotThreadSafe, Opaque}, +};  use core::{ +    cmp::{Eq, PartialEq},      ffi::{c_int, c_long, c_uint}, -    marker::PhantomData,      ops::Deref,      ptr,  }; @@ -94,7 +97,22 @@ unsafe impl Sync for Task {}  /// The type of process identifiers (PIDs).  type Pid = bindings::pid_t; +/// The type of user identifiers (UIDs). +#[derive(Copy, Clone)] +pub struct Kuid { +    kuid: bindings::kuid_t, +} +  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.      ///      /// 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> {          struct TaskRef<'a> {              task: &'a Task, -            _not_send: PhantomData<*mut ()>, +            _not_send: NotThreadSafe,          }          impl Deref for TaskRef<'_> { @@ -117,23 +135,27 @@ impl Task {              }          } -        // SAFETY: Just an FFI call with no additional safety requirements. -        let ptr = unsafe { bindings::get_current() }; - +        let current = Task::current_raw();          TaskRef {              // 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              // (where it could potentially outlive the caller). -            task: unsafe { &*ptr.cast() }, -            _not_send: PhantomData, +            task: unsafe { &*current.cast() }, +            _not_send: NotThreadSafe,          }      } +    /// Returns a raw pointer to the task. +    #[inline] +    pub fn as_ptr(&self) -> *mut bindings::task_struct { +        self.0.get() +    } +      /// Returns the group leader of the given task.      pub fn group_leader(&self) -> &Task { -        // SAFETY: By the type invariant, we know that `self.0` is a valid task. Valid tasks always -        // have a valid `group_leader`. -        let ptr = unsafe { *ptr::addr_of!((*self.0.get()).group_leader) }; +        // SAFETY: The group leader of a task never changes after initialization, so reading this +        // field is not a data race. +        let ptr = unsafe { *ptr::addr_of!((*self.as_ptr()).group_leader) };          // SAFETY: The lifetime of the returned task reference is tied to the lifetime of `self`,          // and given that a task has a reference to its group leader, we know it must be valid for @@ -143,23 +165,41 @@ impl Task {      /// Returns the PID of the given task.      pub fn pid(&self) -> Pid { -        // SAFETY: By the type invariant, we know that `self.0` is a valid task. Valid tasks always -        // have a valid pid. -        unsafe { *ptr::addr_of!((*self.0.get()).pid) } +        // SAFETY: The pid of a task never changes after initialization, so reading this field is +        // not a data race. +        unsafe { *ptr::addr_of!((*self.as_ptr()).pid) } +    } + +    /// Returns the UID of the given task. +    pub fn uid(&self) -> Kuid { +        // SAFETY: It's always safe to call `task_uid` on a valid task. +        Kuid::from_raw(unsafe { bindings::task_uid(self.as_ptr()) }) +    } + +    /// Returns the effective UID of the given task. +    pub fn euid(&self) -> Kuid { +        // SAFETY: It's always safe to call `task_euid` on a valid task. +        Kuid::from_raw(unsafe { bindings::task_euid(self.as_ptr()) })      }      /// Determines whether the given task has pending signals.      pub fn signal_pending(&self) -> bool { -        // SAFETY: By the type invariant, we know that `self.0` is valid. -        unsafe { bindings::signal_pending(self.0.get()) != 0 } +        // SAFETY: It's always safe to call `signal_pending` on a valid task. +        unsafe { bindings::signal_pending(self.as_ptr()) != 0 } +    } + +    /// Returns the given task's pid in the current pid namespace. +    pub fn pid_in_current_ns(&self) -> Pid { +        // SAFETY: It's valid to pass a null pointer as the namespace (defaults to current +        // namespace). The task pointer is also valid. +        unsafe { bindings::task_tgid_nr_ns(self.as_ptr(), ptr::null_mut()) }      }      /// Wakes up the task.      pub fn wake_up(&self) { -        // SAFETY: By the type invariant, we know that `self.0.get()` is non-null and valid. -        // And `wake_up_process` is safe to be called for any valid task, even if the task is +        // SAFETY: It's always safe to call `signal_pending` on a valid task, even if the task          // running. -        unsafe { bindings::wake_up_process(self.0.get()) }; +        unsafe { bindings::wake_up_process(self.as_ptr()) };      }  } @@ -167,7 +207,7 @@ impl Task {  unsafe impl crate::types::AlwaysRefCounted for Task {      fn inc_ref(&self) {          // SAFETY: The existence of a shared reference means that the refcount is nonzero. -        unsafe { bindings::get_task_struct(self.0.get()) }; +        unsafe { bindings::get_task_struct(self.as_ptr()) };      }      unsafe fn dec_ref(obj: ptr::NonNull<Self>) { @@ -175,3 +215,43 @@ unsafe impl crate::types::AlwaysRefCounted for Task {          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 {} | 
