https://git.reactos.org/?p=reactos.git;a=commitdiff;h=caa3571cd78f595add72fe...
commit caa3571cd78f595add72fecfebdb06ecedd44818 Author: George Bișoc george.bisoc@reactos.org AuthorDate: Sun Nov 6 17:40:48 2022 +0100 Commit: George Bișoc george.bisoc@reactos.org CommitDate: Tue Nov 8 18:24:37 2022 +0100
[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. --- ntoskrnl/include/internal/se.h | 17 +++ ntoskrnl/ntos.cmake | 4 + ntoskrnl/se/debug.c | 330 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 351 insertions(+)
diff --git a/ntoskrnl/include/internal/se.h b/ntoskrnl/include/internal/se.h index b81585c64eb..59cb4dbe631 100644 --- a/ntoskrnl/include/internal/se.h +++ b/ntoskrnl/include/internal/se.h @@ -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 // diff --git a/ntoskrnl/ntos.cmake b/ntoskrnl/ntos.cmake index 38af3b2b81b..67fe1186a14 100644 --- a/ntoskrnl/ntos.cmake +++ b/ntoskrnl/ntos.cmake @@ -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") diff --git a/ntoskrnl/se/debug.c b/ntoskrnl/se/debug.c new file mode 100644 index 00000000000..da5e35a160e --- /dev/null +++ b/ntoskrnl/se/debug.c @@ -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 */