6.9 Emission Policy

An event type that is switched off is never written. Each emitter decides, before it writes an event, whether its type is on, from a policy kept in the registry. A consumer decides what to keep of what it reads; it does not decide what is written.

The component that writes a record decides, whatever path the record takes. A component that writes records of its own without going through the kernel's event stream, straight into a store for example, is their emitter for the purposes of this section, and applies the policy to every type it writes that is not essential.

6.9.1 The policy tree #

The policy is the registry key Machine\Generic\Events and the keys beneath it. There is one key per segment of an event type, so the policy for an event type is found on the path that spells its segments beneath Events, one key each, in order: the policy for kacs.audit.access.checked is found by walking Events\kacs\audit\access\checked.

A package-name root (§6.3) is split at its periods like the rest of the type, so a package's events sit beneath one key per segment of its name: org.jellyfin.server.playback.started is found by walking Events\org\jellyfin\server\playback\started, and Events\org\jellyfin is the key that covers every package named beneath org.jellyfin. A segment is used as it is, including one a package name gives that the segment grammar of §6.3 does not admit.

The registry compares key and value names ignoring case, so the walk does too.

Any key on such a path MAY hold a value named Enabled. A REG_DWORD of 1 switches the event types beneath it on, and 0 switches them off. An Enabled value of any other type, or a REG_DWORD holding any other number, is ignored, as though it were absent.

Nothing else in the tree has a meaning. A key on no event type's path, and any value other than Enabled, decides nothing.

6.9.2 Resolving a type #

Whether an event type is on is decided by this procedure. The deepest Enabled value on the type's path wins, and the type's tier decides when there is none.

enabled(event_type, tier) → bool
    if tier == essential
        return true                       // never consults the policy
    setting = absent
    key = Machine\Generic\Events          // absent if it does not exist
    for each segment in segments(event_type)
        if key == absent
            break
        setting = read_enabled(key, setting)
        key = subkey(key, segment)        // absent if it does not exist
    if key != absent
        setting = read_enabled(key, setting)
    if setting != absent
        return setting == 1
    return tier == standard               // standard on; verbose and debug
                                          // off; essential returned above

read_enabled(key, current) → setting
    value = value(key, "Enabled")         // absent if it does not exist
    if value is REG_DWORD and (value == 0 or value == 1)
        return value
    return current                        // ignored: keep what was found

Each rule of the procedure holds on its own:

  • The Enabled value on the deepest key that has one decides. A value on Events itself applies to every type the keys beneath it do not decide.
  • The key named by the whole type, its last segment included, is read like the keys above it.
  • Where a key on the path does not exist, the keys beneath it do not either, and the deepest value found above it decides.
  • A key the emitter may not read ends the walk as a missing one does.
  • With no Enabled value on the path, a standard type is on, and a verbose or debug type is off (§6.8).

An emitter MUST NOT write an event whose type this procedure finds off.

An emitter MUST write an essential event without consulting the policy, whatever the tree holds.

An emitter SHOULD make the decision before it builds the event's payload, so that a type that is off costs nothing beyond the decision.

6.9.2.1 Example #

With no value on Events, Events\kacs holding Enabled = 0, and Events\kacs\audit holding Enabled = 1:

Event typeTierDecided byOn
lcs.config.value.rejectedstandardits tierYes
kacs.caap.staging.divergedstandardEvents\kacsNo
kacs.audit.handle.usedstandardEvents\kacs\auditYes
kacs.audit.access.checkedessentialits tier, alwaysYes

With Enabled = 0 on Events as well, lcs.config.value.rejected is off and the other three are as before. A verbose or debug type in the place of lcs.config.value.rejected would be off in both trees, and in the place of kacs.audit.handle.used on in both.

6.9.3 Gating, SACLs and audit policy #

For an event type with gating (§6.2), the policy and the gating decide together, by AND: the type is written for an occurrence only if the policy has it on and its gating asks for that occurrence.

Neither widens the other. Switching a type on does not record an occurrence that a SACL, or a token's audit policy, does not ask for; and a SACL that asks for an occurrence does not record it while the policy has its type off. The policy decides whether a kind of event exists at all. The gating decides which occurrences of it are recorded, and only the emitter can evaluate it, because only the emitter can see the object.

An essential type's gating alone decides, because the policy never switches it off (§6.8). The kernel's access audit is the case this is for: kacs.audit.access.checked is essential, so whether an access decision is recorded is the SACL's and the audit policy's choice alone, and an administrator never has to switch the same thing on in two places.

6.9.4 Noticing a change #

An emitter MAY cache the policy in-process.

An emitter MUST apply a change to the policy to every decision it makes one second or more after the change was committed, whether or not it caches. An emitter SHOULD apply it to the first decision it makes after the commit, which an emitter that watches the tree can do.

A watch on the subtree of Events sees every change. An emitter that writes under few roots MAY instead watch only the keys on its own types' paths. A key that does not exist cannot be watched, so an emitter watching for one to be created watches the nearest key above it that does exist.

A change is not retroactive. An event written before it stays written, and an occurrence decided before it stays decided.

6.9.5 When the policy cannot be read #

An emitter that cannot read Machine\Generic\Events — before the registry has a source for the Machine hive, where the key does not exist, or where it may not read it — MUST decide by tier alone, as the procedure does when no Enabled value is found.

It MUST NOT hold an event back to wait for the policy to become readable.

Once the policy can be read, an emitter MUST apply it to every decision it makes one second or more after it became readable.

6.9.6 Who may change it #

Each key's security descriptor decides who may change the policy beneath it, and inheritance carries that down the tree. This is why the policy has one key per segment rather than one flat key per pattern: a grant on Events\org\jellyfin lets whoever runs Jellyfin switch its events, and reaches nothing else.

A conforming system:

  • lets every emitter read Machine\Generic\Events and every key beneath it;
  • lets only administrators write Machine\Generic\Events itself, and the keys of platform roots (§6.A);
  • SHOULD give Machine\Generic\Events a SACL that audits writes, so that a change to what is recorded is itself recorded.

Edit this page