From 3370652dfc2f1d0c37e067b31ee37af67a6320c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sun, 22 May 2022 18:11:18 +0200 Subject: [PATCH] [NTOS:SE] Fix locking in SepDuplicateToken() and SepPerformTokenFiltering() (#4523) Shared locking must be used on the source token as it is accessed for reading only. This fixes in particular the kmtest SeTokenFiltering that would hang otherwise on a (wrong) exclusive locking. - SepPerformTokenFiltering(): Always shared-lock the source token. Its callers (NtFilterToken and SeFilterToken) just need to sanitize and put the parameters in correct form before calling this helper function. - Sync comments in NtFilterToken() with SeFilterToken(). --- ntoskrnl/se/token.c | 66 +++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/ntoskrnl/se/token.c b/ntoskrnl/se/token.c index 96e972f2c5b..aad1321abd6 100644 --- a/ntoskrnl/se/token.c +++ b/ntoskrnl/se/token.c @@ -1059,7 +1059,7 @@ SepDuplicateToken( AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession; /* Lock the source token and copy the mutable fields */ - SepAcquireTokenLockExclusive(Token); + SepAcquireTokenLockShared(Token); AccessToken->SessionId = Token->SessionId; RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId); @@ -1286,23 +1286,20 @@ SepDuplicateToken( Token->DefaultDacl->AclSize); } - /* Unlock the source token */ - SepReleaseTokenLock(Token); - - /* Return the token */ + /* Return the token to the caller */ *NewAccessToken = AccessToken; Status = STATUS_SUCCESS; Quit: if (!NT_SUCCESS(Status)) { - /* Unlock the source token */ - SepReleaseTokenLock(Token); - /* Dereference the token, the delete procedure will clean it up */ ObDereferenceObject(AccessToken); } + /* Unlock the source token */ + SepReleaseTokenLock(Token); + return Status; } @@ -2086,8 +2083,8 @@ SepPerformTokenFiltering( _In_ KPROCESSOR_MODE PreviousMode, _Out_ PTOKEN *FilteredToken) { - PTOKEN AccessToken; NTSTATUS Status; + PTOKEN AccessToken; PVOID EndMem; ULONG RestrictedSidsLength; ULONG PrivilegesLength; @@ -2100,10 +2097,12 @@ SepPerformTokenFiltering( BOOLEAN WantPrivilegesDisabled; BOOLEAN FoundPrivilege; BOOLEAN FoundGroup; + PAGED_CODE(); - /* Ensure that the token we get is not garbage */ + /* Ensure that the source token is valid, and lock it */ ASSERT(Token); + SepAcquireTokenLockShared(Token); /* Assume the caller doesn't want privileges disabled */ WantPrivilegesDisabled = FALSE; @@ -2159,6 +2158,9 @@ SepPerformTokenFiltering( if (!NT_SUCCESS(Status)) { DPRINT1("SepPerformTokenFiltering(): Failed to create the filtered token object (Status 0x%lx)\n", Status); + + /* Unlock the source token and bail out */ + SepReleaseTokenLock(Token); return Status; } @@ -2168,10 +2170,7 @@ SepPerformTokenFiltering( /* Set up a lock for the new token */ Status = SepCreateTokenLock(AccessToken); if (!NT_SUCCESS(Status)) - { - ObDereferenceObject(AccessToken); - return Status; - } + goto Quit; /* Allocate new IDs for the token */ ExAllocateLocallyUniqueId(&AccessToken->TokenId); @@ -2576,7 +2575,7 @@ SepPerformTokenFiltering( AccessToken->TokenFlags |= TOKEN_IS_RESTRICTED; } - /* We've finally filtered the token, give it to the caller */ + /* We've finally filtered the token, return it to the caller */ *FilteredToken = AccessToken; Status = STATUS_SUCCESS; DPRINT("SepPerformTokenFiltering(): The token has been filtered!\n"); @@ -2584,10 +2583,13 @@ SepPerformTokenFiltering( Quit: if (!NT_SUCCESS(Status)) { - /* Dereference the token */ + /* Dereference the created token */ ObDereferenceObject(AccessToken); } + /* Unlock the source token */ + SepReleaseTokenLock(Token); + return Status; } @@ -2903,12 +2905,6 @@ SepCreateSystemAnonymousLogonTokenNoEveryone(VOID) * operations and that the access token has been filtered. STATUS_INVALID_PARAMETER * is returned if one or more of the parameter are not valid. A failure NTSTATUS code * is returned otherwise. - * - * @remarks - * WARNING -- The caller IS RESPONSIBLE for locking the existing access token - * before attempting to do any kind of filtering operation into - * the token. The lock MUST BE RELEASED after this kernel routine - * has finished doing its work. */ NTSTATUS NTAPI @@ -2925,6 +2921,7 @@ SeFilterToken( ULONG PrivilegesCount = 0; ULONG SidsCount = 0; ULONG RestrictedSidsCount = 0; + PAGED_CODE(); /* Begin copying the counters */ @@ -2969,11 +2966,11 @@ SeFilterToken( NULL); if (!NT_SUCCESS(Status)) { - DPRINT1("SeFilterToken(): Failed to insert the token (Status 0x%lx)\n", Status); + DPRINT1("SeFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status); return Status; } - /* Give it to the caller */ + /* Return it to the caller */ *FilteredToken = AccessToken; return Status; } @@ -6661,7 +6658,7 @@ NtFilterToken( } _SEH2_END; - /* Reference the token and do the job */ + /* Reference the token */ Status = ObReferenceObjectByHandle(ExistingTokenHandle, TOKEN_DUPLICATE, SeTokenObjectType, @@ -6674,9 +6671,6 @@ NtFilterToken( return Status; } - /* Lock the token */ - SepAcquireTokenLockExclusive(Token); - /* Capture the group SIDs */ if (SidsToDisable != NULL) { @@ -6734,7 +6728,7 @@ NtFilterToken( } } - /* Call the internal API so that it can filter the token for us */ + /* Call the internal API */ Status = SepPerformTokenFiltering(Token, CapturedPrivileges, CapturedSids, @@ -6751,7 +6745,7 @@ NtFilterToken( goto Quit; } - /* We got our filtered token, insert it to the handle */ + /* Insert the filtered token and retrieve a handle to it */ Status = ObInsertObject(FilteredToken, NULL, HandleInfo.GrantedAccess, @@ -6760,11 +6754,11 @@ NtFilterToken( &FilteredTokenHandle); if (!NT_SUCCESS(Status)) { - DPRINT1("NtFilterToken(): Failed to insert the filtered token object into the handle (Status 0x%lx)\n", Status); + DPRINT1("NtFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status); goto Quit; } - /* And give it to the caller once we're done */ + /* And return it to the caller once we're done */ _SEH2_TRY { *NewTokenHandle = FilteredTokenHandle; @@ -6777,17 +6771,15 @@ NtFilterToken( _SEH2_END; Quit: - /* Unlock and dereference the token */ - SepReleaseTokenLock(Token); + /* Dereference the token */ ObDereferenceObject(Token); - /* Release all the stuff we've captured */ + /* Release all the captured data */ if (CapturedSids != NULL) { SeReleaseSidAndAttributesArray(CapturedSids, PreviousMode, TRUE); - CapturedSids = NULL; } if (CapturedPrivileges != NULL) @@ -6795,7 +6787,6 @@ Quit: SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, TRUE); - CapturedPrivileges = NULL; } if (CapturedRestrictedSids != NULL) @@ -6803,7 +6794,6 @@ Quit: SeReleaseSidAndAttributesArray(CapturedRestrictedSids, PreviousMode, TRUE); - CapturedRestrictedSids = NULL; } return Status;