From 9ba0d09d90b6c380a4b35f2931d7b9ea2b556874 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Mon, 6 Sep 2010 15:26:12 +0000 Subject: [PATCH] Improvements to NtAdjustPrivilegesToken part 2: - Check for invalid parameter combinations. - Count privileges that will be changed before changing them. - Return required buffer size. - Fail if the provided buffer is too small. See issue #5497 for more details. svn path=/trunk/; revision=48710 --- reactos/ntoskrnl/se/token.c | 140 +++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 56 deletions(-) diff --git a/reactos/ntoskrnl/se/token.c b/reactos/ntoskrnl/se/token.c index a7c6d5e4b95..c14c9a5d9cc 100644 --- a/reactos/ntoskrnl/se/token.c +++ b/reactos/ntoskrnl/se/token.c @@ -1958,23 +1958,22 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle, ULONG CapturedCount = 0; ULONG CapturedLength = 0; ULONG NewStateSize = 0; - ULONG PrivilegeCount; + ULONG ChangeCount; PTOKEN Token; ULONG i; ULONG j; ULONG k; ULONG Count; -#if 0 - ULONG a; - ULONG b; - ULONG c; -#endif NTSTATUS Status; PAGED_CODE(); DPRINT ("NtAdjustPrivilegesToken() called\n"); + /* Fail, if we do not disable all privileges but NewState is NULL */ + if (DisableAllPrivileges == FALSE && NewState == NULL) + return STATUS_INVALID_PARAMETER; + PreviousMode = KeGetPreviousMode (); if (PreviousMode != KernelMode) { @@ -2067,21 +2066,77 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle, return Status; } + /* Count the privileges that need to be changed */ + ChangeCount = 0; + for (i = 0; i < Token->PrivilegeCount; i++) + { + if (DisableAllPrivileges) + { + if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) + { + DPRINT("Attribute enabled\n"); -#if 0 - SepAdjustPrivileges(Token, - 0, - PreviousMode, - PrivilegeCount, - Privileges, - PreviousState, - &a, - &b, - &c); -#endif + ChangeCount++; + } + } + else + { + for (j = 0; j < CapturedCount; j++) + { + if (Token->Privileges[i].Luid.LowPart == CapturedPrivileges[j].Luid.LowPart && + Token->Privileges[i].Luid.HighPart == CapturedPrivileges[j].Luid.HighPart) + { + DPRINT("Found privilege\n"); + + if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) != + (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED)) + { + DPRINT("Attributes differ\n"); + DPRINT("Current attributes %lx New attributes %lx\n", + Token->Privileges[i].Attributes, + CapturedPrivileges[j].Attributes); + + ChangeCount++; + } + } + } + } + } + + /* + * Return the required buffer size and + * check if the available buffer is large enough + */ + if (PreviousState != NULL) + { + ULONG RequiredLength = (ULONG)sizeof(TOKEN_PRIVILEGES) + + ((ChangeCount - ANYSIZE_ARRAY) * (ULONG)sizeof(LUID_AND_ATTRIBUTES)); + + /* Try to return the required buffer length */ + _SEH2_TRY + { + *ReturnLength = RequiredLength; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Return the exception code */ + _SEH2_YIELD(return _SEH2_GetExceptionCode()); + } + _SEH2_END; + + /* Fail, if the buffer length is smaller than the required length */ + if (BufferLength < RequiredLength) + { + ObDereferenceObject(Token); + if (CapturedPrivileges != NULL) + SeReleaseLuidAndAttributesArray(CapturedPrivileges, + PreviousMode, + TRUE); + + return STATUS_BUFFER_TOO_SMALL; + } + } - PrivilegeCount = (BufferLength - FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges)) / - sizeof(LUID_AND_ATTRIBUTES); if (PreviousState != NULL) PreviousState->PrivilegeCount = 0; @@ -2091,27 +2146,16 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle, { for (i = 0; i < Token->PrivilegeCount; i++) { - if (Token->Privileges[i].Attributes != 0) + if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) { - DPRINT ("Attributes differ\n"); + DPRINT ("Attributes enabled\n"); /* Save current privilege */ if (PreviousState != NULL) { - if (k < PrivilegeCount) - { - PreviousState->PrivilegeCount++; - PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid; - PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes; - } - else - { - /* - * FIXME: Should revert all the changes, calculate how - * much space would be needed, set ResultLength - * accordingly and fail. - */ - } + PreviousState->PrivilegeCount++; + PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid; + PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes; k++; } @@ -2139,27 +2183,16 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle, (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED)) { DPRINT ("Attributes differ\n"); - DPRINT ("Current attributes %lx desired attributes %lx\n", + DPRINT ("Current attributes %lx New attributes %lx\n", Token->Privileges[i].Attributes, CapturedPrivileges[j].Attributes); /* Save current privilege */ if (PreviousState != NULL) { - if (k < PrivilegeCount) - { - PreviousState->PrivilegeCount++; - PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid; - PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes; - } - else - { - /* - * FIXME: Should revert all the changes, calculate how - * much space would be needed, set ResultLength - * accordingly and fail. - */ - } + PreviousState->PrivilegeCount++; + PreviousState->Privileges[k].Luid = Token->Privileges[i].Luid; + PreviousState->Privileges[k].Attributes = Token->Privileges[i].Attributes; k++; } @@ -2177,14 +2210,9 @@ NtAdjustPrivilegesToken(IN HANDLE TokenHandle, } } - Status = Count < CapturedCount ? STATUS_NOT_ALL_ASSIGNED : STATUS_SUCCESS; + Status = (Count < CapturedCount) ? STATUS_NOT_ALL_ASSIGNED : STATUS_SUCCESS; } - if (ReturnLength != NULL) - { - *ReturnLength = sizeof(TOKEN_PRIVILEGES) + - (sizeof(LUID_AND_ATTRIBUTES) * (k - 1)); - } /* Dereference the token */ ObDereferenceObject (Token); -- 2.17.1