1. Overview
The FileIdentity.cpp implementation resolves policy paths into canonical, kernel-compatible device/inode identities and validates object type and trust ownership requirements before those identities are inserted into BPF maps.
The file integrates the following components, APIs, or runtime concepts:
- stat/lstat – filesystem metadata
- major()/minor() – device-number decomposition
- rootguard_shared.h –
rg_file_keylayout
2. Kernel Device Number Conversion
kernelDeviceNumber() converts a userspace dev_t into a 12-bit major plus 20-bit minor layout matching the kernel’s internal MKDEV representation used by inode->i_sb->s_dev.
Values outside the representable major/minor ranges are rejected instead of producing a mismatched BPF key.
3. Symlink and Type Validation
resolve() first calls lstat() and rejects symbolic links. It then calls stat() and accepts only regular files or directories. If requireRegularFile is true, directories are rejected as well.
4. Trusted Executable Ownership Checks
When requireRootOwnedAndNotWritable is enabled, the object must be owned by UID 0 and must not be writable by group or others. This protects privilege-trusted executable identities from configuration that points to a modifiable binary.
5. Resolved Identity
The returned structure contains kernel-format device number, inode, canonical path, permission bits masked to 07777, UID, GID, and file/directory type flags.
6. Runtime and Security Considerations
- No symlink policy identities: prevents policy redirection through symbolic links.
- Kernel/userspace key compatibility: device conversion is explicitly aligned with BPF map lookup semantics.
- Trust hardening: optional ownership/write checks are enforced before a binary can become privilege trusted.
