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

PIP in AccessCheck

Objects MAY opt in to PIP protection by placing a SYSTEM_PROCESS_TRUST_LABEL_ACE in their SACL. The ACE's SID encodes the required pip_type and pip_trust. The ACE's access mask specifies the exact rights that non-dominant callers are allowed.

When AccessCheck encounters a trust label, it compares the caller's process (which carries pip_type and pip_trust on the PSB) against the ACE:

  • If the caller dominates (pip_type >= ACE type AND pip_trust >= ACE trust), PIP imposes no restrictions.
  • If the caller does not dominate, only the rights in the ACE mask are permitted; everything else is denied.

§7.7.1 Privilege revocation

The critical difference from MIC: PIP actively revokes privilege-granted rights. If a non-dominant process used SeBackupPrivilege to gain read access, PIP strips those bits. If SeTakeOwnershipPrivilege granted WRITE_OWNER, PIP strips it. If SeSecurityPrivilege granted ACCESS_SYSTEM_SECURITY, PIP strips it.

Without privilege revocation, a non-PIP administrator with SeSecurityPrivilege could read the SACL of PIP-protected objects -- including removing the trust label itself.

§7.7.2 No default

Unlike MIC, PIP has no default. Objects without a trust label ACE are unrestricted -- any process can access them regardless of PIP identity.

§7.7.3 No privilege escape

PIP has no SeRelabelPrivilege equivalent. No privilege can compensate for insufficient trust level. This is an absolute boundary.

§7.7.4 Multiple trust labels

If multiple SYSTEM_PROCESS_TRUST_LABEL_ACEs appear in the SACL, only the first MUST be used.

§7.7.5 PIP enforcement algorithm

EnforcePIP(ace, pip_type, pip_trust, mapping, &decided,
           &granted, &privilege_granted):

    // pip_type and pip_trust come from the PSB, not the token.

    ace_type = ace.sid.pip_type
    ace_trust = ace.sid.pip_trust

    caller_dominates = (pip_type >= ace_type
                        and pip_trust >= ace_trust)

    if caller_dominates:
        return

    // Non-dominant: the ACE mask IS the allowed set.
    allowed = MapGenericBits(ace.mask, mapping)

    // Compute denied set: everything not explicitly allowed.
    // Includes ACCESS_SYSTEM_SECURITY.
    all_bits = MapGenericBits(GENERIC_ALL, mapping)
              | ACCESS_SYSTEM_SECURITY
    pip_denied = all_bits & ~allowed

    decided |= pip_denied

    // Revoke privilege-granted rights.
    granted &= ~pip_denied
    privilege_granted &= ~pip_denied