Reactos
at master 383 lines 11 kB view raw
1/* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Security subsystem debug routines support 5 * COPYRIGHT: Copyright 2022-2023 George Bișoc <george.bisoc@reactos.org> 6 */ 7 8/* INCLUDES *******************************************************************/ 9 10#include <ntoskrnl.h> 11#define NDEBUG 12#include <debug.h> 13 14/* PRIVATE FUNCTIONS **********************************************************/ 15 16#ifndef NDEBUG 17/** 18 * @brief 19 * Converts an Access Control Entry (ACE) type to a string. 20 * 21 * @return 22 * Returns a converted ACE type strings. If no 23 * known ACE type is found, it will return 24 * UNKNOWN TYPE. 25 */ 26static 27PCSTR 28SepGetAceTypeString( 29 _In_ UCHAR AceType) 30{ 31#define TOSTR(x) #x 32 static const PCSTR AceTypes[] = 33 { 34 TOSTR(ACCESS_ALLOWED_ACE_TYPE), 35 TOSTR(ACCESS_DENIED_ACE_TYPE), 36 TOSTR(SYSTEM_AUDIT_ACE_TYPE), 37 TOSTR(SYSTEM_ALARM_ACE_TYPE), 38 TOSTR(ACCESS_ALLOWED_COMPOUND_ACE_TYPE), 39 TOSTR(ACCESS_ALLOWED_OBJECT_ACE_TYPE), 40 TOSTR(ACCESS_DENIED_OBJECT_ACE_TYPE), 41 TOSTR(SYSTEM_AUDIT_OBJECT_ACE_TYPE), 42 TOSTR(SYSTEM_ALARM_OBJECT_ACE_TYPE), 43 TOSTR(ACCESS_ALLOWED_CALLBACK_ACE_TYPE), 44 TOSTR(ACCESS_DENIED_CALLBACK_ACE_TYPE), 45 TOSTR(ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE), 46 TOSTR(ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE), 47 TOSTR(SYSTEM_AUDIT_CALLBACK_ACE_TYPE), 48 TOSTR(SYSTEM_ALARM_CALLBACK_ACE_TYPE), 49 TOSTR(SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE), 50 TOSTR(SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE), 51 TOSTR(SYSTEM_MANDATORY_LABEL_ACE_TYPE), 52 }; 53#undef TOSTR 54 55 if (AceType < RTL_NUMBER_OF(AceTypes)) 56 return AceTypes[AceType]; 57 else 58 return "UNKNOWN TYPE"; 59} 60 61/** 62 * @brief 63 * Dumps the ACE flags to the debugger output. 64 */ 65static 66VOID 67SepDumpAceFlags( 68 _In_ UCHAR AceFlags) 69{ 70#define ACE_FLAG_PRINT(x) \ 71 if (AceFlags & x) \ 72 { \ 73 DbgPrint(#x "\n"); \ 74 } 75 76 ACE_FLAG_PRINT(OBJECT_INHERIT_ACE); 77 ACE_FLAG_PRINT(CONTAINER_INHERIT_ACE); 78 ACE_FLAG_PRINT(NO_PROPAGATE_INHERIT_ACE); 79 ACE_FLAG_PRINT(INHERIT_ONLY_ACE); 80 ACE_FLAG_PRINT(INHERITED_ACE); 81#undef ACE_FLAG_PRINT 82} 83 84/** 85 * @brief 86 * Iterates and dumps each ACE debug info in an ACL. 87 */ 88static 89VOID 90SepDumpAces( 91 _In_ PACL Acl) 92{ 93 NTSTATUS Status; 94 PACE Ace; 95 ULONG AceIndex; 96 PSID Sid; 97 UNICODE_STRING SidString; 98 99 /* Loop all ACEs and dump their info */ 100 for (AceIndex = 0; AceIndex < Acl->AceCount; AceIndex++) 101 { 102 /* Get the ACE at this index */ 103 Status = RtlGetAce(Acl, AceIndex, (PVOID*)&Ace); 104 if (!NT_SUCCESS(Status)) 105 { 106 /* 107 * Normally this should never happen. 108 * Just fail gracefully and stop further 109 * debugging of ACEs. 110 */ 111 DbgPrint("SepDumpAces(): Failed to find the next ACE, stop dumping info...\n"); 112 return; 113 } 114 115 DbgPrint("================== %lu# ACE DUMP INFO ==================\n", AceIndex); 116 DbgPrint("Ace -> 0x%p\n", Ace); 117 DbgPrint("Ace->Header -> 0x%p\n", Ace->Header); 118 DbgPrint("Ace->Header.AceType -> %s\n", SepGetAceTypeString(Ace->Header.AceType)); 119 DbgPrint("Ace->AccessMask -> 0x%08lx\n", Ace->AccessMask); 120 121 Sid = SepGetSidFromAce(Ace); 122 ASSERT(Sid); 123 RtlConvertSidToUnicodeString(&SidString, Sid, TRUE); 124 DbgPrint("Ace SID -> %wZ\n", &SidString); 125 RtlFreeUnicodeString(&SidString); 126 127 DbgPrint("Ace->Header.AceSize -> %u\n", Ace->Header.AceSize); 128 DbgPrint("Ace->Header.AceFlags:\n"); 129 SepDumpAceFlags(Ace->Header.AceFlags); 130 } 131} 132 133/** 134 * @brief 135 * Dumps debug info of an Access Control List (ACL). 136 */ 137static 138VOID 139SepDumpAclInfo( 140 _In_ PACL Acl, 141 _In_ BOOLEAN IsSacl) 142{ 143 /* Dump relevant info */ 144 DbgPrint("================== %s DUMP INFO ==================\n", IsSacl ? "SACL" : "DACL"); 145 DbgPrint("Acl->AclRevision -> %u\n", Acl->AclRevision); 146 DbgPrint("Acl->AclSize -> %u\n", Acl->AclSize); 147 DbgPrint("Acl->AceCount -> %u\n", Acl->AceCount); 148 149 /* Dump all the ACEs present on this ACL */ 150 SepDumpAces(Acl); 151} 152 153/** 154 * @brief 155 * Dumps control flags of a security descriptor to the debugger. 156 */ 157static 158VOID 159SepDumpSdControlInfo( 160 _In_ SECURITY_DESCRIPTOR_CONTROL SdControl) 161{ 162#define SD_CONTROL_PRINT(x) \ 163 if (SdControl & x) \ 164 { \ 165 DbgPrint(#x "\n"); \ 166 } 167 168 SD_CONTROL_PRINT(SE_OWNER_DEFAULTED); 169 SD_CONTROL_PRINT(SE_GROUP_DEFAULTED); 170 SD_CONTROL_PRINT(SE_DACL_PRESENT); 171 SD_CONTROL_PRINT(SE_DACL_DEFAULTED); 172 SD_CONTROL_PRINT(SE_SACL_PRESENT); 173 SD_CONTROL_PRINT(SE_SACL_DEFAULTED); 174 SD_CONTROL_PRINT(SE_DACL_UNTRUSTED); 175 SD_CONTROL_PRINT(SE_SERVER_SECURITY); 176 SD_CONTROL_PRINT(SE_DACL_AUTO_INHERIT_REQ); 177 SD_CONTROL_PRINT(SE_SACL_AUTO_INHERIT_REQ); 178 SD_CONTROL_PRINT(SE_DACL_AUTO_INHERITED); 179 SD_CONTROL_PRINT(SE_SACL_AUTO_INHERITED); 180 SD_CONTROL_PRINT(SE_DACL_PROTECTED); 181 SD_CONTROL_PRINT(SE_SACL_PROTECTED); 182 SD_CONTROL_PRINT(SE_RM_CONTROL_VALID); 183 SD_CONTROL_PRINT(SE_SELF_RELATIVE); 184#undef SD_CONTROL_PRINT 185} 186 187/** 188 * @brief 189 * Dumps each security identifier (SID) of an access token to debugger. 190 */ 191static 192VOID 193SepDumpSidsOfToken( 194 _In_ PSID_AND_ATTRIBUTES Sids, 195 _In_ ULONG SidCount) 196{ 197 ULONG SidIndex; 198 UNICODE_STRING SidString; 199 200 /* Loop all SIDs and dump them */ 201 for (SidIndex = 0; SidIndex < SidCount; SidIndex++) 202 { 203 RtlConvertSidToUnicodeString(&SidString, Sids[SidIndex].Sid, TRUE); 204 DbgPrint("%lu# %wZ\n", SidIndex, &SidString); 205 RtlFreeUnicodeString(&SidString); 206 } 207} 208#endif 209 210/* PUBLIC FUNCTIONS ***********************************************************/ 211 212/** 213 * @brief 214 * Dumps debug information of a security descriptor to the debugger. 215 */ 216VOID 217SepDumpSdDebugInfo( 218 _In_opt_ PISECURITY_DESCRIPTOR SecurityDescriptor) 219{ 220#ifndef NDEBUG 221 UNICODE_STRING SidString; 222 PSID OwnerSid, GroupSid; 223 PACL Dacl, Sacl; 224#endif 225 226 /* Don't dump anything if no SD was provided */ 227 if (!SecurityDescriptor) 228 { 229 return; 230 } 231 232#ifndef NDEBUG 233 /* Cache the necessary security buffers to dump info from */ 234 OwnerSid = SepGetOwnerFromDescriptor(SecurityDescriptor); 235 GroupSid = SepGetGroupFromDescriptor(SecurityDescriptor); 236 Sacl = SepGetSaclFromDescriptor(SecurityDescriptor); 237 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor); 238 239 DbgPrint("================== SECURITY DESCRIPTOR DUMP INFO ==================\n"); 240 DbgPrint("SecurityDescriptor -> 0x%p\n", SecurityDescriptor); 241 DbgPrint("SecurityDescriptor->Revision -> %u\n", SecurityDescriptor->Revision); 242 DbgPrint("SecurityDescriptor->Control:\n"); 243 SepDumpSdControlInfo(SecurityDescriptor->Control); 244 245 /* Dump the Owner SID if the SD belongs to an owner */ 246 if (OwnerSid) 247 { 248 RtlConvertSidToUnicodeString(&SidString, OwnerSid, TRUE); 249 DbgPrint("SD Owner SID -> %wZ\n", &SidString); 250 RtlFreeUnicodeString(&SidString); 251 } 252 253 /* Dump the Group SID if the SD belongs to a group */ 254 if (GroupSid) 255 { 256 RtlConvertSidToUnicodeString(&SidString, GroupSid, TRUE); 257 DbgPrint("SD Group SID -> %wZ\n", &SidString); 258 RtlFreeUnicodeString(&SidString); 259 } 260 261 /* Dump the ACL contents of SACL if this SD has one */ 262 if (Sacl) 263 { 264 SepDumpAclInfo(Sacl, TRUE); 265 } 266 267 /* Dump the ACL contents of DACL if this SD has one */ 268 if (Dacl) 269 { 270 SepDumpAclInfo(Dacl, FALSE); 271 } 272#endif 273} 274 275/** 276 * @brief 277 * Dumps debug information of an access token to the debugger. 278 */ 279VOID 280SepDumpTokenDebugInfo( 281 _In_opt_ PTOKEN Token) 282{ 283#ifndef NDEBUG 284 UNICODE_STRING SidString; 285#endif 286 287 /* Don't dump anything if no token was provided */ 288 if (!Token) 289 { 290 return; 291 } 292 293#ifndef NDEBUG 294 /* Dump relevant token info */ 295 DbgPrint("================== ACCESS TOKEN DUMP INFO ==================\n"); 296 DbgPrint("Token -> 0x%p\n", Token); 297 DbgPrint("Token->ImageFileName -> %s\n", Token->ImageFileName); 298 DbgPrint("Token->TokenSource.SourceName -> \"%-.*s\"\n", 299 RTL_NUMBER_OF(Token->TokenSource.SourceName), 300 Token->TokenSource.SourceName); 301 DbgPrint("Token->TokenSource.SourceIdentifier -> %lu.%lu\n", 302 Token->TokenSource.SourceIdentifier.HighPart, 303 Token->TokenSource.SourceIdentifier.LowPart); 304 305 RtlConvertSidToUnicodeString(&SidString, Token->PrimaryGroup, TRUE); 306 DbgPrint("Token primary group SID -> %wZ\n", &SidString); 307 RtlFreeUnicodeString(&SidString); 308 309 DbgPrint("Token user and groups SIDs:\n"); 310 SepDumpSidsOfToken(Token->UserAndGroups, Token->UserAndGroupCount); 311 312 if (SeTokenIsRestricted(Token)) 313 { 314 DbgPrint("Token restricted SIDs:\n"); 315 SepDumpSidsOfToken(Token->RestrictedSids, Token->RestrictedSidCount); 316 } 317#endif 318} 319 320/** 321 * @brief 322 * Dumps security access rights to the debugger. 323 */ 324VOID 325SepDumpAccessRightsStats( 326 _In_ PACCESS_CHECK_RIGHTS AccessRights) 327{ 328 /* 329 * Dump the access rights only if we have remaining rights 330 * to dump in the first place. RemainingAccessRights can be 0 331 * if access check procedure has failed prematurely and this 332 * member hasn't been filled yet. 333 */ 334 if (!AccessRights->RemainingAccessRights) 335 { 336 return; 337 } 338 339#ifndef NDEBUG 340 DbgPrint("================== ACCESS CHECK RIGHTS STATISTICS ==================\n"); 341 DbgPrint("Remaining access rights -> 0x%08lx\n", AccessRights->RemainingAccessRights); 342 DbgPrint("Granted access rights -> 0x%08lx\n", AccessRights->GrantedAccessRights); 343 DbgPrint("Denied access rights -> 0x%08lx\n", AccessRights->DeniedAccessRights); 344#endif 345} 346 347/** 348 * @brief 349 * Dumps access and status values of each object type 350 * in the result list. 351 */ 352VOID 353SepDumpAccessAndStatusList( 354 _In_ PACCESS_MASK GrantedAccessList, 355 _In_ PNTSTATUS AccessStatusList, 356 _In_ BOOLEAN IsResultList, 357 _In_ POBJECT_TYPE_LIST_INTERNAL ObjectTypeList, 358 _In_ ULONG ObjectTypeListLength) 359{ 360#ifndef NDEBUG 361 ULONG ResultListIndex; 362 ULONG ObjectTypeIndex; 363 ULONG ResultListLength; 364 365 DbgPrint("================== ACCESS & STATUS OBJECT TYPE LIST STATISTICS ==================\n"); 366 ResultListLength = IsResultList ? ObjectTypeListLength : 1; 367 for (ResultListIndex = 0; ResultListIndex < ResultListLength; ResultListIndex++) 368 { 369 DbgPrint("Result Index #%lu, Granted access rights -> 0x%08lx, Access status -> 0x%08lx\n", 370 ResultListIndex, GrantedAccessList[ResultListIndex], AccessStatusList[ResultListIndex]); 371 } 372 373 for (ObjectTypeIndex = 0; ObjectTypeIndex < ObjectTypeListLength; ObjectTypeIndex++) 374 { 375 DbgPrint("================== #%lu OBJECT ACCESS RIGHTS ==================\n", ObjectTypeIndex); 376 DbgPrint("Remaining access rights -> 0x%08lx\n", ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.RemainingAccessRights); 377 DbgPrint("Granted access rights -> 0x%08lx\n", ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.GrantedAccessRights); 378 DbgPrint("Denied access rights -> 0x%08lx\n", ObjectTypeList[ObjectTypeIndex].ObjectAccessRights.DeniedAccessRights); 379 } 380#endif 381} 382 383/* EOF */