On this page
Service identity and privileges
Every service process runs under a KACS token — the kernel object that carries identity into every system call and is the input to every access decision. peinit's responsibility is to get the right token for a service and install it on the child process before the binary execs, so the service runs as the intended principal from its very first instruction.
One rule frames everything else: peinit never shares its own SYSTEM token with a service. Even a service configured Identity=SYSTEM gets a separately materialised token of its own — never peinit's. This keeps every service's identity independent and auditable, and it is one of peinit's security invariants.
How a token is materialised
The Identity field decides where the token comes from:
Identity value |
Token source |
|---|---|
SYSTEM |
Minted by peinit from its own SYSTEM identity. |
| Any other principal name or SID | Requested from authd. |
| Absent or empty | authd, defaulting to LocalService. |
The SYSTEM path
For a SYSTEM service, peinit mints an independent SYSTEM token using its own token as the template: it reads its own identity (user SID S-1-5-18, the group list, the privilege set) and mints a fresh primary token with the same identity, adding the service's per-service SID. The minted token is fully independent — the privilege trimming that follows affects only this token, never peinit's.
This path exists because of a bootstrapping problem: the platform services that make the normal token flow possible cannot use it, because they have to start before it exists. registryd, authd, lpsd, and eventd all run as SYSTEM and are all minted this way during boot, before authd is available to mint anything.
SYSTEM. The security boundary is the registry key descriptor on Machine\System\Services\ — an administrator who can create service definitions is already trusted to assign any identity, so a second gate would add nothing. The dangerous case is never implicit, though: SYSTEM must be written out explicitly; an empty Identity defaults to the minimal LocalService, never to SYSTEM.The authd path
For any other identity, peinit asks authd for a token: it sends the Identity value verbatim, and authd routes it to the right source —
- Well-known principals (
LocalService,NetworkService, …) → a built-in identity with a predefined minimal privilege set; - Local service accounts → lpsd, the local principal store;
- Domain accounts → the directory connector;
— resolves the principal's SIDs, mints a token, creates a logon session, and hands the token back to peinit to install. peinit neither knows nor cares whether the identity is local or domain; routing is authd's job.
The per-service SID
Every service token — minted or authd-issued — carries a per-service SID in its group list. It uses authority S-1-5-80 and is derived deterministically from the service name: the SHA-1 of the uppercased name (as UTF-16LE), with the digest split into five sub-authorities. authd adds it automatically for the tokens it mints; peinit computes and adds it itself for SYSTEM tokens, no authd involvement needed.
The point of the per-service SID is fine-grained access control even when services share an identity. A dozen services might all run as LocalService, but each has a unique service SID, so an ACL can grant access to exactly one of them without inventing a dedicated account. It is also what keeps the platform services — all running as SYSTEM — distinguishable to AccessCheck. See Well-known principals for the SID landscape this fits into.
Privilege restriction
A token comes from its source (authd or the SYSTEM mint) with a default set of privileges. RequiredPrivileges lets a definition trim that set down to only what the service needs:
- peinit reads the
RequiredPrivilegesallow-list and removes every privilege not on it from the token before exec. - Restriction is purely subtractive. peinit removes privileges; it never adds them. A service cannot acquire a privilege its token's source did not grant.
- If
RequiredPrivilegesis absent, the token's default privilege set is used unchanged.
This is least-privilege made concrete: eudev, for instance, runs as SYSTEM (it needs device access during early boot) but with its privilege set stripped to the minimum it actually uses, so a compromise of eudev does not hand an attacker the full SYSTEM privilege set. Removal is permanent for the life of that token — it is not a disable that the service can re-enable. See Privileges for what the individual privileges grant.
Which identity runs what
A service is not just its main process — it has hooks, health checks, and a reload command, and each runs under a defined identity:
| Context | Runs as |
|---|---|
| Main process | The service's Identity. |
ExecStartPre / ExecStartPost |
HookIdentity if set, otherwise the service's Identity. |
| Health checks | The service's Identity, always. |
ExecReload (command form) |
The service's Identity, always — HookIdentity does not apply. |
| Ad-hoc jobs | The token captured by JFS — the submitter's (possibly impersonated) identity. |
Token materialisation for hooks follows the same rules: a HookIdentity of SYSTEM is minted; any other principal is requested from authd, at the point the hook runs.
HookIdentity exists so hooks can run with different — usually higher — privileges than the service itself: creating directories in privileged locations, or running a database migration as an admin identity, before the long-running daemon drops to a lesser identity.
HookIdentity grants elevated privileges, it is the administrator's responsibility to ensure the hook binary and every parent directory are not writable by a lower-privileged identity — otherwise a less-trusted principal could replace the hook and run code as the elevated identity. (FACS enforces KACS descriptors on managed filesystems, but peinit itself performs no such check — protecting hook binaries still depends on correct SDs from packaging and controlled paths.)Security invariants
The identity model rests on a few rules peinit never breaks:
- peinit never shares its SYSTEM token. Even
Identity=SYSTEMservices get a separately minted token. - peinit never drops its own SYSTEM identity. PID 1 runs as SYSTEM for the life of the system — its identity is axiomatic, granted by the kernel at boot.
- Privileges are subtractive only.
RequiredPrivilegesremoves; it can never add. - Identity is deterministic. Every service runs as a known principal.
SYSTEMmust be declared explicitly; an emptyIdentityis the minimalLocalService, never SYSTEM.
Where to start
Identity decides what a service can do; the ServiceSecurity descriptor decides who can manage it — two independent concerns. Read Who can manage a service for the other half.
To see how the token is installed alongside the rest of the process setup, read The execution environment.
For the identity primitives themselves — tokens, SIDs, privileges — start at Tokens.