5.4 ACE Types
An Access Control Entry (ACE) is a single rule in an ACL. Each ACE has a header, an access mask, and a principal SID, with optional extensions for object-type and conditional ACEs.
5.4.1 ACE header #
Every ACE begins with a 4-byte header:
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 1 | AceType | Identifies the ACE type. |
| 1 | 1 | AceFlags | Inheritance and audit flags. |
| 2 | 2 | AceSize | Total size of the ACE in bytes, including the header. MUST be a multiple of 4. |
5.4.2 ACE body layouts #
The ACE header is followed by a type-specific body. Every multibyte integer in the body is little-endian.
5.4.2.1 Single-SID ACE family #
The following ACE types share the same binary layout:
ACCESS_ALLOWED_ACEACCESS_DENIED_ACESYSTEM_AUDIT_ACESYSTEM_ALARM_ACESYSTEM_MANDATORY_LABEL_ACESYSTEM_SCOPED_POLICY_ID_ACESYSTEM_PROCESS_TRUST_LABEL_ACE
Layout:
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 4 | AceHeader | Standard ACE header. |
| 4 | 4 | Mask | Access mask. |
| 8 | variable | Sid | Principal SID. Consumes the remainder of the ACE. |
Parsing rules:
AceSizeMUST be at least 16 bytes (header + mask + minimum SID).- The SID MUST consume the remainder of the ACE exactly.
5.4.2.2 Object ACE family #
The following ACE types share the object-ACE binary layout:
ACCESS_ALLOWED_OBJECT_ACEACCESS_DENIED_OBJECT_ACESYSTEM_AUDIT_OBJECT_ACESYSTEM_ALARM_OBJECT_ACE
Layout:
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 4 | AceHeader | Standard ACE header. |
| 4 | 4 | Mask | Access mask. |
| 8 | 4 | Flags | Bitfield describing which GUIDs are present. |
| 12 | 0 or 16 | ObjectType | Present when ACE_OBJECT_TYPE_PRESENT is set. |
| 12 or 28 | 0 or 16 | InheritedObjectType | Present when ACE_INHERITED_OBJECT_TYPE_PRESENT is set. |
| variable | variable | Sid | Principal SID. Begins immediately after the optional GUID fields and consumes the remainder of the ACE. |
Object ACE flags:
| Flag | Value | Description |
|---|---|---|
ACE_OBJECT_TYPE_PRESENT | 0x00000001 | ObjectType GUID is present. |
ACE_INHERITED_OBJECT_TYPE_PRESENT | 0x00000002 | InheritedObjectType GUID is present. |
Parsing rules:
AceSizeMUST be large enough to contain the header, mask, flags, all GUIDs selected byFlags, and a complete SID.- Unknown bits in
FlagsMUST be ignored. - If neither GUID-presence bit is set, the ACE has no GUID fields and behaves like the corresponding basic ACE.
- GUID fields are opaque 16-byte values at this layer. Their interpretation is described in the Peios Kernel TRM §3.8.5.
5.4.2.3 Callback ACE family #
The following ACE types extend the corresponding non-callback ACE layout by
appending ApplicationData at the end of the ACE:
ACCESS_ALLOWED_CALLBACK_ACEACCESS_DENIED_CALLBACK_ACESYSTEM_AUDIT_CALLBACK_ACESYSTEM_ALARM_CALLBACK_ACEACCESS_ALLOWED_CALLBACK_OBJECT_ACEACCESS_DENIED_CALLBACK_OBJECT_ACESYSTEM_AUDIT_CALLBACK_OBJECT_ACESYSTEM_ALARM_CALLBACK_OBJECT_ACE
For non-object callback ACEs, the body layout is:
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 4 | AceHeader | Standard ACE header. |
| 4 | 4 | Mask | Access mask. |
| 8 | variable | Sid | Principal SID. |
| variable | variable | ApplicationData | Trailing type-specific bytes. Consumes the remainder of the ACE. |
For callback object ACEs, the body layout is:
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 4 | AceHeader | Standard ACE header. |
| 4 | 4 | Mask | Access mask. |
| 8 | 4 | Flags | Object ACE flags. |
| 12 | 0 or 16 | ObjectType | Present when ACE_OBJECT_TYPE_PRESENT is set. |
| 12 or 28 | 0 or 16 | InheritedObjectType | Present when ACE_INHERITED_OBJECT_TYPE_PRESENT is set. |
| variable | variable | Sid | Principal SID. |
| variable | variable | ApplicationData | Trailing type-specific bytes. Consumes the remainder of the ACE. |
Parsing rules:
- The SID begins after the fixed fields and any optional GUIDs, exactly as in the corresponding non-callback ACE family.
ApplicationDataMAY be empty. Semantics for empty or malformed callback payloads are defined by the relevant subsystem.- For conditional ACEs,
ApplicationDatacarries the conditional expression bytecode defined in the Conditional ACE Bytecode Reference.
5.4.2.4 Resource attribute ACE #
SYSTEM_RESOURCE_ATTRIBUTE_ACE uses the single-SID ACE prefix followed by
trailing application data:
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 4 | AceHeader | Standard ACE header. |
| 4 | 4 | Mask | Reserved for compatibility. Not used for access decisions. |
| 8 | variable | Sid | MUST be Everyone (S-1-1-0). |
| variable | variable | ApplicationData | One claim entry using §5.9. Consumes the remainder of the ACE. |
Parsing rules:
- The SID MUST be Everyone.
ApplicationDataMUST contain exactly one claim entry using §5.9.
5.4.3 DACL ACE types #
5.4.3.1 Basic ACEs #
| Structure | Value | Effect |
|---|---|---|
| ACCESS_ALLOWED_ACE | 0x00 | Grants the specified rights to the SID. |
| ACCESS_DENIED_ACE | 0x01 | Denies the specified rights to the SID. |
5.4.3.2 Object-type ACEs #
Extend basic ACEs with one or two GUIDs that scope the rule to a specific property or object class. Used for Active Directory access control.
| Structure | Value | Effect |
|---|---|---|
| ACCESS_ALLOWED_OBJECT_ACE | 0x05 | Grants rights scoped to a property/class GUID. |
| ACCESS_DENIED_OBJECT_ACE | 0x06 | Denies rights scoped to a property/class GUID. |
The ObjectType GUID identifies the property or property set the ACE applies to. The InheritedObjectType GUID restricts inheritance to child objects of a specific class. Either or both GUIDs MAY be absent (indicated by a flags field), in which case the ACE behaves like a basic ACE for that dimension.
5.4.3.3 Conditional ACEs #
Extend basic and object-type ACEs with a conditional expression. The ACE only takes effect if the expression evaluates to TRUE against the caller's token attributes and the object's resource attributes.
| Structure | Value | Effect |
|---|---|---|
| ACCESS_ALLOWED_CALLBACK_ACE | 0x09 | Conditional allow. |
| ACCESS_DENIED_CALLBACK_ACE | 0x0A | Conditional deny. |
| ACCESS_ALLOWED_CALLBACK_OBJECT_ACE | 0x0B | Conditional allow, scoped to GUID. |
| ACCESS_DENIED_CALLBACK_OBJECT_ACE | 0x0C | Conditional deny, scoped to GUID. |
5.4.4 SACL ACE types #
5.4.4.1 Audit ACEs #
Trigger audit log entries when matching access attempts occur. The AceFlags field carries SUCCESSFUL_ACCESS_ACE_FLAG (0x40) and/or FAILED_ACCESS_ACE_FLAG (0x80).
| Structure | Value | Effect |
|---|---|---|
| SYSTEM_AUDIT_ACE | 0x02 | Audit access matching the SID and mask. |
| SYSTEM_AUDIT_OBJECT_ACE | 0x07 | Audit access scoped to a GUID. |
| SYSTEM_AUDIT_CALLBACK_ACE | 0x0D | Conditional audit. |
| SYSTEM_AUDIT_CALLBACK_OBJECT_ACE | 0x0F | Conditional audit, scoped to GUID. |
5.4.4.2 Alarm ACEs (continuous auditing) #
| Structure | Value | Effect |
|---|---|---|
| SYSTEM_ALARM_ACE | 0x03 | Continuous audit for matching SID and mask. |
| SYSTEM_ALARM_OBJECT_ACE | 0x08 | Continuous audit scoped to a GUID. |
| SYSTEM_ALARM_CALLBACK_ACE | 0x0E | Conditional continuous audit. |
| SYSTEM_ALARM_CALLBACK_OBJECT_ACE | 0x10 | Conditional continuous audit, scoped to GUID. |
5.4.4.3 Mandatory label ACE #
Defines the object's integrity level for MIC. Conforming producers SHOULD emit at most one non-inherit-only mandatory-label ACE per SACL. Imported or existing SACLs MAY contain multiple mandatory-label ACEs; MIC uses the first non-inherit-only mandatory-label ACE as described in the Peios Kernel TRM §3.8.3. Inherit-only mandatory-label ACEs do not apply to the current object. The SID encodes the integrity level. The access mask encodes the MIC policy (which operations are blocked for non-dominant callers).
| Structure | Value | Effect |
|---|---|---|
| SYSTEM_MANDATORY_LABEL_ACE | 0x11 | Sets the object's integrity level and MIC policy. |
5.4.4.4 Resource attribute ACE #
Attaches name-value attributes to the object for conditional ACE evaluation. The ACE's SID is always Everyone (S-1-1-0).
| Structure | Value | Effect |
|---|---|---|
| SYSTEM_RESOURCE_ATTRIBUTE_ACE | 0x12 | Defines a resource attribute on the object. |
5.4.4.5 Scoped policy ID ACE #
References a central access policy by SID. During AccessCheck, the referenced policy's rules are evaluated in addition to the object's own DACL.
| Structure | Value | Effect |
|---|---|---|
| SYSTEM_SCOPED_POLICY_ID_ACE | 0x13 | References a central access policy. |
5.4.4.6 Process trust label ACE #
Defines the object's PIP trust level. The SID encodes the PIP type and trust level. The access mask specifies the exact rights that non-dominant callers are allowed.
| Structure | Value | Effect |
|---|---|---|
| SYSTEM_PROCESS_TRUST_LABEL_ACE | 0x14 | Sets the object's PIP trust level. |
5.4.5 Allocated but unimplemented ACE types #
Two values in the range have a name but no KACS behaviour.
| Structure | Value | Notes |
|---|---|---|
| ACCESS_ALLOWED_COMPOUND_ACE | 0x04 | Never implemented. Reserved. |
| SYSTEM_ACCESS_FILTER_ACE | 0x15 | Defined by MS-DTYP. Named by the KACS ABI for format parity; no KACS semantics. |
ACCESS_ALLOWED_COMPOUND_ACE was specified and then abandoned before any
conforming system implemented it. Nothing produces it.
SYSTEM_ACCESS_FILTER_ACE is different: it is a live MS-DTYP ACE type
that KACS has not implemented. The kernel ABI defines a constant for it
(KACS_ACE_TYPE_SYSTEM_ACCESS_FILTER) so that a decoder can put a name
to the byte, but no section of this specification assigns it meaning. A 0x15 ACE therefore takes the
unrecognised-ACE path described at the end of this section: skipped
during evaluation, preserved byte-for-byte on round-trip. An
implementation MUST NOT grant, deny, audit, or filter access on the
basis of a 0x15 ACE.
Values above 0x15 are unallocated.
5.4.6 AceType constants #
The tables above name each ACE structure. The AceType header field
carries a constant with its own name, which is what a reader decoding a
descriptor by hand will be holding. Both spellings, in value order:
| Value | AceType constant | Structure |
|---|---|---|
| 0x00 | ACCESS_ALLOWED_ACE_TYPE | ACCESS_ALLOWED_ACE |
| 0x01 | ACCESS_DENIED_ACE_TYPE | ACCESS_DENIED_ACE |
| 0x02 | SYSTEM_AUDIT_ACE_TYPE | SYSTEM_AUDIT_ACE |
| 0x03 | SYSTEM_ALARM_ACE_TYPE | SYSTEM_ALARM_ACE |
| 0x04 | ACCESS_ALLOWED_COMPOUND_ACE_TYPE | ACCESS_ALLOWED_COMPOUND_ACE |
| 0x05 | ACCESS_ALLOWED_OBJECT_ACE_TYPE | ACCESS_ALLOWED_OBJECT_ACE |
| 0x06 | ACCESS_DENIED_OBJECT_ACE_TYPE | ACCESS_DENIED_OBJECT_ACE |
| 0x07 | SYSTEM_AUDIT_OBJECT_ACE_TYPE | SYSTEM_AUDIT_OBJECT_ACE |
| 0x08 | SYSTEM_ALARM_OBJECT_ACE_TYPE | SYSTEM_ALARM_OBJECT_ACE |
| 0x09 | ACCESS_ALLOWED_CALLBACK_ACE_TYPE | ACCESS_ALLOWED_CALLBACK_ACE |
| 0x0A | ACCESS_DENIED_CALLBACK_ACE_TYPE | ACCESS_DENIED_CALLBACK_ACE |
| 0x0B | ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE | ACCESS_ALLOWED_CALLBACK_OBJECT_ACE |
| 0x0C | ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE | ACCESS_DENIED_CALLBACK_OBJECT_ACE |
| 0x0D | SYSTEM_AUDIT_CALLBACK_ACE_TYPE | SYSTEM_AUDIT_CALLBACK_ACE |
| 0x0E | SYSTEM_ALARM_CALLBACK_ACE_TYPE | SYSTEM_ALARM_CALLBACK_ACE |
| 0x0F | SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE | SYSTEM_AUDIT_CALLBACK_OBJECT_ACE |
| 0x10 | SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE | SYSTEM_ALARM_CALLBACK_OBJECT_ACE |
| 0x11 | SYSTEM_MANDATORY_LABEL_ACE_TYPE | SYSTEM_MANDATORY_LABEL_ACE |
| 0x12 | SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE | SYSTEM_RESOURCE_ATTRIBUTE_ACE |
| 0x13 | SYSTEM_SCOPED_POLICY_ID_ACE_TYPE | SYSTEM_SCOPED_POLICY_ID_ACE |
| 0x14 | SYSTEM_PROCESS_TRUST_LABEL_ACE_TYPE | SYSTEM_PROCESS_TRUST_LABEL_ACE |
| 0x15 | SYSTEM_ACCESS_FILTER_ACE_TYPE | SYSTEM_ACCESS_FILTER_ACE |
5.4.7 ACL revision #
ACLs carry a revision number that constrains which ACE types MAY appear:
- ACL_REVISION (0x02) — basic ACE types (0x00, 0x01, 0x02, 0x03), mandatory label (0x11), resource attribute (0x12), scoped policy (0x13), and process trust label (0x14).
- ACL_REVISION_DS (0x04) — additionally permits object-type ACEs (0x05–0x08), callback ACEs (0x09–0x0C, 0x0D–0x10). Required for Active Directory access control.
When creating new ACLs containing only recognised ACE types, the revision MUST be set to the minimum required by the ACE types present. When rewriting an existing ACL while preserving one or more unrecognised ACE types, KACS MUST set the revision to the greater of the minimum required by recognised ACE types present and the source ACL revision. When parsing ACLs, KACS MUST NOT reject an ACL based on revision-vs-ACE-type mismatch — accept permissively, write correctly.
Unrecognised ACE types — every value not given semantics above, which
today means 0x04, 0x15, and everything from 0x16 up — MUST be silently
skipped during evaluation and preserved byte-for-byte during round-trip serialisation. The ACE's raw bytes (from AceType through AceType + AceSize) are stored opaquely and written back unchanged. ACEs with AceSize not a multiple of 4 MUST be rejected (the containing ACL is malformed).