5.5.2 Syscalls
5.5.2.1 reg_open_key (1100) #
int ;
Opens an existing key. Fails if it does not exist after layer resolution.
| Parameter | Description |
|---|---|
parent_fd | An open key fd to resolve relative to, or -1 for an absolute path. No AccessCheck is performed on the parent. |
path | A null-terminated registry path — absolute with a hive prefix when parent_fd is -1, relative to the parent key otherwise. |
desired_access | Requested rights, raw generic bits, MAXIMUM_ALLOWED, or a combination (§5.4.2). Zero and unknown bits are EINVAL. |
flags | REG_OPEN_LINK (0x01) opens a symlink key rather than following it. Every other bit is reserved and must be zero. |
- Parse and canonicalise the path: normalise separators, reject empty components and a trailing separator, check the total length and each component length.
- Rewrite a leading
CurrentUser\toUsers\<caller SID>\— only for an absolute path, and only the first component (§5.2.1). - Route. For an absolute path, look the hive name up, private hives before global ones. For a relative one, use the parent key's source and resolve from the parent's GUID.
- Walk the path component by component through
RSI_LOOKUP, resolving each through the layer stack and following symlinks — except a final component whenREG_OPEN_LINKis set. Collect the ancestor chain as you go. - Run AccessCheck against the final key's descriptor.
- Publish an fd holding the key GUID, the granted mask, the resolved path and the ancestor chain.
If the path traversed a symlink, the fd stores the resolved path and ancestor chain. It refers to the target object.
5.5.2.2 reg_create_key (1101) #
int ;
Opens the key if it exists after layer resolution, creates it with an inherited descriptor if not, and reports which happened.
If the key exists, this behaves as reg_open_key and the
disposition is REG_OPENED_EXISTING.
What "exists" means depends on the layer named. For the base layer (a
null layer_ptr) it is the path resolving through any enabled layer.
For a named layer it is that layer holding an entry at the path:
presence is per layer (§5.2.5), so another layer's key at the same path
does not count, and the create makes the named layer's own entry, with
its own GUID and REG_CREATED_NEW — which is how hide-and-replace is
authored.
The named-layer presence check is read-only and compares layer names without
case sensitivity. If that layer already names a key, LCS opens the effective
key using normal layer resolution and checks the requested rights on that
key. It does not require KEY_CREATE_SUB_KEY on the parent, perform layer
write authorization, or send CREATE_ENTRY/CREATE_KEY for an existing key.
An unbound transaction remains unbound by this open; a bound transaction
uses its own view, including entries it has created but not yet committed.
The checks below still apply when the named layer has no key entry there.
If it does not:
- Resolve the parent, which must exist. Check that the parent's depth
plus one is within
MaxKeyDepth. - AccessCheck the parent for
KEY_CREATE_SUB_KEY. - Perform layer write authorization against the target layer's metadata key (§5.3.4).
- Mint a fresh UUIDv4 GUID.
- Compute the new key's descriptor from the parent's, through KACS.
- Create the path entry with a new sequence number, then the key record (§5.2.5).
- AccessCheck the new key's inherited descriptor against
desired_access— an inherited descriptor may not grant everything the creator asked for. - Publish the fd with the granted mask and disposition
REG_CREATED_NEW.
Intermediate path components are not auto-created. Only the final one is.
Races. If two callers race, one creates and the other observes the
key as existing. RSI_ALREADY_EXISTS on the path entry is retried as
an open, reporting REG_OPENED_EXISTING, and EEXIST never reaches
userspace from this syscall. RSI_ALREADY_EXISTS on the key record,
for a GUID LCS has just minted, is not a race — the source and the
kernel disagree about what exists — and fails closed with EIO
(§5.2.3).
5.5.2.3 reg_begin_transaction (1102) #
int ;
Allocates a transaction id, publishes a transaction fd in state
REG_TXN_ACTIVE_UNBOUND, and starts the lifetime timer. It contacts no
source and chooses none (§5.7.1). It can fail only with ENOMEM,
EOVERFLOW on transaction id exhaustion, or EINVAL.