Rewrite `Credentials` comments

This commit is contained in:
Ruihan Li 2026-02-04 23:37:11 +08:00 committed by Jianfeng Jiang
parent 744e95a819
commit dd25a8ad62
5 changed files with 141 additions and 102 deletions

View File

@ -61,24 +61,29 @@ impl CapSet {
self.bits() as u32
}
/// Creates a new `CapSet` with a full capability set, typically for a root user.
/// Creates a new `CapSet` with full capabilities, typically for a root user.
pub const fn new_root() -> Self {
CapSet::all()
}
/// The most significant bit in a 64-bit `CapSet` that may be set to represent a Linux capability.
/// Returns the most significant bit in a 64-bit `CapSet` that may be set to represent a Linux
/// capability.
pub const fn most_significant_bit() -> u8 {
// CHECKPOINT_RESTORE is the Linux capability with the largest numerical value
// CHECKPOINT_RESTORE is the Linux capability with the largest numerical value.
40
}
}
/// An error occurred when converting invalid bits to a [`CapSet`].
#[derive(Debug)]
pub struct InvalidCapSetError;
impl TryFrom<u64> for CapSet {
type Error = &'static str;
type Error = InvalidCapSetError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
if value & !CapSet::MASK != 0 {
Err("Invalid CapSet.")
Err(InvalidCapSetError)
} else {
Ok(CapSet { bits: value })
}

View File

@ -14,48 +14,68 @@ use crate::{
#[derive(Debug)]
pub(super) struct Credentials_ {
/// Real user id. The user to which the process belongs.
/// The real user ID.
///
/// This is the user to which the process belongs.
ruid: AtomicUid,
/// Effective user id. Used to determine the permissions granted to a process when it tries to perform various operations (i.e., system calls)
/// The effective user ID.
///
/// This is used to determine the permissions granted to a process when it tries to perform
/// various operations (e.g., system calls).
euid: AtomicUid,
/// Saved-set uid. Used by set_uid elf, the saved_set_uid will be set if the elf has setuid bit
/// The saved-set user ID.
///
/// This saves a copy of the effective user ID that were set when the program was executed.
suid: AtomicUid,
/// User id used for filesystem checks.
/// The filesystem user ID.
///
/// This is used to determine permissions for accessing files.
fsuid: AtomicUid,
/// Real group id. The group to which the process belongs
/// The real group ID.
///
/// This is the group to which the process belongs.
rgid: AtomicGid,
/// Effective gid,
/// The effective group ID.
///
/// This is used to determine the permissions granted to a process when it tries to perform
/// various operations (e.g., system calls).
egid: AtomicGid,
/// Saved-set gid. Used by set_gid elf, the saved_set_gid will be set if the elf has setgid bit
/// The saved-set group ID.
///
/// This saves a copy of the effective group ID that were set when the program was executed.
sgid: AtomicGid,
/// Group id used for file system checks.
/// The filesystem group ID.
///
/// This is used to determine permissions for accessing files.
fsgid: AtomicGid,
/// A set of additional groups to which a process belongs.
supplementary_gids: RwLock<BTreeSet<Gid>>,
/// The Linux capabilities.
///
/// This is not the capability (in static_cap.rs) enforced on rust objects.
/// Capability that child processes can inherit
// The Linux capabilities. They are not the capability (in `static_cap.rs`) that is enforced on
// Rust objects.
//
/// Capabilities that child processes can inherit.
inheritable_capset: AtomicCapSet,
/// Capabilities that a process can potentially be granted.
/// It defines the maximum set of privileges that the process could possibly have.
/// Even if the process is not currently using these privileges, it has the potential ability to enable them.
///
/// It defines the maximum set of privileges that the process could possibly have. Even if the
/// process is not currently using these privileges, it has the potential ability to enable
/// them.
permitted_capset: AtomicCapSet,
/// Capability that we can actually use
/// Capabilities that we can actually use.
effective_capset: AtomicCapSet,
/// Secure bits flags
/// Secure bits.
securebits: AtomicSecureBits,
}
impl Credentials_ {
/// Create a new credentials. ruid, euid, suid will be set as the same uid, and gid is the same.
pub fn new(uid: Uid, gid: Gid, capset: CapSet) -> Self {
/// Creates a new `Credentials_`.
///
/// The real, effective, saved set, and filesystem IDs will be initialized to the same ID.
pub(super) fn new(uid: Uid, gid: Gid, capset: CapSet) -> Self {
let mut supplementary_gids = BTreeSet::new();
supplementary_gids.insert(gid);
@ -76,7 +96,7 @@ impl Credentials_ {
}
}
// ******* Uid methods *******
// ******* UID methods *******
pub(super) fn ruid(&self) -> Uid {
self.ruid.load(Ordering::Relaxed)
@ -160,8 +180,8 @@ impl Credentials_ {
self.set_resuid_unchecked(None, None, Some(suid));
}
// For `setreuid`, ruid can *NOT* be set to old suid,
// while for `setresuid`, ruid can be set to old suid.
// For `setreuid`, the real UID can *NOT* be set to the old saved-set user ID,
// For `setresuid`, the real UID can be set to the old saved-set user ID.
fn check_uid_perm(
&self,
ruid: Option<&Uid>,
@ -180,7 +200,7 @@ impl Credentials_ {
{
return_errno_with_message!(
Errno::EPERM,
"ruid can only be one of old ruid, old euid (and old suid)."
"the new real UID is not one of the associated UIDs"
);
}
@ -191,7 +211,7 @@ impl Credentials_ {
{
return_errno_with_message!(
Errno::EPERM,
"euid can only be one of old ruid, old euid and old suid."
"the new effective UID is not one of the associated UIDs"
)
}
@ -202,7 +222,7 @@ impl Credentials_ {
{
return_errno_with_message!(
Errno::EPERM,
"suid can only be one of old ruid, old euid and old suid."
"the new saved-set UID is not one of the associated UIDs"
)
}
@ -285,7 +305,7 @@ impl Credentials_ {
}
}
// ******* Gid methods *******
// ******* GID methods *******
pub(super) fn rgid(&self) -> Gid {
self.rgid.load(Ordering::Relaxed)
@ -373,8 +393,8 @@ impl Credentials_ {
self.set_resgid_unchecked(None, None, Some(sgid));
}
// For `setregid`, rgid can *NOT* be set to old sgid,
// while for `setresgid`, ruid can be set to old sgid.
// For `setregid`, the real GID can *NOT* be set to old saved-set GID,
// For `setresgid`, the real GID can be set to the old saved-set GID.
fn check_gid_perm(
&self,
rgid: Option<&Gid>,
@ -393,7 +413,7 @@ impl Credentials_ {
{
return_errno_with_message!(
Errno::EPERM,
"rgid can only be one of old rgid, old egid (and old sgid)."
"the new real GID is not one of the associated GIDs"
);
}
@ -404,7 +424,7 @@ impl Credentials_ {
{
return_errno_with_message!(
Errno::EPERM,
"egid can only be one of old rgid, old egid and old sgid."
"the new effective GID is not one of the associated GIDs"
)
}
@ -415,7 +435,7 @@ impl Credentials_ {
{
return_errno_with_message!(
Errno::EPERM,
"sgid can only be one of old rgid, old egid and old sgid."
"the new saved-set GID is not one of the associated GIDs"
)
}
@ -442,7 +462,7 @@ impl Credentials_ {
self.fsgid.store(fsuid, Ordering::Relaxed);
}
// ******* Supplementary groups methods *******
// ******* Supplementary Groups methods *******
pub(super) fn groups(&self) -> RwLockReadGuard<'_, BTreeSet<Gid>, PreemptDisabled> {
self.supplementary_gids.read()
@ -452,7 +472,7 @@ impl Credentials_ {
self.supplementary_gids.write()
}
// ******* Linux Capability methods *******
// ******* Linux Capabilities methods *******
pub(super) fn inheritable_capset(&self) -> CapSet {
self.inheritable_capset.load(Ordering::Relaxed)
@ -496,7 +516,7 @@ impl Credentials_ {
self.securebits.try_store(stored_bits, Ordering::Relaxed)
}
// ******* SecureBits methods *******
// ******* Secure Bits methods *******
pub(super) fn securebits(&self) -> SecureBits {
self.securebits.load(Ordering::Relaxed)
@ -506,7 +526,7 @@ impl Credentials_ {
if !self.effective_capset().contains(CapSet::SETPCAP) {
return_errno_with_message!(
Errno::EPERM,
"only threads with CAP_SETPCAP can change securebits"
"only threads with CAP_SETPCAP can change secure bits"
);
}

View File

@ -16,13 +16,14 @@ pub use user::Uid;
use crate::prelude::*;
/// `Credentials` represents a set of associated numeric user ids (UIDs) and group identifiers (GIDs)
/// for a process.
/// These identifiers are as follows:
/// A set of associated numeric user IDs (UIDs) and group IDs (GIDs) for a process.
///
/// This type contains:
/// - real user ID and group ID;
/// - effective user ID and group ID;
/// - saved-set user ID and saved-set group ID;
/// - file system user ID and group ID (Linux-specific);
/// - filesystem user ID and group ID (Linux-specific);
/// - supplementary group IDs;
/// - Linux capabilities.
/// - Linux capabilities;
/// - secure bits.
pub struct Credentials<R = FullOp>(Arc<Credentials_>, R);

View File

@ -8,36 +8,33 @@ use bitflags::bitflags;
use crate::prelude::*;
bitflags! {
/// Represents the secure bits flags for a POSIX thread.
/// Represents the secure bits for a POSIX thread.
///
/// These flags control the behavior of capabilities when changing UIDs.
///
/// Reference: <https://man7.org/linux/man-pages/man7/capabilities.7.html>
pub struct SecureBits: u16 {
/// If set, the kernel does not grant capabilities when a set-user-ID-root program
/// is executed, or when a process with an effective or real UID of 0 calls `execve`.
const NOROOT = 1 << 0;
/// Make `NOROOT` bit immutable (irreversible).
const NOROOT_LOCKED = 1 << 1;
/// If set, the kernel does not adjust the process's permitted, effective, and
/// ambient capability sets when the UIDs are switched between zero and nonzero values.
const NO_SETUID_FIXUP = 1 << 2;
/// Make `NO_SETUID_FIXUP` bit immutable (irreversible).
const NO_SETUID_FIXUP_LOCKED = 1 << 3;
/// If set, the kernel preserves permitted capabilities across UID changes,
/// specifically when all UIDs transition from root (0) to non-root values.
const KEEP_CAPS = 1 << 4;
/// Make `KEEP_CAPS` bit immutable (irreversible).
const KEEP_CAPS_LOCKED = 1 << 5;
/// If set, the kernel will not permit raising ambient capabilities via the
/// prctl PR_CAP_AMBIENT_RAISE operation.
const NO_CAP_AMBIENT_RAISE = 1 << 6;
/// Make `NO_CAP_AMBIENT_RAISE` bit immutable (irreversible).
const NO_CAP_AMBIENT_RAISE_LOCKED = 1 << 7;
}
@ -72,7 +69,7 @@ impl TryFrom<u16> for SecureBits {
fn try_from(value: u16) -> Result<Self> {
if value & !SecureBits::ALL_VALID_BITS != 0 {
return_errno_with_message!(Errno::EINVAL, "invalid SecureBits value");
return_errno_with_message!(Errno::EINVAL, "the bits are not valid secure bits");
}
#[cfg(debug_assertions)]
@ -140,11 +137,11 @@ impl AtomicSecureBits {
let locked_bits = current.locked_bits();
if locked_bits & current != locked_bits & bits {
return_errno_with_message!(Errno::EPERM, "one or more SecureBits are locked");
return_errno_with_message!(Errno::EPERM, "one or more secure bits are locked");
}
if SecureBits::LOCK_MASK & current.bits() & !bits.bits() != 0 {
return_errno_with_message!(Errno::EPERM, "cannot unlock the lock bits");
return_errno_with_message!(Errno::EPERM, "locked secure bits cannot be unlocked");
}
self.inner.store(bits, ordering);

View File

@ -8,7 +8,9 @@ use super::{Credentials, Gid, SecureBits, Uid, capabilities::CapSet, credentials
use crate::prelude::*;
impl<R: TRights> Credentials<R> {
/// Creates a root `Credentials`. This method can only be used when creating the first process
/// Creates a root `Credentials`.
///
/// This method can only be used when creating the init process.
pub fn new_root() -> Self {
let uid = Uid::new_root();
let gid = Gid::new_root();
@ -43,9 +45,9 @@ impl<R: TRights> Credentials<R> {
Credentials(credentials_, R1::new())
}
// *********** Uid methods **********
// *********** UID methods **********
/// Gets real user id.
/// Gets the real user ID.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -53,7 +55,7 @@ impl<R: TRights> Credentials<R> {
self.0.ruid()
}
/// Gets effective user id.
/// Gets the effective user ID.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -61,7 +63,7 @@ impl<R: TRights> Credentials<R> {
self.0.euid()
}
/// Gets saved-set user id.
/// Gets the saved-set user ID.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -69,7 +71,7 @@ impl<R: TRights> Credentials<R> {
self.0.suid()
}
/// Gets file system user id.
/// Gets the filesystem user ID.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -77,8 +79,10 @@ impl<R: TRights> Credentials<R> {
self.0.fsuid()
}
/// Sets uid. If self is privileged, sets the effective, real, saved-set user ids as `uid`,
/// Otherwise, sets effective user id as `uid`.
/// Sets the user ID.
///
/// If `self` is privileged, sets the real, effective, saved-set user IDs as `uid`, Otherwise,
/// sets the effective user ID as `uid`.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -86,8 +90,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_uid(uid)
}
/// Sets real, effective user ids as `ruid`, `euid` respectively. if `ruid` or `euid`
/// is `None`, the corresponding user id will leave unchanged.
/// Sets the real, effective user IDs as `ruid`, `euid` respectively.
///
/// If `ruid` or `euid` is `None`, the corresponding user ID will leave unchanged.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -95,8 +100,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_reuid(ruid, euid)
}
/// Sets real, effective, saved-set user ids as `ruid`, `euid`, `suid` respectively. if
/// `ruid`, `euid` or `suid` is `None`, the corresponding user id will leave unchanged.
/// Sets the real, effective, saved-set user IDs as `ruid`, `euid`, `suid` respectively.
///
/// If `ruid`, `euid`, or `suid` is `None`, the corresponding user ID will leave unchanged.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -109,8 +115,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_resuid(ruid, euid, suid)
}
/// Sets file system user id as `fsuid`. Returns the original file system user id.
/// If `fsuid` is None, leaves file system user id unchanged.
/// Sets the filesystem user ID as `fsuid` and returns the original filesystem user ID.
///
/// If `fsuid` is `None`, leaves the filesystem user ID unchanged.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -118,8 +125,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_fsuid(fsuid)
}
/// Sets effective user id as `euid`. This method should only be used when executing a file
/// whose `setuid` bit is set.
/// Sets the effective user ID as `euid`.
///
/// This method should only be used when executing a file whose `setuid` bit is set.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -127,8 +135,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_euid(euid);
}
/// Sets saved-set user id as the same of effective user id. This method should only be used when
/// executing a new executable file.
/// Sets the saved-set user ID as the same of the effective user ID.
///
/// This method should only be used when executing a new executable file.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -137,9 +146,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_suid(euid);
}
// *********** Gid methods **********
// *********** GID methods **********
/// Gets real group id.
/// Gets the real group ID.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -147,7 +156,7 @@ impl<R: TRights> Credentials<R> {
self.0.rgid()
}
/// Gets effective group id.
/// Gets the effective group ID.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -155,7 +164,7 @@ impl<R: TRights> Credentials<R> {
self.0.egid()
}
/// Gets saved-set group id.
/// Gets the saved-set group ID.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -163,7 +172,7 @@ impl<R: TRights> Credentials<R> {
self.0.sgid()
}
/// Gets file system group id.
/// Gets the filesystem group ID.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -171,8 +180,10 @@ impl<R: TRights> Credentials<R> {
self.0.fsgid()
}
/// Sets gid. If self is privileged, sets the effective, real, saved-set group ids as `gid`,
/// Otherwise, sets effective group id as `gid`.
/// Sets the group ID.
///
/// If `self` is privileged, sets the real, effective, saved-set group IDs as `gid`, Otherwise,
/// sets the effective group ID as `gid`.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -180,8 +191,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_gid(gid)
}
/// Sets real, effective group ids as `rgid`, `egid` respectively. if `rgid` or `egid`
/// is `None`, the corresponding group id will leave unchanged.
/// Sets the real, effective group IDs as `rgid`, `egid` respectively.
///
/// If `rgid` or `egid` is `None`, the corresponding group ID will leave unchanged.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -189,8 +201,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_regid(rgid, egid)
}
/// Sets real, effective, saved-set group ids as `rgid`, `egid`, `sgid` respectively. if
/// `rgid`, `egid` or `sgid` is `None`, the corresponding group id will leave unchanged.
/// Sets the real, effective, saved-set group IDs as `rgid`, `egid`, `sgid` respectively.
///
/// If `rgid`, `egid`, or `sgid` is `None`, the corresponding group ID will leave unchanged.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -203,8 +216,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_resgid(rgid, egid, sgid)
}
/// Sets file system group id as `fsgid`. Returns the original file system group id.
/// If `fsgid` is None, leaves file system group id unchanged.
/// Sets the filesystem group ID as `fsgid` and returns the original filesystem group ID.
///
/// If `fsgid` is `None`, leaves the filesystem group ID unchanged.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -212,8 +226,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_fsgid(fsgid)
}
/// Sets effective group id as `egid`. This method should only be used when executing a file
/// whose `setgid` bit is set.
/// Sets the effective group ID as `egid`.
///
/// This method should only be used when executing a file whose `setgid` bit is set.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -221,8 +236,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_egid(egid);
}
/// Sets saved-set group id as the same of effective group id. This method should only be used when
/// executing a new executable file.
/// Sets the saved-set group ID as the same of the effective group ID.
///
/// This method should only be used when executing a new executable file.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -231,9 +247,9 @@ impl<R: TRights> Credentials<R> {
self.0.set_sgid(egid);
}
// *********** Supplementary group methods **********
// *********** Supplementary Groups methods **********
/// Acquires the read lock of supplementary group ids.
/// Acquires the read lock of supplementary group IDs.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -241,7 +257,7 @@ impl<R: TRights> Credentials<R> {
self.0.groups()
}
/// Acquires the write lock of supplementary group ids.
/// Acquires the write lock of supplementary group IDs.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -249,9 +265,9 @@ impl<R: TRights> Credentials<R> {
self.0.groups_mut()
}
// *********** Linux Capability methods **********
// *********** Linux Capabilities methods **********
/// Gets the capabilities that child process can inherit.
/// Gets the capabilities that child processes can inherit.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -259,7 +275,7 @@ impl<R: TRights> Credentials<R> {
self.0.inheritable_capset()
}
/// Gets the capabilities that are permitted.
/// Gets the capabilities that are a process can potentially be granted.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -267,7 +283,7 @@ impl<R: TRights> Credentials<R> {
self.0.permitted_capset()
}
/// Gets the capabilities that actually use.
/// Gets the capabilities that we can actually use.
///
/// This method requires the `Read` right.
#[require(R > Read)]
@ -275,7 +291,7 @@ impl<R: TRights> Credentials<R> {
self.0.effective_capset()
}
/// Sets the capabilities that child process can inherit.
/// Sets the capabilities that child processes can inherit.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -283,7 +299,7 @@ impl<R: TRights> Credentials<R> {
self.0.set_inheritable_capset(inheritable_capset);
}
/// Sets the capabilities that are permitted.
/// Sets the capabilities that are a process can potentially be granted.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -291,7 +307,7 @@ impl<R: TRights> Credentials<R> {
self.0.set_permitted_capset(permitted_capset);
}
/// Sets the capabilities that actually use.
/// Sets the capabilities that we can actually use.
///
/// This method requires the `Write` right.
#[require(R > Write)]
@ -317,7 +333,7 @@ impl<R: TRights> Credentials<R> {
self.0.set_keep_capabilities(keep_capabilities)
}
// *********** SecureBits methods **********
// *********** Secure Bits methods **********
/// Gets the secure bits.
///
@ -329,8 +345,8 @@ impl<R: TRights> Credentials<R> {
/// Sets the secure bits.
///
/// If the caller does not have the `CAP_SETPCAP` capability, or if it tries to set
/// locked bits, this method will return an error.
/// If the caller does not have the `CAP_SETPCAP` capability, or if it tries to set locked
/// bits, this method will return an error.
///
/// This method requires the `Write` right.
#[require(R > Write)]