3.4.1 The Privilege Model

Some operations do not fit the subject-object model at all. Rebooting the machine, loading a kernel module, changing the system clock, creating a token — these affect the system itself rather than a specific protected resource, so there is nothing to attach a security descriptor to. They still need authorization.

Privileges fill that gap. A privilege is the right to perform a particular system operation, carried on the token beside the principal's identity. Where a descriptor says "this principal may read this file", a privilege says "this principal may shut down the system". The descriptor lives on the object; the privilege lives on the subject.

3.4.1.1 Lifecycle #

A privilege is assigned by policy when authd creates the token, resolving the principal's assignments from security policy once, at creation. There are no runtime grants: a privilege absent at creation can never be added later.

The privilege then sits on the token in whatever enabled state it was created with. The kernel accepts any enabled set that is a subset of the present set, and takes the creation-time enabled set as the enabled-by-default set. authd issues every privilege it grants already enabled, on the reasoning that a privilege the holder had to enable before it worked would be a grant in name only — so the present-but-disabled resting state exists in the model and is reachable through AdjustPrivileges, but is not where privileges normally start.

A privilege that has been disabled is re-activated by explicitly enabling it through AdjustPrivileges.

When the privilege is exercised, the kernel checks that it is both present and enabled — a single mask test against both words — permits the operation, and records it as used.

For a standalone gate, "exercised" means the gate accepted that bit, and the used bit is meant to be recorded even when a later independent check — a process descriptor, PIP, or a malformed-input test — denies the operation afterwards. Where the shared privilege helper performs the check, it marks the bit immediately, and the impersonation gate does the same. Three gates mark later and therefore record nothing when a subsequent check fails: token creation marks after the token has been constructed and its descriptor allocated, so a malformed specification leaves the bit unset; primary token installation marks after the same-user and same-LogonSession gate; and the CAP_SYS_BOOT mapping marks after the remote-shutdown origin gate.

Used-state for the AccessCheck-influencing privileges follows the provenance rules of §3.8 instead.

Recording the used bit is not merely bookkeeping. Every gate treats a failure to record it as a failure of the operation itself and returns EPERM or EACCES.

Afterwards the privilege may be disabled, returning to rest, or removed permanently, which clears it from the present, enabled, and enabled-by-default states while preserving the used bit for audit.

3.4.1.2 Two enforcement categories #

Standalone operation gates are the majority. They authorize specific operations that AccessCheck does not mediate — rebooting, loading modules, debugging processes — and the kernel simply checks whether the calling thread's token holds the privilege present and enabled before allowing the operation.

AccessCheck-influencing privileges alter the outcome of AccessCheck itself, causing it to grant rights the object's DACL would not grant on its own. They are evaluated inside the pipeline alongside DACL rules, integrity policy, and confinement. There are five: SeSecurityPrivilege grants ACCESS_SYSTEM_SECURITY for SACL access (and doubles as a standalone gate for the audit-related Linux capabilities); SeTakeOwnershipPrivilege grants WRITE_OWNER as a post-DACL fallback; SeBackupPrivilege grants all read access; SeRestorePrivilege grants all write access plus WRITE_DAC, WRITE_OWNER, DELETE and ACCESS_SYSTEM_SECURITY; and SeRelabelPrivilege loosens MIC's constraint on WRITE_OWNER for non-dominant callers. §3.8 gives the exact mechanics.

3.4.1.3 Intent gating #

SeBackupPrivilege and SeRestorePrivilege are intent-gated. Other AccessCheck-influencing privileges are self-scoping — SeSecurityPrivilege only matters when ACCESS_SYSTEM_SECURITY is requested — but backup and restore grant such broad categories of access that evaluating them unconditionally would apply them to every AccessCheck on the system.

AccessCheck therefore takes a privilege_intent parameter. A caller passes BACKUP_INTENT for a backup-context operation and RESTORE_INTENT for a restore-context one, and the corresponding privilege is evaluated only when its flag is present. Without the flag, these privileges are invisible to the pipeline.

Intent gating also keeps backup and restore inside the pipeline rather than short-circuiting it, which matters because later stages — PIP in particular — have to be able to constrain privilege-granted access.

3.4.1.4 Assignment #

Privileges are assigned by security policy, not by identity. Membership of the Administrators group confers no privilege by itself. Groups and privileges are orthogonal: groups determine which objects you can reach through DACLs, privileges determine which system operations you can perform.

An administrator defines policy — that members of Backup Operators receive SeBackupPrivilege and SeRestorePrivilege, say. At authentication authd resolves the principal's group memberships, evaluates the policy against them, and creates the token carrying the result. The kernel neither verifies nor evaluates that policy; it trusts authd as a TCB component. The token then carries those privileges for its whole lifetime.

3.4.1.5 Auditing #

Every exercise sets the token's monotonic used state for that privilege, and every standalone gate emits an ftrace event.

KMES audit events are emitted only for the five AccessCheck-influencing privileges, and only when the token's audit_policy opts in through PRIVILEGE_USE_SUCCESS or PRIVILEGE_USE_FAILURE. The event fires when the privilege's provenance bits intersect both the mapped desired mask and the final granted mask. For SeSecurityPrivilege and SeTakeOwnershipPrivilege that intersection is genuinely counterfactual — ACCESS_SYSTEM_SECURITY is pre-decided by the privilege, and take-ownership contributes only when WRITE_OWNER was not already granted — so an event means the privilege was load-bearing. Backup and restore seed their bits unconditionally, without asking whether the DACL would have granted the same access, so their events also fire for accesses the DACL alone would have permitted.

A MAXIMUM_ALLOWED request short-circuits this accounting entirely, recording no used bits and emitting no privilege-use events for any privilege.

Edit this page