diff --git a/ntoskrnl/include/internal/se.h b/ntoskrnl/include/internal/se.h index de65310b331..b81585c64eb 100644 --- a/ntoskrnl/include/internal/se.h +++ b/ntoskrnl/include/internal/se.h @@ -390,6 +390,17 @@ SepRemoveUserGroupToken( _Inout_ PTOKEN Token, _In_ ULONG Index); +ULONG +SepComputeAvailableDynamicSpace( + _In_ ULONG DynamicCharged, + _In_ PSID PrimaryGroup, + _In_opt_ PACL DefaultDacl); + +NTSTATUS +SepRebuildDynamicPartOfToken( + _In_ PTOKEN Token, + _In_ ULONG NewDynamicPartSize); + BOOLEAN NTAPI SeTokenCanImpersonate( diff --git a/ntoskrnl/se/token.c b/ntoskrnl/se/token.c index ad2dd8e806f..33354f2ea8b 100644 --- a/ntoskrnl/se/token.c +++ b/ntoskrnl/se/token.c @@ -636,6 +636,147 @@ SepRemoveUserGroupToken( Token->UserAndGroupCount--; } +/** + * @brief + * Computes the exact available dynamic area of an access + * token whilst querying token statistics. + * + * @param[in] DynamicCharged + * The current charged dynamic area of an access token. + * This must not be 0! + * + * @param[in] PrimaryGroup + * A pointer to a primary group SID. + * + * @param[in] DefaultDacl + * If provided, this pointer points to a default DACL of an + * access token. + * + * @return + * Returns the calculated available dynamic area. + */ +ULONG +SepComputeAvailableDynamicSpace( + _In_ ULONG DynamicCharged, + _In_ PSID PrimaryGroup, + _In_opt_ PACL DefaultDacl) +{ + ULONG DynamicAvailable; + + PAGED_CODE(); + + /* A token's dynamic area is always charged */ + ASSERT(DynamicCharged != 0); + + /* + * Take into account the default DACL if + * the token has one. Otherwise the occupied + * space is just the present primary group. + */ + DynamicAvailable = DynamicCharged - RtlLengthSid(PrimaryGroup); + if (DefaultDacl) + { + DynamicAvailable -= DefaultDacl->AclSize; + } + + return DynamicAvailable; +} + +/** + * @brief + * Re-builds the dynamic part area of an access token + * during an a default DACL or primary group replacement + * within the said token if the said dynamic area can't + * hold the new security content. + * + * @param[in] AccessToken + * A pointer to an access token where its dynamic part + * is to be re-built and expanded based upon the new + * dynamic part size provided by the caller. Dynamic + * part expansion is not always guaranteed. See Remarks + * for further information. + * + * @param[in] NewDynamicPartSize + * The new dynamic part size. + * + * @return + * Returns STATUS_SUCCESS if the function has completed its + * operations successfully. STATUS_INSUFFICIENT_RESOURCES + * is returned if the new dynamic part could not be allocated. + * + * @remarks + * STATUS_SUCCESS does not indicate if the function has re-built + * the dynamic part of a token. If the current dynamic area size + * suffices the new dynamic area length provided by the caller + * then the dynamic area can hold the new security content buffer + * so dynamic part expansion is not necessary. + */ +NTSTATUS +SepRebuildDynamicPartOfToken( + _Inout_ PTOKEN AccessToken, + _In_ ULONG NewDynamicPartSize) +{ + PVOID NewDynamicPart; + PVOID PreviousDynamicPart; + ULONG CurrentDynamicLength; + + PAGED_CODE(); + + /* Sanity checks */ + ASSERT(AccessToken); + ASSERT(NewDynamicPartSize != 0); + + /* + * Compute the exact length of the available + * dynamic part of the access token. + */ + CurrentDynamicLength = AccessToken->DynamicAvailable + RtlLengthSid(AccessToken->PrimaryGroup); + if (AccessToken->DefaultDacl) + { + CurrentDynamicLength += AccessToken->DefaultDacl->AclSize; + } + + /* + * Figure out if the current dynamic part is too small + * to fit new contents inside the said dynamic part. + * Rebuild the dynamic area and expand it if necessary. + */ + if (CurrentDynamicLength < NewDynamicPartSize) + { + NewDynamicPart = ExAllocatePoolWithTag(PagedPool, + NewDynamicPartSize, + TAG_TOKEN_DYNAMIC); + if (NewDynamicPart == NULL) + { + DPRINT1("SepRebuildDynamicPartOfToken(): Insufficient resources to allocate new dynamic part!\n"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Copy the existing dynamic part */ + PreviousDynamicPart = AccessToken->DynamicPart; + RtlCopyMemory(NewDynamicPart, PreviousDynamicPart, CurrentDynamicLength); + + /* Update the available dynamic area and assign new dynamic */ + AccessToken->DynamicAvailable += NewDynamicPartSize - CurrentDynamicLength; + AccessToken->DynamicPart = NewDynamicPart; + + /* Move the contents (primary group and default DACL) addresses as well */ + AccessToken->PrimaryGroup = (PSID)((ULONG_PTR)AccessToken->DynamicPart + + ((ULONG_PTR)AccessToken->PrimaryGroup - (ULONG_PTR)PreviousDynamicPart)); + if (AccessToken->DefaultDacl != NULL) + { + AccessToken->DefaultDacl = (PACL)((ULONG_PTR)AccessToken->DynamicPart + + ((ULONG_PTR)AccessToken->DefaultDacl - (ULONG_PTR)PreviousDynamicPart)); + } + + /* And discard the previous dynamic part */ + DPRINT("SepRebuildDynamicPartOfToken(): The dynamic part has been re-built with success!\n"); + ExFreePoolWithTag(PreviousDynamicPart, TAG_TOKEN_DYNAMIC); + } + + return STATUS_SUCCESS; +} + /** * @unimplemented * @brief diff --git a/ntoskrnl/se/tokencls.c b/ntoskrnl/se/tokencls.c index 8bb5598ce9e..4810996114e 100644 --- a/ntoskrnl/se/tokencls.c +++ b/ntoskrnl/se/tokencls.c @@ -398,7 +398,7 @@ SeQueryInformationToken( ts->TokenType = Token->TokenType; ts->ImpersonationLevel = Token->ImpersonationLevel; ts->DynamicCharged = Token->DynamicCharged; - ts->DynamicAvailable = Token->DynamicAvailable; + ts->DynamicAvailable = SepComputeAvailableDynamicSpace(Token->DynamicCharged, Token->PrimaryGroup, Token->DefaultDacl); ts->GroupCount = Token->UserAndGroupCount - 1; ts->PrivilegeCount = Token->PrivilegeCount; ts->ModifiedId = Token->ModifiedId; @@ -854,7 +854,7 @@ NtQueryInformationToken( ts->TokenType = Token->TokenType; ts->ImpersonationLevel = Token->ImpersonationLevel; ts->DynamicCharged = Token->DynamicCharged; - ts->DynamicAvailable = Token->DynamicAvailable; + ts->DynamicAvailable = SepComputeAvailableDynamicSpace(Token->DynamicCharged, Token->PrimaryGroup, Token->DefaultDacl); ts->GroupCount = Token->UserAndGroupCount - 1; ts->PrivilegeCount = Token->PrivilegeCount; ts->ModifiedId = Token->ModifiedId; @@ -1116,7 +1116,7 @@ NtQueryInformationToken( * the operation in question. A failure NTSTATUS code is returned otherwise. * * @remarks - * The function is partly implemented, mainly TokenOrigin and TokenDefaultDacl. + * The function is partly implemented, mainly TokenOrigin. */ _Must_inspect_result_ __kernel_entry @@ -1227,8 +1227,9 @@ NtSetInformationToken( if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP)) { PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; + ULONG_PTR PrimaryGroup; PSID InputSid = NULL, CapturedSid; - ULONG PrimaryGroupIndex; + ULONG PrimaryGroupIndex, NewDynamicLength; _SEH2_TRY { @@ -1251,17 +1252,73 @@ NtSetInformationToken( /* Lock the token */ SepAcquireTokenLockExclusive(Token); - /* Find the primary group amongst the existing token user and groups */ - Status = SepFindPrimaryGroupAndDefaultOwner(Token, - CapturedSid, - NULL, - &PrimaryGroupIndex, - NULL); + /* + * We can whack the token's primary group only if + * the charged dynamic space boundary allows us + * to do so. Exceeding this boundary and we're + * busted out. + */ + NewDynamicLength = RtlLengthSid(CapturedSid) + + Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0; + if (NewDynamicLength > Token->DynamicCharged) + { + SepReleaseTokenLock(Token); + SepReleaseSid(CapturedSid, PreviousMode, FALSE); + Status = STATUS_ALLOTTED_SPACE_EXCEEDED; + DPRINT1("NtSetInformationToken(): Couldn't assign new primary group, space exceeded (current length %u, new length %lu)\n", + Token->DynamicCharged, NewDynamicLength); + goto Cleanup; + } + + /* + * The dynamic part of the token may require a rebuild + * if the current dynamic area is too small. If not then + * we're pretty much good as is. + */ + Status = SepRebuildDynamicPartOfToken(Token, NewDynamicLength); if (NT_SUCCESS(Status)) { - /* Found it */ - Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid; - ExAllocateLocallyUniqueId(&Token->ModifiedId); + /* Find the primary group amongst the existing token user and groups */ + Status = SepFindPrimaryGroupAndDefaultOwner(Token, + CapturedSid, + NULL, + &PrimaryGroupIndex, + NULL); + if (NT_SUCCESS(Status)) + { + /* + * We have found it. Add the length of + * the previous primary group SID to the + * available dynamic area. + */ + Token->DynamicAvailable += RtlLengthSid(Token->PrimaryGroup); + + /* + * Move the default DACL if it's not at the + * head of the dynamic part. + */ + if ((Token->DefaultDacl) && + ((PULONG)(Token->DefaultDacl) != Token->DynamicPart)) + { + RtlMoveMemory(Token->DynamicPart, + Token->DefaultDacl, + RtlLengthSid(Token->PrimaryGroup)); + Token->DefaultDacl = (PACL)(Token->DynamicPart); + } + + /* Take away available space from the dynamic area */ + Token->DynamicAvailable -= RtlLengthSid(Token->UserAndGroups[PrimaryGroupIndex].Sid); + + /* And assign the primary group */ + PrimaryGroup = (ULONG_PTR)(Token->DynamicPart) + Token->DefaultDacl ? + Token->DefaultDacl->AclSize : 0; + RtlCopySid(RtlLengthSid(Token->UserAndGroups[PrimaryGroupIndex].Sid), + (PVOID)PrimaryGroup, + Token->UserAndGroups[PrimaryGroupIndex].Sid); + Token->PrimaryGroup = (PSID)PrimaryGroup; + + ExAllocateLocallyUniqueId(&Token->ModifiedId); + } } /* Unlock the token */ @@ -1309,68 +1366,76 @@ NtSetInformationToken( &CapturedAcl); if (NT_SUCCESS(Status)) { - ULONG DynamicLength; + ULONG NewDynamicLength; + ULONG_PTR Acl; /* Lock the token */ SepAcquireTokenLockExclusive(Token); - // - // NOTE: So far our dynamic area only contains - // the default dacl, so this makes the following - // code pretty simple. The day where it stores - // other data, the code will require adaptations. - // - - DynamicLength = Token->DynamicAvailable; - // Add here any other data length present in the dynamic area... - if (Token->DefaultDacl) - DynamicLength += Token->DefaultDacl->AclSize; - - /* Reallocate the dynamic area if it is too small */ - Status = STATUS_SUCCESS; - if ((DynamicLength < CapturedAcl->AclSize) || - (Token->DynamicPart == NULL)) + /* + * We can whack the token's default DACL only if + * the charged dynamic space boundary allows us + * to do so. Exceeding this boundary and we're + * busted out. + */ + NewDynamicLength = CapturedAcl->AclSize + RtlLengthSid(Token->PrimaryGroup); + if (NewDynamicLength > Token->DynamicCharged) { - PVOID NewDynamicPart; - - NewDynamicPart = ExAllocatePoolWithTag(PagedPool, - CapturedAcl->AclSize, - TAG_TOKEN_DYNAMIC); - if (NewDynamicPart == NULL) - { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - else - { - if (Token->DynamicPart != NULL) - { - // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength); - ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC); - } - Token->DynamicPart = NewDynamicPart; - Token->DynamicAvailable = 0; - } - } - else - { - Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize; + SepReleaseTokenLock(Token); + SepReleaseAcl(CapturedAcl, PreviousMode, TRUE); + Status = STATUS_ALLOTTED_SPACE_EXCEEDED; + DPRINT1("NtSetInformationToken(): Couldn't assign new default DACL, space exceeded (current length %u, new length %lu)\n", + Token->DynamicCharged, NewDynamicLength); + goto Cleanup; } + /* + * The dynamic part of the token may require a rebuild + * if the current dynamic area is too small. If not then + * we're pretty much good as is. + */ + Status = SepRebuildDynamicPartOfToken(Token, NewDynamicLength); if (NT_SUCCESS(Status)) { + /* + * Before setting up a new DACL for the + * token object we add up the size of + * the old DACL to the available dynamic + * area + */ + if (Token->DefaultDacl) + { + Token->DynamicAvailable += Token->DefaultDacl->AclSize; + } + + /* + * Move the primary group if it's not at the + * head of the dynamic part. + */ + if ((PULONG)(Token->PrimaryGroup) != Token->DynamicPart) + { + RtlMoveMemory(Token->DynamicPart, + Token->PrimaryGroup, + RtlLengthSid(Token->PrimaryGroup)); + Token->PrimaryGroup = (PSID)(Token->DynamicPart); + } + + /* Take away available space from the dynamic area */ + Token->DynamicAvailable -= CapturedAcl->AclSize; + /* Set the new dacl */ - Token->DefaultDacl = (PVOID)Token->DynamicPart; - RtlCopyMemory(Token->DefaultDacl, + Acl = (ULONG_PTR)(Token->DynamicPart) + RtlLengthSid(Token->PrimaryGroup); + RtlCopyMemory((PVOID)Acl, CapturedAcl, CapturedAcl->AclSize); + Token->DefaultDacl = (PACL)Acl; ExAllocateLocallyUniqueId(&Token->ModifiedId); } - /* Unlock the token */ + /* Unlock the token and release the ACL */ SepReleaseTokenLock(Token); - - ExFreePoolWithTag(CapturedAcl, TAG_ACL); + SepReleaseAcl(CapturedAcl, PreviousMode, TRUE); } } else diff --git a/ntoskrnl/se/tokenlif.c b/ntoskrnl/se/tokenlif.c index c3900c2dce5..9f6e9aef9c8 100644 --- a/ntoskrnl/se/tokenlif.c +++ b/ntoskrnl/se/tokenlif.c @@ -12,6 +12,10 @@ #define NDEBUG #include +/* DEFINES ********************************************************************/ + +#define SE_TOKEN_DYNAMIC_SLIM 500 + /* PRIVATE FUNCTIONS *********************************************************/ /** @@ -121,7 +125,8 @@ SepCreateToken( ULONG PrivilegesLength; ULONG UserGroupsLength; ULONG VariableLength; - ULONG TotalSize; + ULONG DynamicPartSize, TotalSize; + ULONG TokenPagedCharges; ULONG i; PAGED_CODE(); @@ -169,13 +174,34 @@ SepCreateToken( VariableLength = PrivilegesLength + UserGroupsLength; TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; + /* + * A token is considered slim if it has the default dynamic + * contents, or in other words, the primary group and ACL. + * We judge if such contents are default by checking their + * total size if it's over the range. On Windows this range + * is 0x1F4 (aka 500). If the size of the whole dynamic contents + * is over that range then the token is considered fat and + * the token will be charged the whole of its token body length + * plus the dynamic size. + */ + DynamicPartSize = DefaultDacl ? DefaultDacl->AclSize : 0; + DynamicPartSize += RtlLengthSid(PrimaryGroup); + if (DynamicPartSize > SE_TOKEN_DYNAMIC_SLIM) + { + TokenPagedCharges = DynamicPartSize + TotalSize; + } + else + { + TokenPagedCharges = SE_TOKEN_DYNAMIC_SLIM + TotalSize; + } + Status = ObCreateObject(PreviousMode, SeTokenObjectType, ObjectAttributes, PreviousMode, NULL, TotalSize, - 0, + TokenPagedCharges, 0, (PVOID*)&AccessToken); if (!NT_SUCCESS(Status)) @@ -203,6 +229,7 @@ SepCreateToken( AccessToken->ExpirationTime = *ExpirationTime; AccessToken->ModifiedId = ModifiedId; + AccessToken->DynamicCharged = TokenPagedCharges - TotalSize; AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED; @@ -332,27 +359,48 @@ SepCreateToken( goto Quit; } - AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; - AccessToken->DefaultOwnerIndex = DefaultOwnerIndex; + /* + * Now allocate the token's dynamic information area + * and set the data. The dynamic part consists of two + * contents, the primary group SID and the default DACL + * of the token, in this strict order. + */ + AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, + DynamicPartSize, + TAG_TOKEN_DYNAMIC); + if (AccessToken->DynamicPart == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quit; + } - /* Now allocate the token's dynamic information area and set the data */ - AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area. - AccessToken->DynamicPart = NULL; + /* Unused memory in the dynamic area */ + AccessToken->DynamicAvailable = 0; + + /* + * Assign the primary group to the token + * and put it in the dynamic part as well. + */ + EndMem = (PVOID)AccessToken->DynamicPart; + AccessToken->PrimaryGroup = EndMem; + RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid), + EndMem, + AccessToken->UserAndGroups[PrimaryGroupIndex].Sid); + AccessToken->DefaultOwnerIndex = DefaultOwnerIndex; + EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid)); + + /* + * We have assigned a primary group and put it in the + * dynamic part, now it's time to copy the provided + * default DACL (if it's provided to begin with) into + * the DACL field of the token and put it at the end + * tail of the dynamic part too. + */ if (DefaultDacl != NULL) { - AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, - DefaultDacl->AclSize, - TAG_TOKEN_DYNAMIC); - if (AccessToken->DynamicPart == NULL) - { - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quit; - } - - EndMem = (PVOID)AccessToken->DynamicPart; AccessToken->DefaultDacl = EndMem; - RtlCopyMemory(AccessToken->DefaultDacl, + RtlCopyMemory(EndMem, DefaultDacl, DefaultDacl->AclSize); } @@ -434,7 +482,7 @@ SepDuplicateToken( PVOID EndMem; ULONG PrimaryGroupIndex; ULONG VariableLength; - ULONG TotalSize; + ULONG DynamicPartSize, TotalSize; ULONG PrivilegesIndex, GroupsIndex; PAGED_CODE(); @@ -443,14 +491,22 @@ SepDuplicateToken( VariableLength = Token->VariableLength; TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; + /* + * Compute how much size we need to allocate + * the dynamic part of the newly duplicated + * token. + */ + DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0; + DynamicPartSize += RtlLengthSid(Token->PrimaryGroup); + Status = ObCreateObject(PreviousMode, SeTokenObjectType, ObjectAttributes, PreviousMode, NULL, TotalSize, - 0, - 0, + Token->DynamicCharged, + TotalSize, (PVOID*)&AccessToken); if (!NT_SUCCESS(Status)) { @@ -484,6 +540,7 @@ SepDuplicateToken( AccessToken->ParentTokenId = Token->ParentTokenId; AccessToken->ExpirationTime = Token->ExpirationTime; AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession; + AccessToken->DynamicCharged = Token->DynamicCharged; /* Lock the source token and copy the mutable fields */ SepAcquireTokenLockShared(Token); @@ -584,9 +641,6 @@ SepDuplicateToken( goto Quit; } - AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; - AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex; - /* Copy the restricted SIDs */ AccessToken->RestrictedSidCount = 0; AccessToken->RestrictedSids = NULL; @@ -684,31 +738,40 @@ SepDuplicateToken( } } - // - // NOTE: So far our dynamic area only contains - // the default dacl, so this makes the following - // code pretty simple. The day where it stores - // other data, the code will require adaptations. - // - /* Now allocate the token's dynamic information area and set the data */ - AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area. - AccessToken->DynamicPart = NULL; + AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, + DynamicPartSize, + TAG_TOKEN_DYNAMIC); + if (AccessToken->DynamicPart == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quit; + } + + /* Unused memory in the dynamic area */ + AccessToken->DynamicAvailable = 0; + + /* + * Assign the primary group to the token + * and put it in the dynamic part as well. + */ + EndMem = (PVOID)AccessToken->DynamicPart; + AccessToken->PrimaryGroup = EndMem; + RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid), + EndMem, + AccessToken->UserAndGroups[PrimaryGroupIndex].Sid); + AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex; + EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid)); + + /* + * The existing token has a default DACL only + * if it has an allocated dynamic part. + */ if (Token->DynamicPart && Token->DefaultDacl) { - AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, - Token->DefaultDacl->AclSize, - TAG_TOKEN_DYNAMIC); - if (AccessToken->DynamicPart == NULL) - { - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quit; - } - - EndMem = (PVOID)AccessToken->DynamicPart; AccessToken->DefaultDacl = EndMem; - RtlCopyMemory(AccessToken->DefaultDacl, + RtlCopyMemory(EndMem, Token->DefaultDacl, Token->DefaultDacl->AclSize); } @@ -804,6 +867,7 @@ SepPerformTokenFiltering( NTSTATUS Status; PTOKEN AccessToken; PVOID EndMem; + ULONG DynamicPartSize; ULONG RestrictedSidsLength; ULONG PrivilegesLength; ULONG PrimaryGroupIndex; @@ -863,6 +927,14 @@ SepPerformTokenFiltering( TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; } + /* + * Compute how much size we need to allocate + * the dynamic part of the newly duplicated + * token. + */ + DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0; + DynamicPartSize += RtlLengthSid(Token->PrimaryGroup); + /* Set up a filtered token object */ Status = ObCreateObject(PreviousMode, SeTokenObjectType, @@ -870,8 +942,8 @@ SepPerformTokenFiltering( PreviousMode, NULL, TotalSize, - 0, - 0, + Token->DynamicCharged, + TotalSize, (PVOID*)&AccessToken); if (!NT_SUCCESS(Status)) { @@ -907,6 +979,7 @@ SepPerformTokenFiltering( AccessToken->AuthenticationId = Token->AuthenticationId; AccessToken->ParentTokenId = Token->TokenId; AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession; + AccessToken->DynamicCharged = Token->DynamicCharged; AccessToken->ExpirationTime = Token->ExpirationTime; @@ -1092,28 +1165,40 @@ SepPerformTokenFiltering( goto Quit; } - /* Assign the primary group and default owner index now */ - AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; - AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex; - /* Now allocate the token's dynamic information area and set the data */ + AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, + DynamicPartSize, + TAG_TOKEN_DYNAMIC); + if (AccessToken->DynamicPart == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + goto Quit; + } + + /* Unused memory in the dynamic area */ AccessToken->DynamicAvailable = 0; - AccessToken->DynamicPart = NULL; + + /* + * Assign the primary group to the token + * and put it in the dynamic part as well. + */ + EndMem = (PVOID)AccessToken->DynamicPart; + AccessToken->PrimaryGroup = EndMem; + RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid), + EndMem, + AccessToken->UserAndGroups[PrimaryGroupIndex].Sid); + AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex; + EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid)); + + /* + * The existing token has a default DACL only + * if it has an allocated dynamic part. + */ if (Token->DynamicPart && Token->DefaultDacl) { - AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, - Token->DefaultDacl->AclSize, - TAG_TOKEN_DYNAMIC); - if (AccessToken->DynamicPart == NULL) - { - Status = STATUS_INSUFFICIENT_RESOURCES; - goto Quit; - } - - EndMem = (PVOID)AccessToken->DynamicPart; AccessToken->DefaultDacl = EndMem; - RtlCopyMemory(AccessToken->DefaultDacl, + RtlCopyMemory(EndMem, Token->DefaultDacl, Token->DefaultDacl->AclSize); }