These docs are under active development and cover the v0.20 Kobicha security model.
On this page
§2.8

Deletion

Key deletion operates on two levels: path entries (per-layer naming) and key data (identity and properties).

§2.8.1 Explicit deletion

When a process deletes a key via syscall, LCS removes the path entry for the specified layer. The key's data (GUID, SD, values) is not affected -- only the naming is removed.

Hive root keys cannot be explicitly deleted or hidden. A hive root has no parent GUID or child name, so there is no path-entry tuple to remove or mask with RSI_DELETE_ENTRY or RSI_HIDE_ENTRY. LCS MUST reject delete and hide operations on hive root fds with EINVAL before source dispatch, transaction enlistment, sequence allocation, or watch generation.

If the key still has path entries in other layers, those remain. The key is still visible through those layers.

If no path entries remain across any layer after the deletion, the key is orphaned.

§2.8.2 Layer deletion

When a layer is deleted, all its path entries and value entries are removed across all sources. LCS broadcasts the deletion to all registered sources.

Any GUIDs that lose their last path entry (across all layers) are orphaned. Values that were the highest-precedence entry for their name are removed, and the next-highest-precedence entry becomes effective. Blanket tombstones held by the deleted layer are removed, unmasking lower-precedence values.

Layer deletion is the mechanism for role uninstallation and Group Policy removal.

Interaction with transactions. Before sending RSI_DELETE_LAYER, LCS MUST abort all bound transactions that have written to the layer being deleted. This prevents stale writes from being committed into a deleted layer after RSI_DELETE_LAYER completes. Affected transactions receive EINVAL on their next operation or commit attempt.

§2.8.3 Orphaned keys

An orphaned key is a GUID with no path entries in any layer. It follows the Linux unlink model:

  • Existing fds to the orphaned key continue to work. Reads, writes, and enumeration operate normally against the key's GUID.
  • The key is alive but unnamed -- no new opens can reach it by path.
  • When the last fd closes, LCS tells the source to drop the GUID via RSI_DROP_KEY.

Existing fds to an orphaned key may perform GUID-local operations:

  • query, set, and delete values
  • set or remove blanket tombstones
  • query and set the key Security Descriptor
  • query key metadata
  • flush the key's hive
  • close the fd

Namespace operations are rejected once the fd's key is orphaned:

  • creating a child key under the orphaned key returns ENOENT
  • relative open or create through the orphaned key returns ENOENT
  • deleting the orphaned key's path entry returns ENOENT
  • hiding the orphaned key returns ENOENT
  • backup of the orphaned key returns ENOENT

An orphaned key is no longer a reachable subtree root. Allowing new path entries beneath an unnamed key would create unreachable subgraphs, so namespace mutation is not permitted.

Existing watches on a key remain armed when the key becomes orphaned. The transition to orphaned state delivers KEY_DELETED. After that, the watch may observe GUID-local changes made through existing fds until the fd closes, but subtree expansion through the orphaned key is not performed. Arming a new watch on an already orphaned key returns ENOENT.

RSI_DROP_KEY removes all data associated with the GUID: the key record, all value entries across all layers, and any remaining path entries that might reference it.

If the last fd to an orphaned key closes while the backing source is Active, LCS sends RSI_DROP_KEY before releasing its in-kernel key state. If the source is Down, LCS releases its in-kernel key state and does not queue a deferred drop. The source's required startup and re-registration orphan cleanup is responsible for purging key records that have no path entries before the source becomes Active.

close() does not report orphan cleanup failure to userspace. If a source cannot complete orphan cleanup, registration fails or the source remains unavailable.

§2.8.4 RSI deletion operations

The deletion model maps to three RSI operations:

  • RSI_DELETE_ENTRY(parent_GUID, child_name, layer): Remove a specific layer's path entry. The key's data remains, keyed by GUID. Used for explicit key deletion.

  • RSI_DROP_KEY(GUID): Remove all data associated with the GUID. Called by LCS when an orphaned key's last fd closes.

  • RSI_DELETE_LAYER(layer_name): Remove all path entries, value entries, and blanket tombstones tagged with the specified layer from the source's storage. Returns the set of orphaned GUIDs. Called by LCS when a layer's metadata key is deleted (see §2.6).

The source does not know about fds. It sees two database operations: remove a path table row, remove all data rows for a GUID.

§2.8.5 Crash recovery

Sources MUST clean up orphaned GUIDs on startup. An orphaned GUID is a key record with no corresponding path entries in any layer. These arise from keys that were orphaned but not yet dropped before the previous shutdown.

On startup or re-registration, a source queries its storage for GUIDs that exist in the key table but have no path entries. It purges them. This is standard referential integrity cleanup and MUST be performed before completing registration with LCS.

§2.8.6 New key at same path

A layer can create a new key at a path where another layer's key already exists. Each layer has its own path entry pointing to its own GUID. Layer resolution determines which is visible.

Existing fds referencing a different GUID at the same path are completely isolated -- different GUIDs, different data, different value entries.

§2.8.7 Constraints

  • A key with visible children MUST NOT be deleted. Visibility is evaluated globally (all enabled layers), not relative to the caller's private layer set. This ensures deletion semantics are deterministic regardless of caller credentials. The syscall returns ENOTEMPTY. Recursive deletion is a client-side tree walk, not a kernel primitive.

  • Deleting a key does NOT delete its values. Values are associated with the GUID, not the path entry. They are removed when the GUID is dropped (last fd closes on an orphaned key).