5.5 The Base Environment
peinit constructs every service and hook process's environment from
scratch, in four layers, lowest precedence first. Nothing is inherited
: peinit's own startup
environment holds TERM and nothing else (§2.1), and none of it is
passed through.
5.5.1 Layer 1: the compiled-in base #
One variable:
| Variable | Value |
|---|---|
PATH | /sbin:/bin |
Executables are addressed through the root-level StrataFS runtime views.
Package storage paths under /usr are deliberately not on the default
search path.
5.5.2 Layer 2: global environment variables #
Each value under Machine\System\Init\EnvVars\ becomes a variable: the
value name is the variable name, the REG_SZ data is the value. An
EnvVars\PATH overrides the compiled-in PATH; every other name adds.
A malformed entry — an empty name, or a name containing = — fails the
whole layer, which at boot means recovery mode.
registryd does not receive this layer.
The exemption is a
trust rule, not an availability one. Write access to EnvVars\ is equivalent
to compromising every service peinit starts: LD_PRELOAD,
LD_LIBRARY_PATH and their relatives are not filtered, because the
key's Security Descriptor is meant to be the control boundary. A key
that could inject into the daemon that enforces who may write it would
make that boundary self-referential.
The exemption is narrow, and matches on two things at once: the job's
resolved identity is SYSTEM and its service name is registryd.
A
non-platform service that happens to be called registryd receives the
ordinary layering. It matches on the job, so a hook of registryd's
running under a non-SYSTEM HookIdentity would receive the layer; and
it matches the resolved identity string, so a definition naming
S-1-5-18 literally rather than SYSTEM would not be exempt.
registryd is launched in Phase 1, before EnvVars has been read at all,
so the exemption is only observable on a restart.
5.5.3 Layer 3: the service's own Environment #
The definition's Environment entries, overriding both layers below.
5.5.4 Layer 4: protocol variables #
NOTIFY_SOCKET, always. LISTEN_FDS, LISTEN_FDNAMES and
LISTEN_PID, only when descriptors are being injected — from the fd
store for a service, or from a submission's attachments for a submitted
job (§8.5).
These have the highest precedence. The first three are inserted after
both configurable layers, and all four names are dropped from those
layers before insertion, so a service cannot override NOTIFY_SOCKET
and break its own notification protocol, and an EnvVars\LISTEN_FDS=3
cannot point an fd-store-less service's sd_listen_fds at whatever
happens to sit at descriptor 3.
The name filter is what protects the LISTEN_* set when it is not
being set.
LISTEN_PID, which a conforming sd_listen_fds implementation checks
against its own PID before trusting LISTEN_FDS, is appended by the
child itself after the clone, because only then is the PID known; the
name filter keeps a configured value from shadowing it.
5.5.5 What peinit does not set #
Not HOME, USER, LOGNAME, SHELL or TERM. Peios identity is a
KACS token — a SID — rather than a passwd entry, so there is no
canonical home directory or login shell to populate. A service that
needs one supplies it through EnvVars\ or its own Environment; a
submitted job's submitter supplies it in the submission's
environment, which occupies layer 3 for a job.
5.5.6 Hooks and probes #
Hooks, health checks and reload commands are built through the same
path, so they receive the identical environment: the same layers, the
same NOTIFY_SOCKET, and the service's WorkingDirectory,
LimitNOFILE, LimitCORE and RequiredPrivileges. They never receive
LISTEN_FDS — stored descriptors go to the main process only.
5.5.7 When changes apply #
The global layer is a snapshot refreshed at boot and on reload-config,
and both it and the per-service Environment take effect at a service's
next start. Neither is applied to a running process.