ci.dll — trust bypass / missing validation (CWE-358) in SIPolicyIsPolicyPlatformSecured fixed
KB5079473
1. Overview
- Unpatched Binary ID:
ci_unpatched.dll - Patched Binary ID:
ci_patched.dll - Overall Similarity Score: 0.95
- Diff Statistics:
- Matched Functions: 380
- Changed Functions: 88
- Identical Functions: 292
- Unmatched Functions: 0 (both directions)
Verdict: The primary change tightens a System Integrity (SI) policy trust check where, on the non-strict path, a policy could be treated as "platform secured" via a single flag bit without the full identity check. The patch also removes one policy identity from a hardcoded list of policy IDs that are required to be Windows-signed (which relaxes, not tightens, the requirement for that identity), adds a feature-gated flag check to the VBS/HVCI (Virtualization-Based Security) policy-failure path, and switches one catalog-hash lookup from bsearch to the bounds-checked bsearch_s. Separately, the patch hardens the EFI Secure Boot signature-database parser (SbpParseSignatureDatabase, reached from SbParseKEK via SbEFIGetVariable): the merged-list allocation size, previously computed with raw shl/add and no overflow check, is now validated with RtlULongLongMult plus carry checks in the newly extracted helper SbpParseSignatureDatabaseFromBuffer before the buffer is allocated and attacker-controlled variable data is copied in (CWE-190 integer-overflow hardening; see Finding 4).
2. Vulnerability Summary
Finding 1: SI Policy "Platform Secured" Trust Check Bypass
- Severity: Medium
- Vulnerability Class: Trust Bypass / Improperly Implemented Security Check (CWE-358)
- Affected Function:
SIPolicyIsPolicyPlatformSecured (sub_18006FC88)
Root Cause:
SIPolicyIsPolicyPlatformSecured decides whether a loaded System Integrity policy is "platform secured" (return 1) based on a policy-options flag dword at offset +0x710 of the policy structure. In the unpatched build, when the function is called with arg2 = 0 (the non-strict path) and bit 2 (value & 4) is set in that flag dword, it immediately returns 1 (platform secured), skipping the stricter check. The patched build removes this early-return shortcut: on the arg2 = 0 path it now requires bit 0 (value & 1) to be set AND a hardcoded 16-byte policy-identity value at offset +0x6CC/+0x6D4 (0x4C0644C9A244370E / 0x7630566E01F651B5) to match before returning platform-secured. There is no page-hash table or binary search in this function; the check is a policy flag test plus a fixed identity comparison.
The "platform secured" result is a trust gate: one caller honors a policy's PlatformSecureSetting security-policy query only when the owning policy is platform-secured, and another proceeds with image validation once any loaded policy is platform-secured. Removing the bit-2 shortcut therefore narrows which policies are treated as platform-secured. The severity is assessed as Medium rather than High because the end-to-end impact depends on an attacker being able to get a policy loaded and evaluated whose +0x710 flag has bit 2 set while lacking the fixed identity, which cannot be demonstrated from these two binaries alone.
Call Chain:
1. SI policy load / evaluation
2. SIPolicyParsePolicyData and related policy setup
3. SIPolicyIsPolicyPlatformSecured (sub_18006FC88) (platform-secured determination)
Finding 2: Removal of a Policy Identity from the Windows-Signing Mandate List (Relaxation)
- Severity: Informational (not a security fix; the patched build is the less strict one for this identity)
- Vulnerability Class: Signing-requirement relaxation of a hardcoded policy-ID list (no unpatched-vulnerable / patched-fixed direction)
- Affected Function:
SIPolicyIsPolicyMustBeWindowsSigned (sub_18006FB74)
Root Cause:
SIPolicyIsPolicyMustBeWindowsSigned compares a 16-byte policy identity against a built-in list of hardcoded policy-identity constants and returns 1 if any match. The unpatched build contains one extra entry: identity 0x4C3279F4784C4414 (at offset +0x0) with 0xD1DA542FBF0A5A6 (at offset +0x8, i.e. a1[1]). The patch removes this one entry; all other entries are unchanged in both builds.
The direction of this change is a relaxation, not a tightening. In both builds the sole caller reaches the customized-signed acceptance path (SIPolicyCheckPolicyCustomizedSigned, which allows a non-Windows/third-party signer) only when the policy is not Windows-signed (status 0xC0430005) AND SIPolicyIsPolicyMustBeWindowsSigned returns 0. A policy whose identity is on the list is therefore barred from the customized-signed path and must be Windows-signed. Removing identity 0x4C3279F4784C4414 from the list means the patched build no longer forces that identity to be Windows-signed: it may now be accepted through the customized-signed path. So the unpatched build is the stricter one here; this is a policy-ID list adjustment, not a trust revocation and not a vulnerability being fixed. This is a policy-identity constant compare, not a certificate-chain or signer-hash check.
The separately-changed CiHvciIsVbsPolicyFailure (sub_18006C428) is a distinct HVCI/VBS policy-failure detector (it does not call SIPolicyIsPolicyMustBeWindowsSigned); its patched change is described in Finding 2b below.
Call Chain:
1. SI policy evaluation
2. SIPolicyIsPolicyMustBeWindowsSigned (sub_18006FB74) (built-in policy-identity allowlist compare)
Finding 2b: VBS/HVCI Policy-Failure Gate Tightened
- Severity: Low
- Vulnerability Class: Improperly Implemented Security Check (CWE-358)
- Affected Function:
CiHvciIsVbsPolicyFailure (sub_18006C428)
Root Cause:
CiHvciIsVbsPolicyFailure walks loaded policies looking for a specific hardcoded policy identity (0x4B5E588BA072029F / 0x87F67DD6AA05F9B7) to decide whether an HVCI/VBS policy failure occurred. The patch adds a feature-gated pre-check: when Feature_CodeIntegrity_TrustedLaunchPolicy__private_IsEnabledDeviceUsageNoInline (sub_180018DF8) returns non-zero, it re-reads the flag dword at offset +0x938 and returns 0 (no failure) unless bit 0x100000 is set and bit 0x200000 is clear. The +0x938 offset is unchanged between builds.
Finding 3: Hardening of the SHA-256 Catalog Hash Binary Search
- Severity: Low (defensive hardening; no out-of-bounds condition demonstrated in either build)
- Vulnerability Class: Potential Out-of-Bounds Read / Improper Bounds Handling (CWE-125)
- Affected Function:
I_FindFileOrHeaderHashInLoadedCatalogs (sub_1800D6FEC)
Root Cause:
I_FindFileOrHeaderHashInLoadedCatalogs looks up a file/header hash in the sorted hash tables of loaded catalogs. In the unpatched build the SHA-256 branch (a3 == 32780) uses the standard bsearch (element size 0x20, comparator I_HashSearchCompareRoutineSHA256). The patch transitions that call to the bounds-checked variant bsearch_s (with CipFileHashSearchCompareRoutineSHA256, element size 0x20, and a null context argument), which adds runtime parameter validation. The SHA-1 branch (a3 == 32772, element size 0x14) continues to use bsearch in both builds. This is a defensive hardening change; neither build exhibits a demonstrable out-of-bounds read.
Finding 4: Integer-Overflow Hardening of the EFI Secure Boot Signature-Database Parser
- Severity: Low (defensive integer-overflow hardening on an untrusted parser; a demonstrable 64-bit overflow is not provable from these binaries, see below)
- Vulnerability Class: Integer Overflow in size computation (CWE-190) guarding an undersized-allocation heap buffer overflow (CWE-787 / CWE-122)
- Affected Function:
SbpParseSignatureDatabase(unpatched@0x18000BDDC) — in the patch the size/allocation logic is split out into the newly added helperSbpParseSignatureDatabaseFromBuffer (@0x18001E1DC), called from the patchedSbpParseSignatureDatabase (@0x18000E0FC).
Root Cause:
SbpParseSignatureDatabase retrieves an EFI (UEFI) Secure Boot signature-database variable via SbEFIGetVariable (at 0x18000BE21 in the unpatched build) and parses its EFI_SIGNATURE_LIST records to build a merged descriptor array. It is reached from SbParseKEK (@0x18001E16C in the patched build), which parses the Secure Boot KEK/db variable contents — firmware/Secure-Boot configuration data that is exactly the untrusted input this parser exists to validate.
In the unpatched build the allocation size for the merged list is computed with raw shift/add and no overflow validation. After the counting pass, the entry counts in r14/rdi and the raw variable size in r15 are combined as lea rcx,[r14+rdi]; shl rcx,4; add rcx,r15 and passed straight to SbeAlloc (at 0x18000BE54). The attacker-controlled variable data is then copied into that buffer with memmove (at 0x18000BF62). There is no RtlULongLongMult or carry check anywhere in the function; in fact RtlULongLongMult does not appear anywhere in the unpatched binary.
In the patched build every size multiplication that was previously a bare shl is replaced by a checked 64-bit multiply, RtlULongLongMult (multiplier 0x10), whose NTSTATUS result is tested with test eax,eax; js loc_18001E5BC (error path). Each subsequent addition of the sub-region sizes is followed by an explicit carry check (add r10,[rbp+pullResult]; cmp r10,[rbp+pullResult]; jb loc_18001E574, where loc_18001E574 sets STATUS_INTEGER_OVERFLOW = 0xC0000095). Only after all multiplications and additions pass is the buffer allocated with SbeAlloc (at 0x18001E2EC) and the attacker data copied in with memmove (at 0x18001E324).
The change is a genuine, correctly-directed integer-overflow hardening on an untrusted UEFI-variable parsing path (the patched build is the stricter one). It is rated Low rather than higher because the guarded operands are 32-bit entry counts multiplied by 16 and added to a 32-bit variable size; the arithmetic is performed in 64-bit registers and the counts are bounded by the parsed variable size, so a full 64-bit overflow of the allocation size — and therefore the undersized-allocation-plus-memmove heap overflow it would cause — is not demonstrable from these two binaries alone. It is best characterized as defense-in-depth (CWE-190) that forecloses an undersized SbeAlloc followed by an oversized memmove of attacker-controlled EFI-variable data.
Call Chain:
1. Secure Boot variable evaluation
2. SbParseKEK (@0x18001E16C) (parses the KEK/db Secure Boot variable)
3. SbpParseSignatureDatabase (retrieves the variable via SbEFIGetVariable)
4. SbpParseSignatureDatabaseFromBuffer (@0x18001E1DC) (patched-only; overflow-checked size computation before SbeAlloc/memmove)
3. Pseudocode Diff
SIPolicyIsPolicyPlatformSecured (sub_18006FC88) (Platform-Secured Determination)
// UNPATCHED SIPolicyIsPolicyPlatformSecured @ 0x18006FC88:
char SIPolicyIsPolicyPlatformSecured(int64_t a1, char a2) {
int v2 = *(int32_t*)(a1 + 0x710); // policy-options flags
if (a2 != 0) {
if ((v2 & 0x18) == 0) goto full_check;
return 1; // strict path (preserved in patch)
}
if ((v2 & 4) != 0)
return 1; // <--- VULNERABLE: bit 2 alone => platform secured
full_check:
uint32_t v4 = *(uint32_t*)(a1 + 0x28);
if (a2 != 0) return 0;
if ((v2 & 1) == 0) return 0;
uint64_t v6 = -(int64_t)(v4 < 6) & 0xFFFFFFFFFFFFF944ull;
if (*(uint64_t*)(v6 + a1 + 0x6CC) != 0x4C0644C9A244370Eull ||
*(uint64_t*)(v6 + a1 + 0x6D4) != 0x7630566E01F651B5ull)
return 0;
return 1; // identity match required
}
// PATCHED SIPolicyIsPolicyPlatformSecured @ 0x180074028:
char SIPolicyIsPolicyPlatformSecured(int64_t a1, char a2) {
int v2 = *(int32_t*)(a1 + 0x710); // same +0x710 offset in patched
if (a2 != 0 && (v2 & 0x18) != 0)
return 1; // only the strict (a2!=0) path returns early
// The (a2==0 && v2&4) shortcut is REMOVED.
uint32_t v5 = *(uint32_t*)(a1 + 0x28);
if (a2 != 0) return 0;
if ((v2 & 1) == 0) return 0;
uint64_t v7 = -(int64_t)(v5 < 6) & 0xFFFFFFFFFFFFF944ull;
if (*(uint64_t*)(v7 + a1 + 0x6CC) != 0x4C0644C9A244370Eull ||
*(uint64_t*)(v7 + a1 + 0x6D4) != 0x7630566E01F651B5ull)
return 0;
return 1;
}
SIPolicyIsPolicyMustBeWindowsSigned (sub_18006FB74) (Hardcoded Windows-Signing Mandate List)
// UNPATCHED SIPolicyIsPolicyMustBeWindowsSigned @ 0x18006FB74:
char SIPolicyIsPolicyMustBeWindowsSigned(uint64_t* a1) {
if (a1[0] == 0x4730CB9F976D12C8 && a1[1] == 0x8E234308605452BE) return 1;
if (a1[0] == 0x4B5E588BA072029F && a1[1] == 0x87F67DD6AA05F9B7) return 1;
// This entry is REMOVED in the patch (identity no longer forced Windows-signed):
if (a1[0] == 0x4C3279F4784C4414 && a1[1] == 0xD1DA542FBF0A5A6)
return 1;
// [remaining hardcoded comparisons, unchanged in both builds...]
return SIPolicyGetSystemPolicyDefinitionByID() != 0;
}
// PATCHED SIPolicyIsPolicyMustBeWindowsSigned @ 0x180073F34:
// The 0x4C3279F4784C4414 / 0xD1DA542FBF0A5A6 entry is entirely absent;
// all other entries are unchanged. Because a "must be Windows-signed" match
// blocks the customized-signed acceptance path in the caller, removing this
// entry RELAXES the requirement for that identity (it may now be accepted
// via customized signing).
4. Assembly Analysis
SIPolicyIsPolicyPlatformSecured (sub_18006FC88) Assembly Analysis
; UNPATCHED ci!SIPolicyIsPolicyPlatformSecured @ 0x18006FC88
; policy pointer in rcx, a2 (strict flag) in dl
mov eax, [rcx+710h] ; load policy-options flags
mov r8, rcx
test dl, dl ; a2 == 0 ?
jz loc_18006FCDD ; a2==0 -> check bit 2
test al, 18h ; a2!=0: bits 3/4
jnz loc_18006FCE1 ; -> return 1
mov r9d, [rcx+28h]
; ... full check: (al & 1) plus identity compare vs g_SiPolicyLegacyIDs / qword_18002F258 ...
loc_18006FCDD:
test al, 4 ; <--- check bit 2
jz loc_18006FC99 ; if 0, fall into full check
loc_18006FCE1:
mov al, 1 ; <--- return platform-secured
retn ; <--- BYPASS: bit 2 alone marks the policy secured
In the patched build (@ 0x180074028) the flags are still read from [rcx+710h]. The a2==0 branch jumps straight to the full check (test al,18h; jz loc_18007403D); the test al, 4 / mov al,1; retn shortcut is gone, so an a2==0 policy is only "platform secured" when bit 0 is set and the hardcoded identity at +0x6CC/+0x6D4 matches.
SbpParseSignatureDatabase / SbpParseSignatureDatabaseFromBuffer Assembly Analysis (Finding 4)
; UNPATCHED ci!SbpParseSignatureDatabase @ 0x18000BDDC
; ... EFI variable fetched into [rbp+Src], size into [rbp+Size]:
000000018000BE21 call SbEFIGetVariable
; ... counting pass produces entry counts in r14 / rdi (r15d) ...
; allocation of merged descriptor array + data (NO overflow check):
000000018000BE42 mov edi, r15d
000000018000BE45 mov r15d, dword ptr [rbp+Size]
000000018000BE49 lea rcx, [r14+rdi] ; count_a + count_b
000000018000BE4D shl rcx, 4 ; * 16, raw, unchecked
000000018000BE51 add rcx, r15 ; + Size, raw, unchecked
000000018000BE54 call SbeAlloc
; ... later, attacker data copied into the buffer:
000000018000BF62 call memmove
; PATCHED ci!SbpParseSignatureDatabaseFromBuffer @ 0x18001E1DC
; each *16 is a checked 64-bit multiply; overflow -> error path:
000000018001E25F mov ecx, esi ; ullMultiplicand = count
000000018001E261 mov edx, 10h ; ullMultiplier = 16
000000018001E269 call RtlULongLongMult
000000018001E270 js loc_18001E5BC ; overflow -> free + return
000000018001E287 call RtlULongLongMult ; second count * 16
000000018001E290 js loc_18001E5BC
; addition of sub-region sizes with explicit carry check:
000000018001E29A add r10, [rbp+pullResult]
000000018001E29E cmp r10, [rbp+pullResult]
000000018001E2A2 jb loc_18001E574 ; carry -> STATUS_INTEGER_OVERFLOW 0xC0000095
000000018001E2B7 call RtlULongLongMult ; third count * 16
000000018001E2C0 js loc_18001E5BC
000000018001E2CA add rdx, r10
000000018001E2CD cmp rdx, r10
000000018001E2D0 jb loc_18001E574
000000018001E2D9 lea rcx, [rdx+r14] ; + Size
000000018001E2DD cmp rcx, rdx
000000018001E2E0 jb loc_18001E574
000000018001E2EC call SbeAlloc ; allocate only after all checks pass
000000018001E324 call memmove
The unpatched build has no size-overflow validation on this path (RtlULongLongMult is absent from the entire unpatched binary); the patched build gates every multiplication and addition before allocating and copying.
5. Trigger Conditions
To trigger the primary weakness (SI Policy "Platform Secured" Bypass):
- Cause a System Integrity policy to be loaded/evaluated whose policy-options flag dword at offset
+0x710has bit 2 (0x4) set but that does not carry the hardcoded identity value at+0x6CC/+0x6D4. - A code path calls
SIPolicyIsPolicyPlatformSecuredwitharg2 = 0(the non-strict path). - In the unpatched build the function hits the
bit 2early return and reports the policy as "platform secured" without the identity check. - Observable Effect: The policy is treated as platform-secured (a trusted state) on the strength of a single flag bit. In the patched build the same input requires bit 0 set and the fixed identity match, otherwise it returns not-secured. The failure is purely logical; no BSOD occurs.
6. Exploit Primitive & Development Notes
- Provided Primitive: SI-policy trust-state bypass. The unpatched logic lets a policy be classified as "platform secured" (a trusted state that downstream code relies on) using only flag bit 2, without the fixed policy-identity match. This is a logic/trust weakness, not a direct memory-corruption or code-execution primitive.
- Exploitation Requirements:
- An attacker must reach a state where a loaded SI policy has bit 2 set in the flag dword at
+0x710while lacking the hardcoded identity at+0x6CC/+0x6D4, and where a caller invokes the function witharg2 = 0. - Mitigations & Bypasses:
- VBS / HVCI: In a related change,
CiHvciIsVbsPolicyFailure (sub_18006C428)adds a feature-gated check (Feature_CodeIntegrity_TrustedLaunchPolicy__private_IsEnabledDeviceUsageNoInline,sub_180018DF8) that tightens the HVCI/VBS policy-failure path via the flag bits at+0x938. - KASLR / SMEP / SMAP: Not directly applicable, as this is a validation/trust-logic change rather than a memory-corruption chain.
7. Debugger PoC Playbook
For a researcher with a kernel debugger (WinDbg / KD) attached to the unpatched binary:
Breakpoints
Run the following commands to intercept the vulnerable logic:
bp ci!SIPolicyIsPolicyPlatformSecured
bp ci!SIPolicyIsPolicyPlatformSecured+0x55 "Location of the 'test al, 4' shortcut (loc_18006FCDD)"
bp ci!SIPolicyIsPolicyMustBeWindowsSigned "To monitor the hardcoded policy-identity allowlist"
What to Inspect
- At
ci!SIPolicyIsPolicyPlatformSecured: rcx: Pointer to the SI policy structure.dl(rdx): Thearg2strict flag. The shortcut requiresdl == 0.[rcx+0x710]: Inspect the policy-options flags. Usedd rcx+0x710 L1. Bit 2 (0x4) must be set.- At the
loc_18006FCDDshortcut: - Single-step (
t) throughtest al, 4. If it setsal = 1and returns without reaching the identity compare at+0x6CC/+0x6D4, the shortcut is confirmed.
Trigger Setup
- Boot Windows normally.
- Arrange for an SI policy to be loaded/evaluated so that
SIPolicyIsPolicyPlatformSecuredis invoked witharg2 = 0. - Trace into the function, then artificially set
[rcx+0x710] |= 4in the debugger to observe the immediate "platform secured" return in the unpatched build.
Expected Observation
After setting bit 2, the unpatched build sets al = 1 and returns immediately, skipping the identity compare. The patched build falls through to require bit 0 and the fixed identity at +0x6CC/+0x6D4, returning 0 when those do not hold.
8. Changed Functions — Full Triage
| Function Name | Similarity | Change Type | Note on Change |
|---|---|---|---|
SIPolicyIsPolicyPlatformSecured (sub_18006FC88) |
0.50 | Security | Removed early-return "platform secured" shortcut for !arg2 && result & 4. |
SIPolicyIsPolicyMustBeWindowsSigned (sub_18006FB74) |
0.40 | Relaxation | Removed one entry (0x4C3279F4784C4414 / 0xD1DA542FBF0A5A6) from the Windows-signing mandate list; that identity is no longer forced to be Windows-signed (patched is less strict). |
CiHvciIsVbsPolicyFailure (sub_18006C428) |
0.45 | Security | Added feature-gated (Feature_CodeIntegrity_TrustedLaunchPolicy..., sub_180018DF8) check on flag bits at +0x938 in the HVCI/VBS policy-failure path. |
I_FindFileOrHeaderHashInLoadedCatalogs (sub_1800D6FEC) |
0.60 | Security | Swapped the SHA-256 catalog-hash bsearch to the secure bsearch_s variant. |
SbpParseSignatureDatabase (unpatched @0x18000BDDC) / SbpParseSignatureDatabaseFromBuffer (patched-only @0x18001E1DC) |
0.35 | Security | EFI Secure Boot signature-database parser: patched replaces raw shl-based allocation-size math with checked RtlULongLongMult + carry checks before SbeAlloc/memmove (CWE-190 integer-overflow hardening). |
wil_details_FeatureStateCache_ReevaluateCachedFeatureEnabledState (sub_180018FC8) |
0.65 | Behavioral | WIL feature-state cache: patched adds | 0x40000 to the cached feature-state value. |
SymCryptFdefDecideModulusType (sub_18000E878) |
0.60 | Behavioral | SymCrypt library math routine; patched adds (v & 0xC000) == 0 guard on a CPU-feature path. |
I_ParseCatalogAndMapHashes (sub_1800882F4) |
0.35 | Behavioral | Purely structural; inlined I_AllocateCatalogParseBuffers (sub_1800884A0) (pool allocator for 0xed0-byte struct). |
CiQueryInformation (sub_1800D50A0) |
0.70 | Behavioral | Gated a flag on global configuration bit (data_180045e70 & 0x400000). |
SIPolicyParsePolicyData (sub_18006E09C) |
0.55 | Behavioral | Updated policy structure offsets (+0xa80 to +0xaa0); added VBS checks. |
CipValidateFileHash (sub_1800DB310) |
0.50 | Behavioral | Struct offset shifts and VBS gating. |
CiUnpackPolicy (sub_1800AD8EC) |
0.60 | Behavioral | Both builds call memmove; the referenced symbol difference is only an address shift, not a memcpy-to-memmove switch. |
CipMinCryptToAuthRoot2 (sub_180054BC4) |
0.50 | Behavioral | Refactored policy verification logic for HVCI compatibility. |
9. Unmatched Functions
One function was added in the patched build: SbpParseSignatureDatabaseFromBuffer (@0x18001E1DC). The patch extracted the EFI signature-database parsing/allocation logic (previously inline in SbpParseSignatureDatabase) into this new helper and added the integer-overflow checks described in Finding 4. No functions were removed. All other modifications occurred inline within existing functions.
10. Confidence & Caveats
- Confidence Level: High for the diff facts, which are verified directly against both binaries. The decompilation and assembly confirm the
bit 2early-return being removed fromSIPolicyIsPolicyPlatformSecured(CWE-358) and the single entry0x4C3279F4784C4414/0xD1DA542FBF0A5A6being dropped fromSIPolicyIsPolicyMustBeWindowsSigned. The direction of the second change was re-checked against its caller and is a relaxation of a Windows-signing mandate, not a trust revocation. The end-to-end exploit impact of Finding 1 is less certain (see below), which is why it is rated Medium rather than High. - Assumptions:
- The exact conditions that set bit 2 (
value & 4) at offset+0x710of the SI policy structure are not visible in these two functions and are inferred to originate in policy parsing/setup. A researcher must trace policy initialization to find what sets this bit and whether it is attacker-influenceable. - Verification Needed: The two callers of
SIPolicyIsPolicyPlatformSecuredwere located in this binary: one honors a policy'sPlatformSecureSettingsecurity-policy query only for platform-secured policies, and one proceeds with image validation once a loaded policy is platform-secured. A dynamic PoC would still be needed to show that an attacker-loadable policy can carry+0x710bit 2 set without the fixed identity and thereby gain a meaningful trust elevation.