whyno-core 0.5.0

Permission check pipeline, fix engine, and state types
Documentation
//! Linux capability constants and bitmask helpers.
//!
//! Bit positions from `capabilities(7)`. Only the subset relevant
//! to DAC permission checking is defined here.

/// Bypass file read, write, and execute permission checks.
///
/// For regular files, execute is only bypassed when at least one
/// execute bit is set in `i_mode & 0o111`. For directories, always
/// bypasses search permission. Bit 1 in `CapEff`.
pub const CAP_DAC_OVERRIDE: u64 = 1 << 1;

/// Bypass file read permission checks and directory read/search checks.
///
/// Grants `open_by_handle_at(2)` access. independent of
/// `CAP_DAC_OVERRIDE` — neither is a superset of the other. bit 2.
pub const CAP_DAC_READ_SEARCH: u64 = 1 << 2;

/// Bypass permission checks on file ownership operations.
///
/// Chmod, chown, sticky bit enforcement, ACL modification. Bit 3.
pub const CAP_FOWNER: u64 = 1 << 3;

/// Make arbitrary changes to file UIDs and GIDs. Bit 0.
pub const CAP_CHOWN: u64 = 1 << 0;

/// Set and clear the immutable and append-only file attributes. Bit 9.
pub const CAP_LINUX_IMMUTABLE: u64 = 1 << 9;

/// Don't clear set-user-ID and set-group-ID mode bits when a file is modified.
///
/// Don't set the set-group-ID bit on a newly created file if the GID doesn't
/// match the caller's group membership. Bit 4.
pub const CAP_FSETID: u64 = 1 << 4;

/// Broad system administration capability.
///
/// Required for `trusted.*` and `security.*` xattr namespace operations. Bit 21.
pub const CAP_SYS_ADMIN: u64 = 1 << 21;

/// Returns true if the bitmask contains the given capability.
#[must_use]
pub fn has_cap(bitmask: u64, cap: u64) -> bool {
    bitmask & cap != 0
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn has_cap_detects_set_bit() {
        assert!(has_cap(CAP_DAC_OVERRIDE, CAP_DAC_OVERRIDE));
    }

    #[test]
    fn has_cap_returns_false_for_unset_bit() {
        assert!(!has_cap(0, CAP_DAC_OVERRIDE));
    }

    #[test]
    fn has_cap_detects_combined_bitmask() {
        let bitmask = CAP_DAC_OVERRIDE | CAP_FOWNER;
        assert!(has_cap(bitmask, CAP_FOWNER));
        assert!(!has_cap(bitmask, CAP_DAC_READ_SEARCH));
    }

    #[test]
    fn cap_dac_override_and_read_search_are_independent() {
        // neither is a superset of the other
        assert!(!has_cap(CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH));
        assert!(!has_cap(CAP_DAC_READ_SEARCH, CAP_DAC_OVERRIDE));
    }

    #[test]
    fn cap_fsetid_is_bit_4() {
        assert_eq!(CAP_FSETID, 1 << 4);
    }

    #[test]
    fn cap_sys_admin_is_bit_21() {
        assert_eq!(CAP_SYS_ADMIN, 1 << 21);
    }

    #[test]
    fn cap_fsetid_independent_of_fowner() {
        assert!(!has_cap(CAP_FOWNER, CAP_FSETID));
    }

    #[test]
    fn cap_sys_admin_independent_of_dac_override() {
        assert!(!has_cap(CAP_DAC_OVERRIDE, CAP_SYS_ADMIN));
    }
}