[NTOS:SE] Implement security debug facility routines

debug.c will serve as a centralized facility for security debugging routines and everything related to that. This file will be expanded with further debug functions for the Security subsystem if needed.
This commit is contained in:
George Bișoc 2022-11-06 17:40:48 +01:00
parent 9f48c69231
commit caa3571cd7
No known key found for this signature in database
GPG key ID: 688C4FBE25D7DEF6
3 changed files with 351 additions and 0 deletions

View file

@ -289,6 +289,23 @@ extern PTOKEN SeAnonymousLogonTokenNoEveryone;
KeLeaveCriticalRegion(); \
}
#if DBG
//
// Security Debug Utility Functions
//
VOID
SepDumpSdDebugInfo(
_In_opt_ PISECURITY_DESCRIPTOR SecurityDescriptor);
VOID
SepDumpTokenDebugInfo(
_In_opt_ PTOKEN Token);
VOID
SepDumpAccessRightsStats(
_In_opt_ PACCESS_CHECK_RIGHTS AccessRights);
#endif // DBG
//
// Token Functions
//

View file

@ -294,6 +294,10 @@ list(APPEND SOURCE
${REACTOS_SOURCE_DIR}/ntoskrnl/wmi/wmi.c
${REACTOS_SOURCE_DIR}/ntoskrnl/wmi/wmidrv.c)
if(DBG)
list(APPEND SOURCE ${REACTOS_SOURCE_DIR}/ntoskrnl/se/debug.c)
endif()
list(APPEND ASM_SOURCE ${REACTOS_SOURCE_DIR}/ntoskrnl/ex/zw.S)
if(ARCH STREQUAL "i386")

330
ntoskrnl/se/debug.c Normal file
View file

@ -0,0 +1,330 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Security subsystem debug routines support
* COPYRIGHT: Copyright 2022 George Bișoc <george.bisoc@reactos.org>
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
/**
* @brief
* Converts an Access Control Entry (ACE) type to a string.
*
* @return
* Returns a converted ACE type strings. If no
* known ACE type is found, it will return
* UNKNOWN TYPE.
*/
static
PCSTR
SepGetAceTypeString(
_In_ UCHAR AceType)
{
#define TOSTR(x) #x
static const PCSTR AceTypes[] =
{
TOSTR(ACCESS_ALLOWED_ACE_TYPE),
TOSTR(ACCESS_DENIED_ACE_TYPE),
TOSTR(SYSTEM_AUDIT_ACE_TYPE),
TOSTR(SYSTEM_ALARM_ACE_TYPE),
TOSTR(ACCESS_ALLOWED_COMPOUND_ACE_TYPE),
TOSTR(ACCESS_ALLOWED_OBJECT_ACE_TYPE),
TOSTR(ACCESS_DENIED_OBJECT_ACE_TYPE),
TOSTR(SYSTEM_AUDIT_OBJECT_ACE_TYPE),
TOSTR(SYSTEM_ALARM_OBJECT_ACE_TYPE),
TOSTR(ACCESS_ALLOWED_CALLBACK_ACE_TYPE),
TOSTR(ACCESS_DENIED_CALLBACK_ACE_TYPE),
TOSTR(ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE),
TOSTR(ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE),
TOSTR(SYSTEM_AUDIT_CALLBACK_ACE_TYPE),
TOSTR(SYSTEM_ALARM_CALLBACK_ACE_TYPE),
TOSTR(SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE),
TOSTR(SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE),
TOSTR(SYSTEM_MANDATORY_LABEL_ACE_TYPE),
};
#undef TOSTR
if (AceType < RTL_NUMBER_OF(AceTypes))
return AceTypes[AceType];
else
return "UNKNOWN TYPE";
}
/**
* @brief
* Dumps the ACE flags to the debugger output.
*/
static
VOID
SepDumpAceFlags(
_In_ UCHAR AceFlags)
{
#define ACE_FLAG_PRINT(x) \
if (AceFlags & x) \
{ \
DbgPrint(#x "\n"); \
}
ACE_FLAG_PRINT(OBJECT_INHERIT_ACE);
ACE_FLAG_PRINT(CONTAINER_INHERIT_ACE);
ACE_FLAG_PRINT(NO_PROPAGATE_INHERIT_ACE);
ACE_FLAG_PRINT(INHERIT_ONLY_ACE);
ACE_FLAG_PRINT(INHERITED_ACE);
#undef ACE_FLAG_PRINT
}
/**
* @brief
* Iterates and dumps each ACE debug info in an ACL.
*/
static
VOID
SepDumpAces(
_In_ PACL Acl)
{
NTSTATUS Status;
PACE Ace;
ULONG AceIndex;
PSID Sid;
UNICODE_STRING SidString;
/* Loop all ACEs and dump their info */
for (AceIndex = 0; AceIndex < Acl->AceCount; AceIndex++)
{
/* Get the ACE at this index */
Status = RtlGetAce(Acl, AceIndex, (PVOID*)&Ace);
if (!NT_SUCCESS(Status))
{
/*
* Normally this should never happen.
* Just fail gracefully and stop further
* debugging of ACEs.
*/
DbgPrint("SepDumpAces(): Failed to find the next ACE, stop dumping info...\n");
return;
}
DbgPrint("================== %lu# ACE DUMP INFO ==================\n", AceIndex);
DbgPrint("Ace -> 0x%p\n", Ace);
DbgPrint("Ace->Header -> 0x%p\n", Ace->Header);
DbgPrint("Ace->Header.AceType -> %s\n", SepGetAceTypeString(Ace->Header.AceType));
DbgPrint("Ace->AccessMask -> 0x%08lx\n", Ace->AccessMask);
Sid = SepGetSidFromAce(Ace->Header.AceType, Ace);
ASSERT(Sid);
RtlConvertSidToUnicodeString(&SidString, Sid, TRUE);
DbgPrint("Ace SID -> %wZ\n", &SidString);
RtlFreeUnicodeString(&SidString);
DbgPrint("Ace->Header.AceSize -> %u\n", Ace->Header.AceSize);
DbgPrint("Ace->Header.AceFlags:\n");
SepDumpAceFlags(Ace->Header.AceFlags);
}
}
/**
* @brief
* Dumps debug info of an Access Control List (ACL).
*/
static
VOID
SepDumpAclInfo(
_In_ PACL Acl,
_In_ BOOLEAN IsSacl)
{
/* Dump relevant info */
DbgPrint("================== %s DUMP INFO ==================\n", IsSacl ? "SACL" : "DACL");
DbgPrint("Acl->AclRevision -> %u\n", Acl->AclRevision);
DbgPrint("Acl->AclSize -> %u\n", Acl->AclSize);
DbgPrint("Acl->AceCount -> %u\n", Acl->AceCount);
/* Dump all the ACEs present on this ACL */
SepDumpAces(Acl);
}
/**
* @brief
* Dumps control flags of a security descriptor to the debugger.
*/
static
VOID
SepDumpSdControlInfo(
_In_ SECURITY_DESCRIPTOR_CONTROL SdControl)
{
#define SD_CONTROL_PRINT(x) \
if (SdControl & x) \
{ \
DbgPrint(#x "\n"); \
}
SD_CONTROL_PRINT(SE_OWNER_DEFAULTED);
SD_CONTROL_PRINT(SE_GROUP_DEFAULTED);
SD_CONTROL_PRINT(SE_DACL_PRESENT);
SD_CONTROL_PRINT(SE_DACL_DEFAULTED);
SD_CONTROL_PRINT(SE_SACL_PRESENT);
SD_CONTROL_PRINT(SE_SACL_DEFAULTED);
SD_CONTROL_PRINT(SE_DACL_UNTRUSTED);
SD_CONTROL_PRINT(SE_SERVER_SECURITY);
SD_CONTROL_PRINT(SE_DACL_AUTO_INHERIT_REQ);
SD_CONTROL_PRINT(SE_SACL_AUTO_INHERIT_REQ);
SD_CONTROL_PRINT(SE_DACL_AUTO_INHERITED);
SD_CONTROL_PRINT(SE_SACL_AUTO_INHERITED);
SD_CONTROL_PRINT(SE_DACL_PROTECTED);
SD_CONTROL_PRINT(SE_SACL_PROTECTED);
SD_CONTROL_PRINT(SE_RM_CONTROL_VALID);
SD_CONTROL_PRINT(SE_SELF_RELATIVE);
#undef SD_CONTROL_PRINT
}
/**
* @brief
* Dumps each security identifier (SID) of an access token to debugger.
*/
static
VOID
SepDumpSidsOfToken(
_In_ PSID_AND_ATTRIBUTES Sids,
_In_ ULONG SidCount)
{
ULONG SidIndex;
UNICODE_STRING SidString;
/* Loop all SIDs and dump them */
for (SidIndex = 0; SidIndex < SidCount; SidIndex++)
{
RtlConvertSidToUnicodeString(&SidString, Sids[SidIndex].Sid, TRUE);
DbgPrint("%lu# %wZ\n", SidIndex, &SidString);
RtlFreeUnicodeString(&SidString);
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
/**
* @brief
* Dumps debug information of a security descriptor to the debugger.
*/
VOID
SepDumpSdDebugInfo(
_In_opt_ PISECURITY_DESCRIPTOR SecurityDescriptor)
{
UNICODE_STRING SidString;
PSID OwnerSid, GroupSid;
PACL Dacl, Sacl;
/* Don't dump anything if no SD was provided */
if (!SecurityDescriptor)
{
return;
}
/* Cache the necessary security buffers to dump info from */
OwnerSid = SepGetOwnerFromDescriptor(SecurityDescriptor);
GroupSid = SepGetGroupFromDescriptor(SecurityDescriptor);
Sacl = SepGetSaclFromDescriptor(SecurityDescriptor);
Dacl = SepGetDaclFromDescriptor(SecurityDescriptor);
DbgPrint("================== SECURITY DESCRIPTOR DUMP INFO ==================\n");
DbgPrint("SecurityDescriptor -> 0x%p\n", SecurityDescriptor);
DbgPrint("SecurityDescriptor->Revision -> %u\n", SecurityDescriptor->Revision);
DbgPrint("SecurityDescriptor->Control:\n");
SepDumpSdControlInfo(SecurityDescriptor->Control);
/* Dump the Owner SID if the SD belongs to an owner */
if (OwnerSid)
{
RtlConvertSidToUnicodeString(&SidString, OwnerSid, TRUE);
DbgPrint("SD Owner SID -> %wZ\n", &SidString);
RtlFreeUnicodeString(&SidString);
}
/* Dump the Group SID if the SD belongs to a group */
if (GroupSid)
{
RtlConvertSidToUnicodeString(&SidString, GroupSid, TRUE);
DbgPrint("SD Group SID -> %wZ\n", &SidString);
RtlFreeUnicodeString(&SidString);
}
/* Dump the ACL contents of SACL if this SD has one */
if (Sacl)
{
SepDumpAclInfo(Sacl, TRUE);
}
/* Dump the ACL contents of DACL if this SD has one */
if (Dacl)
{
SepDumpAclInfo(Dacl, FALSE);
}
}
/**
* @brief
* Dumps debug information of an access token to the debugger.
*/
VOID
SepDumpTokenDebugInfo(
_In_opt_ PTOKEN Token)
{
UNICODE_STRING SidString;
/* Don't dump anything if no token was provided */
if (!Token)
{
return;
}
/* Dump relevant token info */
DbgPrint("================== ACCESS TOKEN DUMP INFO ==================\n");
DbgPrint("Token -> 0x%p\n", Token);
DbgPrint("Token->ImageFileName -> %s\n", Token->ImageFileName);
DbgPrint("Token->TokenSource.SourceName -> \"%-.*s\"\n",
RTL_NUMBER_OF(Token->TokenSource.SourceName),
Token->TokenSource.SourceName);
DbgPrint("Token->TokenSource.SourceIdentifier -> %lu.%lu\n",
Token->TokenSource.SourceIdentifier.HighPart,
Token->TokenSource.SourceIdentifier.LowPart);
RtlConvertSidToUnicodeString(&SidString, Token->PrimaryGroup, TRUE);
DbgPrint("Token primary group SID -> %wZ\n", &SidString);
RtlFreeUnicodeString(&SidString);
DbgPrint("Token user and groups SIDs:\n");
SepDumpSidsOfToken(Token->UserAndGroups, Token->UserAndGroupCount);
if (SeTokenIsRestricted(Token))
{
DbgPrint("Token restricted SIDs:\n");
SepDumpSidsOfToken(Token->RestrictedSids, Token->RestrictedSidCount);
}
}
/**
* @brief
* Dumps security access rights to the debugger.
*/
VOID
SepDumpAccessRightsStats(
_In_opt_ PACCESS_CHECK_RIGHTS AccessRights)
{
/* Don't dump anything if no access check rights list was provided */
if (!AccessRights)
{
return;
}
DbgPrint("================== ACCESS CHECK RIGHTS STATISTICS ==================\n");
DbgPrint("Remaining access rights -> 0x%08lx\n", AccessRights->RemainingAccessRights);
DbgPrint("Granted access rights -> 0x%08lx\n", AccessRights->GrantedAccessRights);
DbgPrint("Denied access rights -> 0x%08lx\n", AccessRights->DeniedAccessRights);
}
/* EOF */