https://git.reactos.org/?p=reactos.git;a=commitdiff;h=44b8e5caac51157cc6c01d...
commit 44b8e5caac51157cc6c01d1c07810fc971d3e9ea Author: George Bișoc george.bisoc@reactos.org AuthorDate: Sun Jan 17 21:46:30 2021 +0100 Commit: Victor Perevertkin victor@perevertkin.ru CommitDate: Thu Mar 4 16:22:56 2021 +0300
[NTOS:SE] Complete the SepCompareTokens implementation
* Implement SepCompareSidAndAttributesFromTokens and SepComparePrivilegeAndAttributesFromTokens functions for array elements comparison * Implement the token comparison code in SepCompareTokens function * Add a missing PAGED_CODE() in SepCompareTokens as most of the token comparison code is paged * Use SAL annotations for SepCompareTokens and NtCompareTokens --- ntoskrnl/se/token.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 228 insertions(+), 16 deletions(-)
diff --git a/ntoskrnl/se/token.c b/ntoskrnl/se/token.c index 1f12e0109d2..872e5e15d0d 100644 --- a/ntoskrnl/se/token.c +++ b/ntoskrnl/se/token.c @@ -135,12 +135,173 @@ SepDeleteTokenLock( ExFreePoolWithTag(Token->TokenLock, TAG_SE_TOKEN_LOCK); }
-static NTSTATUS -SepCompareTokens(IN PTOKEN FirstToken, - IN PTOKEN SecondToken, - OUT PBOOLEAN Equal) +/** + * @brief + * Compares the elements of SID arrays provided by tokens. + * The elements that are being compared for equality are + * the SIDs and their attributes. + * + * @param[in] SidArrayToken1 + * SID array from the first token. + * + * @param[in] CountSidArray1 + * SID count array from the first token. + * + * @param[in] SidArrayToken2 + * SID array from the second token. + * + * @param[in] CountSidArray2 + * SID count array from the second token. + * + * @return + * Returns TRUE if the elements match from either arrays, + * FALSE otherwise. + */ +static +BOOLEAN +SepCompareSidAndAttributesFromTokens( + _In_ PSID_AND_ATTRIBUTES SidArrayToken1, + _In_ ULONG CountSidArray1, + _In_ PSID_AND_ATTRIBUTES SidArrayToken2, + _In_ ULONG CountSidArray2) +{ + ULONG FirstCount, SecondCount; + PSID_AND_ATTRIBUTES FirstSidArray, SecondSidArray; + PAGED_CODE(); + + /* Bail out if index counters provided are not equal */ + if (CountSidArray1 != CountSidArray2) + { + DPRINT("SepCompareSidAndAttributesFromTokens(): Index counters are not the same!\n"); + return FALSE; + } + + /* Loop over the SID arrays and compare them */ + for (FirstCount = 0; FirstCount < CountSidArray1; FirstCount++) + { + for (SecondCount = 0; SecondCount < CountSidArray2; SecondCount++) + { + FirstSidArray = &SidArrayToken1[FirstCount]; + SecondSidArray = &SidArrayToken2[SecondCount]; + + if (RtlEqualSid(FirstSidArray->Sid, SecondSidArray->Sid) && + FirstSidArray->Attributes == SecondSidArray->Attributes) + { + break; + } + } + + /* We've exhausted the array of the second token without finding this one */ + if (SecondCount == CountSidArray2) + { + DPRINT("SepCompareSidAndAttributesFromTokens(): No matching elements could be found in either token!\n"); + return FALSE; + } + } + + return TRUE; +} + +/** + * @brief + * Compares the elements of privilege arrays provided by tokens. + * The elements that are being compared for equality are + * the privileges and their attributes. + * + * @param[in] PrivArrayToken1 + * Privilege array from the first token. + * + * @param[in] CountPrivArray1 + * Privilege count array from the first token. + * + * @param[in] PrivArrayToken2 + * Privilege array from the second token. + * + * @param[in] CountPrivArray2 + * Privilege count array from the second token. + * + * @return + * Returns TRUE if the elements match from either arrays, + * FALSE otherwise. + */ +static +BOOLEAN +SepComparePrivilegeAndAttributesFromTokens( + _In_ PLUID_AND_ATTRIBUTES PrivArrayToken1, + _In_ ULONG CountPrivArray1, + _In_ PLUID_AND_ATTRIBUTES PrivArrayToken2, + _In_ ULONG CountPrivArray2) +{ + ULONG FirstCount, SecondCount; + PLUID_AND_ATTRIBUTES FirstPrivArray, SecondPrivArray; + PAGED_CODE(); + + /* Bail out if index counters provided are not equal */ + if (CountPrivArray1 != CountPrivArray2) + { + DPRINT("SepComparePrivilegeAndAttributesFromTokens(): Index counters are not the same!\n"); + return FALSE; + } + + /* Loop over the privilege arrays and compare them */ + for (FirstCount = 0; FirstCount < CountPrivArray1; FirstCount++) + { + for (SecondCount = 0; SecondCount < CountPrivArray2; SecondCount++) + { + FirstPrivArray = &PrivArrayToken1[FirstCount]; + SecondPrivArray = &PrivArrayToken2[SecondCount]; + + if (RtlEqualLuid(&FirstPrivArray->Luid, &SecondPrivArray->Luid) && + FirstPrivArray->Attributes == SecondPrivArray->Attributes) + { + break; + } + } + + /* We've exhausted the array of the second token without finding this one */ + if (SecondCount == CountPrivArray2) + { + DPRINT("SepComparePrivilegeAndAttributesFromTokens(): No matching elements could be found in either token!\n"); + return FALSE; + } + } + + return TRUE; +} + +/** + * @brief + * Compares tokens if they're equal based on all the following properties. If all + * of the said conditions are met then the tokens are deemed as equal. + * + * - Every SID that is present in either token is also present in the other one. + * - Both or none of the tokens are restricted. + * - If both tokens are restricted, every SID that is restricted in either token is + * also restricted in the other one. + * - Every privilege present in either token is also present in the other one. + * + * @param[in] FirstToken + * The first token. + * + * @param[in] SecondToken + * The second token. + * + * @param[out] Equal + * The retrieved value which determines if the tokens are + * equal or not. + * + * @return + * Returns STATUS_SUCCESS. + */ +static +NTSTATUS +SepCompareTokens( + _In_ PTOKEN FirstToken, + _In_ PTOKEN SecondToken, + _Out_ PBOOLEAN Equal) { BOOLEAN Restricted, IsEqual = FALSE; + PAGED_CODE();
ASSERT(FirstToken != SecondToken);
@@ -148,21 +309,53 @@ SepCompareTokens(IN PTOKEN FirstToken, SepAcquireTokenLockShared(FirstToken); SepAcquireTokenLockShared(SecondToken);
- /* FIXME: Check if every SID that is present in either token is also present in the other one */ + /* Check if every SID that is present in either token is also present in the other one */ + if (!SepCompareSidAndAttributesFromTokens(FirstToken->UserAndGroups, + FirstToken->UserAndGroupCount, + SecondToken->UserAndGroups, + SecondToken->UserAndGroupCount)) + { + goto Quit; + }
+ /* Is one token restricted but the other isn't? */ Restricted = SeTokenIsRestricted(FirstToken); - if (Restricted == SeTokenIsRestricted(SecondToken)) + if (Restricted != SeTokenIsRestricted(SecondToken)) + { + /* If that's the case then bail out */ + goto Quit; + } + + /* + * If both tokens are restricted check if every SID + * that is restricted in either token is also restricted + * in the other one. + */ + if (Restricted) { - if (Restricted) + if (!SepCompareSidAndAttributesFromTokens(FirstToken->RestrictedSids, + FirstToken->RestrictedSidCount, + SecondToken->RestrictedSids, + SecondToken->RestrictedSidCount)) { - /* FIXME: Check if every SID that is restricted in either token is also restricted in the other one */ + goto Quit; } + }
- /* FIXME: Check if every privilege that is present in either token is also present in the other one */ - DPRINT1("FIXME: Pretending tokens are equal!\n"); - IsEqual = TRUE; + /* Check if every privilege present in either token is also present in the other one */ + if (!SepComparePrivilegeAndAttributesFromTokens(FirstToken->Privileges, + FirstToken->PrivilegeCount, + SecondToken->Privileges, + SecondToken->PrivilegeCount)) + { + goto Quit; }
+ /* If we're here then the tokens are equal */ + IsEqual = TRUE; + DPRINT("SepCompareTokens(): Tokens are equal!\n"); + +Quit: /* Unlock the tokens */ SepReleaseTokenLock(SecondToken); SepReleaseTokenLock(FirstToken); @@ -3921,14 +4114,29 @@ NtOpenThreadToken(IN HANDLE ThreadHandle, TokenHandle); }
-/* - * @unimplemented +/** + * @brief + * Compares tokens if they're equal or not. + * + * @param[in] FirstToken + * The first token. + * + * @param[in] SecondToken + * The second token. + * + * @param[out] Equal + * The retrieved value which determines if the tokens are + * equal or not. + * + * @return + * Returns STATUS_SUCCESS, otherwise it returns a failure NTSTATUS code. */ NTSTATUS NTAPI -NtCompareTokens(IN HANDLE FirstTokenHandle, - IN HANDLE SecondTokenHandle, - OUT PBOOLEAN Equal) +NtCompareTokens( + _In_ HANDLE FirstTokenHandle, + _In_ HANDLE SecondTokenHandle, + _Out_ PBOOLEAN Equal) { KPROCESSOR_MODE PreviousMode; PTOKEN FirstToken, SecondToken; @@ -3960,7 +4168,10 @@ NtCompareTokens(IN HANDLE FirstTokenHandle, (PVOID*)&FirstToken, NULL); if (!NT_SUCCESS(Status)) + { + DPRINT1("ObReferenceObjectByHandle() failed (Status 0x%lx)\n", Status); return Status; + }
Status = ObReferenceObjectByHandle(SecondTokenHandle, TOKEN_QUERY, @@ -3970,6 +4181,7 @@ NtCompareTokens(IN HANDLE FirstTokenHandle, NULL); if (!NT_SUCCESS(Status)) { + DPRINT1("ObReferenceObjectByHandle() failed (Status 0x%lx)\n", Status); ObDereferenceObject(FirstToken); return Status; }