https://git.reactos.org/?p=reactos.git;a=commitdiff;h=44b8e5caac51157cc6c01…
commit 44b8e5caac51157cc6c01d1c07810fc971d3e9ea
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Sun Jan 17 21:46:30 2021 +0100
Commit: Victor Perevertkin <victor(a)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;
}