5.3.4 Writing Into a Layer
Every mutating operation that targets a layer — value writes, value
deletions, tombstones, key hides, blanket tombstones, key creation —
requires layer write authorization: KEY_SET_VALUE on the layer's
metadata key at Machine\System\Registry\Layers\<LayerName>\.
This is a second AccessCheck, against a different object, and it is in addition to the fd's granted mask on the target key. Both must pass.
The descriptor on a layer's metadata key is therefore the answer to
"who may write into this layer". The base layer's, where the key has
been created, is the one inheritance computes from the Machine hive
root, like any other key's.
Group Policy layers get restrictive descriptors from the GP client at
creation; role layers get theirs from the role installer.
That closes two escalation paths at once. An unprivileged process cannot write into a GP layer, and one role's service cannot write into another role's.
The base layer is the one layer meant to be written by everybody. It
is where a write goes that names no layer, a person's own settings
under Users\<SID>\ included, so its descriptor lets in anyone who has
authenticated and leaves what they may write to the descriptor of the
key they are writing. A layer check that refused them would make every
key read-only to everyone but SYSTEM and Administrators, whatever the
key's own descriptor said.
The layer metadata descriptors are cached alongside the layer table and
invalidated by the same self-watch (§5.3.3). A layer that is not in the
table is ENOENT for any operation naming it.
5.3.4.1 The base layer before it exists #
While Layers\base\ does not exist, LCS falls back to a compiled-in
default descriptor, so base-layer writes work from the start. It is
owned by SYSTEM and grants KEY_ALL_ACCESS to SYSTEM and
Administrators and KEY_SET_VALUE, the one right this check asks for,
to Authenticated Users. Nobody else is granted anything: a principal
that has not authenticated cannot write into the base layer, whatever
the target key allows.
Nothing in a Peios system creates Layers\base\, so on a system as
shipped the compiled-in default is the descriptor in force for as long
as the system runs.
It is replaced by the persisted descriptor the moment the key is created.
5.3.4.2 Layer lifecycle #
Everything except the precedence rule is controlled purely by the descriptor on the metadata key.
5.3.4.3 The precedence gate #
SeTcbPrivilege is required specifically to establish or raise a
layer's precedence above 0. It is defence in depth: compromising the
descriptor on Layers\ is not enough to create a Group Policy-tier
layer.
The check is synchronous and inline at REG_IOC_SET_VALUE time, and it
happens early — before sequence allocation, before transaction
enlistment, before the source is contacted.
It runs when three things hold: the target key is a layer metadata key,
the value name folds equal to Precedence under the same Unicode
folding used for every other value name, and the data is a positive
REG_DWORD. A key
is a layer metadata key by its path — a direct child of
Machine\System\Registry\Layers — or by already being in the set of
published layer metadata keys. The path test is what covers the
recommended creation flow (§5.3.3), where Precedence is written inside
the transaction that creates the metadata key, before the layer has
been published at all.
Failing the privilege check is EPERM.
The gate tests for a four-byte REG_DWORD specifically. A Precedence
written with some other type slips past it — and then fails at the
refresh, which rejects a non-REG_DWORD Precedence as malformed
metadata. The precedence never actually rises.
REG_IOC_RESTORE has its own equivalent gate, applied to the backup
stream's layer manifest before anything is written (§5.9.3).
5.3.4.4 Deleting a layer #
Deleting the metadata key fires a SUBKEY_DELETED on the internal
self-watch. LCS removes the layer from the table and broadcasts
RSI_DELETE_LAYER to every registered source, each of which purges
every entry tagged with that name and reports the GUIDs that lost their
last path entry.
Before the broadcast, LCS aborts every bound transaction whose mutation log touched that layer (§5.2.9).
A SUBKEY_DELETED for base is ignored (§5.3.2).