reactos/ntoskrnl/se/access.c
Joachim Henze 3780e42ff9 [0.4.15][NTOS:SE][NDK][KMTESTS:SE] Fix 'kmtest_.exe SeQueryInfoToken' (#5308)
This backport fixes 'kmtest_.exe SeQueryInfoToken'
on all testers: VBox x86, KVM x86, WHS x86, Win2003_x64.
And according to Thomas description may also prevent a buffer overrun when executing that formerly broken test.
Afterwards all 76 tests of this suite do complete on all those builders.
Before the patch only 74 of those tests succeeded, 2 failed.

The fix is a squashed backport of the following 6 commits from Thomas Faber:
0.4.16-dev-11-g 44bdafa17e [KMTESTS:SE] Fix failing tests (#5308)
0.4.16-dev-10-g bf6af0f52e [NTOS:SE] Mark output parameters as such (#5308)
0.4.16-dev-9-g 156053cafd [NDK] Match AUX_ACCESS_DATA definition with publicly available version. - if you allocated only sizeof(AUX_ACCESS_DATA), the test would crash with a 4 byte buffer overflow. (#5308)
0.4.16-dev-8-g ff410211e9 [KMTESTS:SE] Don't modify internal data structure, this might cause buffer overrun (#5308)
0.4.16-dev-7-g 206df96bc4 [KMTESTS:SE] Correctly allocate PrivilegeSet buffers (#5308)
0.4.16-dev-6-g 64a6bd4c3e [KMTESTS:SE] Avoid use of uninitialized pool and hardcoded offsets (#5308)

WHS x86 before-and-after-state, the after-test had a few fixes from Timos unrelated PR7343 inside unfortunately:
https://reactos.org/testman/compare.php?ids=97640,97871
(This is added to prove the test being wrong)

I tested it also successfully on my local 2k3sp2 x86 with the releases/0.4.15 afterstate, built with RosBEWin2.2.2 GCC8.4.0dbg x86.

Win2003_x64 0.4.16-dev-11-g44bdafa at 2024-09-12 15:19 (after-state):
https://reactos.org/testman/compare.php?ids=97791

0.4.16-dev-5-g2913ef5 vs. 0.4.16-dev-11-g44bdafa vs. 0.4.16-dev-23-g53b304e:
VBox x86 https://reactos.org/testman/compare.php?ids=97795,97806,97877

0.4.16-dev-5-g2913ef5 vs. 0.4.16-dev-20-g144a8b5 vs. 0.4.16-dev-21-g2af6fd4:
KVM x86 https://reactos.org/testman/compare.php?ids=97793,97855,97856

Since we do touch the NTOS and NDK here the fix is not guaranteed to be side-effect-free,
but since we are so early in the RC-phase, I dared to pick it, especially since the alternative would have
been to disable the test altogether in the releases/0.4.15 which would have been a pity, if we can also have it all green everywhere.
2024-09-15 14:09:29 +02:00

203 lines
5.1 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Security access state functions support
* COPYRIGHT: Copyright Alex Ionescu <alex@relsoft.net>
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* PUBLIC FUNCTIONS ***********************************************************/
/**
* @brief
* An extended function that creates an access state.
*
* @param[in] Thread
* Valid thread object where subject context is to be captured.
*
* @param[in] Process
* Valid process object where subject context is to be captured.
*
* @param[out] AccessState
* An initialized returned parameter to an access state.
*
* @param[out] AuxData
* Auxiliary security data for access state.
*
* @param[in] Access
* Type of access mask to assign.
*
* @param[in] GenericMapping
* Generic mapping for the access state to assign.
*
* @return
* Returns STATUS_SUCCESS.
*/
NTSTATUS
NTAPI
SeCreateAccessStateEx(
_In_ PETHREAD Thread,
_In_ PEPROCESS Process,
_Out_ PACCESS_STATE AccessState,
_Out_ __drv_aliasesMem PAUX_ACCESS_DATA AuxData,
_In_ ACCESS_MASK Access,
_In_ PGENERIC_MAPPING GenericMapping)
{
ACCESS_MASK AccessMask = Access;
PTOKEN Token;
PAGED_CODE();
/* Map the Generic Acess to Specific Access if we have a Mapping */
if ((Access & GENERIC_ACCESS) && (GenericMapping))
{
RtlMapGenericMask(&AccessMask, GenericMapping);
}
/* Initialize the Access State */
RtlZeroMemory(AccessState, sizeof(ACCESS_STATE));
ASSERT(AccessState->SecurityDescriptor == NULL);
ASSERT(AccessState->PrivilegesAllocated == FALSE);
/* Initialize and save aux data */
RtlZeroMemory(AuxData, sizeof(AUX_ACCESS_DATA));
AccessState->AuxData = AuxData;
/* Capture the Subject Context */
SeCaptureSubjectContextEx(Thread,
Process,
&AccessState->SubjectSecurityContext);
/* Set Access State Data */
AccessState->RemainingDesiredAccess = AccessMask;
AccessState->OriginalDesiredAccess = AccessMask;
ExAllocateLocallyUniqueId(&AccessState->OperationID);
/* Get the Token to use */
Token = SeQuerySubjectContextToken(&AccessState->SubjectSecurityContext);
/* Check for Travers Privilege */
if (Token->TokenFlags & TOKEN_HAS_TRAVERSE_PRIVILEGE)
{
/* Preserve the Traverse Privilege */
AccessState->Flags = TOKEN_HAS_TRAVERSE_PRIVILEGE;
}
/* Set the Auxiliary Data */
AuxData->PrivilegesUsed = (PPRIVILEGE_SET)((ULONG_PTR)AccessState +
FIELD_OFFSET(ACCESS_STATE,
Privileges));
if (GenericMapping) AuxData->GenericMapping = *GenericMapping;
/* Return Sucess */
return STATUS_SUCCESS;
}
/**
* @brief
* Creates an access state.
*
* @param[out] AccessState
* An initialized returned parameter to an access state.
*
* @param[out] AuxData
* Auxiliary security data for access state.
*
* @param[in] Access
* Type of access mask to assign.
*
* @param[in] GenericMapping
* Generic mapping for the access state to assign.
*
* @return
* See SeCreateAccessStateEx.
*/
NTSTATUS
NTAPI
SeCreateAccessState(
_Out_ PACCESS_STATE AccessState,
_Out_ __drv_aliasesMem PAUX_ACCESS_DATA AuxData,
_In_ ACCESS_MASK Access,
_In_ PGENERIC_MAPPING GenericMapping)
{
PAGED_CODE();
/* Call the extended API */
return SeCreateAccessStateEx(PsGetCurrentThread(),
PsGetCurrentProcess(),
AccessState,
AuxData,
Access,
GenericMapping);
}
/**
* @brief
* Deletes an allocated access state from the memory.
*
* @param[in] AccessState
* A valid access state.
*
* @return
* Nothing.
*/
VOID
NTAPI
SeDeleteAccessState(
_In_ PACCESS_STATE AccessState)
{
PAUX_ACCESS_DATA AuxData;
PAGED_CODE();
/* Get the Auxiliary Data */
AuxData = AccessState->AuxData;
/* Deallocate Privileges */
if (AccessState->PrivilegesAllocated)
ExFreePoolWithTag(AuxData->PrivilegesUsed, TAG_PRIVILEGE_SET);
/* Deallocate Name and Type Name */
if (AccessState->ObjectName.Buffer)
{
ExFreePool(AccessState->ObjectName.Buffer);
}
if (AccessState->ObjectTypeName.Buffer)
{
ExFreePool(AccessState->ObjectTypeName.Buffer);
}
/* Release the Subject Context */
SeReleaseSubjectContext(&AccessState->SubjectSecurityContext);
}
/**
* @brief
* Sets a new generic mapping for an allocated access state.
*
* @param[in] AccessState
* A valid access state.
*
* @param[in] GenericMapping
* New generic mapping to assign.
*
* @return
* Nothing.
*/
VOID
NTAPI
SeSetAccessStateGenericMapping(
_In_ PACCESS_STATE AccessState,
_In_ PGENERIC_MAPPING GenericMapping)
{
PAGED_CODE();
/* Set the Generic Mapping */
((PAUX_ACCESS_DATA)AccessState->AuxData)->GenericMapping = *GenericMapping;
}
/* EOF */