[RTL][NTDLL_APITEST] Implement RtlRemovePrivileges (#4614)

Vista+ API, compile-time guarded.
Add tests for it.
This commit is contained in:
Ratin Gao 2022-10-05 20:31:39 +08:00 committed by GitHub
parent 967f5b9898
commit badd97043f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 231 additions and 1 deletions

View file

@ -1568,6 +1568,20 @@ RtlReleasePrivilege(
_In_ PVOID ReturnedState
);
#if (NTDDI_VERSION >= NTDDI_VISTA)
NTSYSAPI
NTSTATUS
NTAPI
RtlRemovePrivileges(
_In_ HANDLE TokenHandle,
_In_reads_opt_(PrivilegeCount) _When_(PrivilegeCount != 0, _Notnull_)
PULONG PrivilegesToKeep,
_In_ ULONG PrivilegeCount
);
#endif /* (NTDDI_VERSION >= NTDDI_VISTA) */
_IRQL_requires_max_(APC_LEVEL)
NTSYSAPI
NTSTATUS

View file

@ -486,3 +486,105 @@ RtlAdjustPrivilege(IN ULONG Privilege,
return STATUS_SUCCESS;
}
#if (NTDDI_VERSION >= NTDDI_VISTA)
/**
* @brief
* Removes all privileges in the specified access token.
*
* @param[in] TokenHandle
* A handle to the access token that contains the privileges to be removed.
*
* @param[in] PrivilegesToKeep
* A pointer to an array of privilege values (defined as SE_XXX_PRIVILEGE) that specify
* the privileges to keep in the token.
*
* @param[in] PrivilegeCount
* Specifies the number of entries in the PrivilegesToKeep array.
*
* @return
* Returns STATUS_SUCCESS if privileges removed successfully.
* STATUS_INVALID_PARAMETER is returned if input privilege value greater than
* SE_MAX_WELL_KNOWN_PRIVILEGE. STATUS_NOT_ALL_ASSIGNED is returned if The token does
* not have one or more of the privileges specified in the PrivilegesToKeep parameter,
* and no privileges were removed. A failure NTSTATUS code is returned otherwise.
*/
NTSTATUS
NTAPI
RtlRemovePrivileges(
_In_ HANDLE TokenHandle,
_In_reads_opt_(PrivilegeCount) _When_(PrivilegeCount != 0, _Notnull_)
PULONG PrivilegesToKeep,
_In_ ULONG PrivilegeCount)
{
NTSTATUS Status;
UINT64 PrivilegesToKeepBitmap;
ULONG i, ReturnLength;
UCHAR Buffer[sizeof(TOKEN_PRIVILEGES) +
sizeof(LUID_AND_ATTRIBUTES) * (SE_MAX_WELL_KNOWN_PRIVILEGE - SE_MIN_WELL_KNOWN_PRIVILEGE)];
PTOKEN_PRIVILEGES Privileges;
C_ASSERT(SE_MAX_WELL_KNOWN_PRIVILEGE < 64);
DPRINT("RtlRemovePrivileges(%p, %p, %u)\n", TokenHandle, PrivilegesToKeep, PrivilegeCount);
/* Save privileges that should be keep */
PrivilegesToKeepBitmap = 0;
if (PrivilegeCount)
{
for (i = 0; i < PrivilegeCount; i++)
{
if (PrivilegesToKeep[i] > SE_MAX_WELL_KNOWN_PRIVILEGE)
{
return STATUS_INVALID_PARAMETER;
}
PrivilegesToKeepBitmap |= (1ULL << PrivilegesToKeep[i]);
}
}
/* Get token privileges information */
Status = ZwQueryInformationToken(TokenHandle,
TokenPrivileges,
Buffer,
sizeof(Buffer),
&ReturnLength);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Remove all privileges that we don't need to keep */
Privileges = (PTOKEN_PRIVILEGES)Buffer;
for (i = 0; i < Privileges->PrivilegeCount; i++)
{
LARGE_INTEGER Privilege = *(LARGE_INTEGER*)&Privileges->Privileges[i].Luid;
ASSERT(Privilege.QuadPart <= SE_MAX_WELL_KNOWN_PRIVILEGE);
if (PrivilegesToKeepBitmap & (1ULL << Privilege.QuadPart))
{
PrivilegesToKeepBitmap &= ~(1ULL << Privilege.QuadPart);
}
else
{
Privileges->Privileges[i].Attributes = SE_PRIVILEGE_REMOVED;
}
}
if (PrivilegesToKeepBitmap)
{
Status = STATUS_NOT_ALL_ASSIGNED;
}
else
{
Status = ZwAdjustPrivilegesToken(TokenHandle,
FALSE,
(PTOKEN_PRIVILEGES)Buffer,
sizeof(Buffer),
NULL,
NULL);
}
return Status;
}
#endif /* (NTDDI_VERSION >= NTDDI_VISTA) */