Skip to content

Fix missing SDDL mapping for ZD object-deny callback ACE (Fixes #129) - #130

Merged
p0dalirius merged 1 commit into
mainfrom
bugfix-zd-sddl-mapping
Jul 21, 2026
Merged

Fix missing SDDL mapping for ZD object-deny callback ACE (Fixes #129)#130
p0dalirius merged 1 commit into
mainfrom
bugfix-zd-sddl-mapping

Conversation

@p0dalirius

Copy link
Copy Markdown
Collaborator

Linked Issue

Closes #129

Root Cause

ZD (ACCESS_DENIED_CALLBACK_OBJECT, ACE type 0x0C) was omitted from the SDDL_* constants and from SDDLToACETypeMap in sddl/ace/acetype/AccessControlEntryType.go when the sibling callback types (XA/0x09, XD/0x0A, ZA/0x0B) were added. That map is the single source of truth for the SDDL↔ACE-type translation in both directions, so the omission made 0x0C unrepresentable on parse and serialize even though the rest of the descriptor pipeline already supported it.

Fix Description

Add the SDDL_CALLBACK_OBJECT_ACCESS_DENIED = "ZD" constant and its SDDLToACETypeMap entry mapping to ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT. Because sddlParseACE() looks up token→type via this map and sddlACETypeToString() reverse-iterates the same map for type→token, the single entry enables both parsing and serialization. No other production code needed changing: isConditionalACEType() and sddlGetACLRevision() already list 0x0C, the object-GUID field parsing is type-agnostic, and the conditional-expression trailer path already routes through isConditionalACEType(). A stale comment listing the conditional callback types (XA/XD/XU/ZA) is updated to include ZD.

How Verified

  • Tests: added TestObjectCallbackACE_ZD_SDDLRoundTrip (see below); go test ./... passes with no regressions.
  • Runtime: FromSDDLString("D:P(ZD;;WP;bf967950-0de6-11d0-a285-00aa003049e2;;S-1-1-0;(Member_of {SID(BA)}))") now parses to a 0x0C ACE with the ObjectType GUID and artx conditional expression intact; the descriptor binary-marshals and unmarshals unchanged; and ToSDDLString() re-emits D:P(ZD;;WP;bf967950-0de6-11d0-a285-00aa003049e2;;WD;(Member_of {SID(S-1-5-32-544)})) (previously it emitted nothing for the 0x0C ACE and parsing errored with unknown ACE type: ZD).

Test Coverage

Added: securitydescriptor/NtSecurityDescriptor_conditional_test.goTestObjectCallbackACE_ZD_SDDLRoundTrip, asserting the ACE type (0x0C), the ObjectType GUID, and the conditional expression survive both an SDDL round-trip and a binary Marshal/Unmarshal round-trip.

Scope of Change

  • Files changed: sddl/ace/acetype/AccessControlEntryType.go, securitydescriptor/NtSecurityDescriptor_sddl.go (comment only), securitydescriptor/NtSecurityDescriptor_conditional_test.go (new test)
  • Submodule pointer updated: no
  • Behavioral changes outside the bug fix: none

Risk and Rollout

Low blast radius: adds a previously-absent map key and a test. It cannot change behavior for any ACE type other than 0x0C (whose SDDL handling was previously non-functional), so it is safe to merge without staged rollout.

Add the SDDL_CALLBACK_OBJECT_ACCESS_DENIED = "ZD" constant and its
SDDLToACETypeMap entry mapping to ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT
(0x0C). Because SDDLToACETypeMap is used bidirectionally -- sddlParseACE
looks up token->type and sddlACETypeToString reverse-iterates it for
type->token -- this one entry enables both parsing and serializing ZD
ACEs. The rest of the pipeline (isConditionalACEType, sddlGetACLRevision,
binary Marshal/Unmarshal, condition codec) already handled 0x0C.

Also update the stale comment listing conditional callback ACE types to
include ZD, and add a round-trip test.
@p0dalirius
p0dalirius merged commit d0fb571 into main Jul 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant