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 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 /** 17 * @brief 18 * Converts an Access Control Entry (ACE) type to a string. 19 * 20 * @return 21 * Returns a converted ACE type strings. If no 22 * known ACE type is found, it will return 23 * UNKNOWN TYPE. 24 */ 25 static 26 PCSTR 27 SepGetAceTypeString( 28 _In_ UCHAR AceType) 29 { 30 #define TOSTR(x) #x 31 static const PCSTR AceTypes[] = 32 { 33 TOSTR(ACCESS_ALLOWED_ACE_TYPE), 34 TOSTR(ACCESS_DENIED_ACE_TYPE), 35 TOSTR(SYSTEM_AUDIT_ACE_TYPE), 36 TOSTR(SYSTEM_ALARM_ACE_TYPE), 37 TOSTR(ACCESS_ALLOWED_COMPOUND_ACE_TYPE), 38 TOSTR(ACCESS_ALLOWED_OBJECT_ACE_TYPE), 39 TOSTR(ACCESS_DENIED_OBJECT_ACE_TYPE), 40 TOSTR(SYSTEM_AUDIT_OBJECT_ACE_TYPE), 41 TOSTR(SYSTEM_ALARM_OBJECT_ACE_TYPE), 42 TOSTR(ACCESS_ALLOWED_CALLBACK_ACE_TYPE), 43 TOSTR(ACCESS_DENIED_CALLBACK_ACE_TYPE), 44 TOSTR(ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE), 45 TOSTR(ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE), 46 TOSTR(SYSTEM_AUDIT_CALLBACK_ACE_TYPE), 47 TOSTR(SYSTEM_ALARM_CALLBACK_ACE_TYPE), 48 TOSTR(SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE), 49 TOSTR(SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE), 50 TOSTR(SYSTEM_MANDATORY_LABEL_ACE_TYPE), 51 }; 52 #undef TOSTR 53 54 if (AceType < RTL_NUMBER_OF(AceTypes)) 55 return AceTypes[AceType]; 56 else 57 return "UNKNOWN TYPE"; 58 } 59 60 /** 61 * @brief 62 * Dumps the ACE flags to the debugger output. 63 */ 64 static 65 VOID 66 SepDumpAceFlags( 67 _In_ UCHAR AceFlags) 68 { 69 #define ACE_FLAG_PRINT(x) \ 70 if (AceFlags & x) \ 71 { \ 72 DbgPrint(#x "\n"); \ 73 } 74 75 ACE_FLAG_PRINT(OBJECT_INHERIT_ACE); 76 ACE_FLAG_PRINT(CONTAINER_INHERIT_ACE); 77 ACE_FLAG_PRINT(NO_PROPAGATE_INHERIT_ACE); 78 ACE_FLAG_PRINT(INHERIT_ONLY_ACE); 79 ACE_FLAG_PRINT(INHERITED_ACE); 80 #undef ACE_FLAG_PRINT 81 } 82 83 /** 84 * @brief 85 * Iterates and dumps each ACE debug info in an ACL. 86 */ 87 static 88 VOID 89 SepDumpAces( 90 _In_ PACL Acl) 91 { 92 NTSTATUS Status; 93 PACE Ace; 94 ULONG AceIndex; 95 PSID Sid; 96 UNICODE_STRING SidString; 97 98 /* Loop all ACEs and dump their info */ 99 for (AceIndex = 0; AceIndex < Acl->AceCount; AceIndex++) 100 { 101 /* Get the ACE at this index */ 102 Status = RtlGetAce(Acl, AceIndex, (PVOID*)&Ace); 103 if (!NT_SUCCESS(Status)) 104 { 105 /* 106 * Normally this should never happen. 107 * Just fail gracefully and stop further 108 * debugging of ACEs. 109 */ 110 DbgPrint("SepDumpAces(): Failed to find the next ACE, stop dumping info...\n"); 111 return; 112 } 113 114 DbgPrint("================== %lu# ACE DUMP INFO ==================\n", AceIndex); 115 DbgPrint("Ace -> 0x%p\n", Ace); 116 DbgPrint("Ace->Header -> 0x%p\n", Ace->Header); 117 DbgPrint("Ace->Header.AceType -> %s\n", SepGetAceTypeString(Ace->Header.AceType)); 118 DbgPrint("Ace->AccessMask -> 0x%08lx\n", Ace->AccessMask); 119 120 Sid = SepGetSidFromAce(Ace->Header.AceType, Ace); 121 ASSERT(Sid); 122 RtlConvertSidToUnicodeString(&SidString, Sid, TRUE); 123 DbgPrint("Ace SID -> %wZ\n", &SidString); 124 RtlFreeUnicodeString(&SidString); 125 126 DbgPrint("Ace->Header.AceSize -> %u\n", Ace->Header.AceSize); 127 DbgPrint("Ace->Header.AceFlags:\n"); 128 SepDumpAceFlags(Ace->Header.AceFlags); 129 } 130 } 131 132 /** 133 * @brief 134 * Dumps debug info of an Access Control List (ACL). 135 */ 136 static 137 VOID 138 SepDumpAclInfo( 139 _In_ PACL Acl, 140 _In_ BOOLEAN IsSacl) 141 { 142 /* Dump relevant info */ 143 DbgPrint("================== %s DUMP INFO ==================\n", IsSacl ? "SACL" : "DACL"); 144 DbgPrint("Acl->AclRevision -> %u\n", Acl->AclRevision); 145 DbgPrint("Acl->AclSize -> %u\n", Acl->AclSize); 146 DbgPrint("Acl->AceCount -> %u\n", Acl->AceCount); 147 148 /* Dump all the ACEs present on this ACL */ 149 SepDumpAces(Acl); 150 } 151 152 /** 153 * @brief 154 * Dumps control flags of a security descriptor to the debugger. 155 */ 156 static 157 VOID 158 SepDumpSdControlInfo( 159 _In_ SECURITY_DESCRIPTOR_CONTROL SdControl) 160 { 161 #define SD_CONTROL_PRINT(x) \ 162 if (SdControl & x) \ 163 { \ 164 DbgPrint(#x "\n"); \ 165 } 166 167 SD_CONTROL_PRINT(SE_OWNER_DEFAULTED); 168 SD_CONTROL_PRINT(SE_GROUP_DEFAULTED); 169 SD_CONTROL_PRINT(SE_DACL_PRESENT); 170 SD_CONTROL_PRINT(SE_DACL_DEFAULTED); 171 SD_CONTROL_PRINT(SE_SACL_PRESENT); 172 SD_CONTROL_PRINT(SE_SACL_DEFAULTED); 173 SD_CONTROL_PRINT(SE_DACL_UNTRUSTED); 174 SD_CONTROL_PRINT(SE_SERVER_SECURITY); 175 SD_CONTROL_PRINT(SE_DACL_AUTO_INHERIT_REQ); 176 SD_CONTROL_PRINT(SE_SACL_AUTO_INHERIT_REQ); 177 SD_CONTROL_PRINT(SE_DACL_AUTO_INHERITED); 178 SD_CONTROL_PRINT(SE_SACL_AUTO_INHERITED); 179 SD_CONTROL_PRINT(SE_DACL_PROTECTED); 180 SD_CONTROL_PRINT(SE_SACL_PROTECTED); 181 SD_CONTROL_PRINT(SE_RM_CONTROL_VALID); 182 SD_CONTROL_PRINT(SE_SELF_RELATIVE); 183 #undef SD_CONTROL_PRINT 184 } 185 186 /** 187 * @brief 188 * Dumps each security identifier (SID) of an access token to debugger. 189 */ 190 static 191 VOID 192 SepDumpSidsOfToken( 193 _In_ PSID_AND_ATTRIBUTES Sids, 194 _In_ ULONG SidCount) 195 { 196 ULONG SidIndex; 197 UNICODE_STRING SidString; 198 199 /* Loop all SIDs and dump them */ 200 for (SidIndex = 0; SidIndex < SidCount; SidIndex++) 201 { 202 RtlConvertSidToUnicodeString(&SidString, Sids[SidIndex].Sid, TRUE); 203 DbgPrint("%lu# %wZ\n", SidIndex, &SidString); 204 RtlFreeUnicodeString(&SidString); 205 } 206 } 207 208 /* PUBLIC FUNCTIONS ***********************************************************/ 209 210 /** 211 * @brief 212 * Dumps debug information of a security descriptor to the debugger. 213 */ 214 VOID 215 SepDumpSdDebugInfo( 216 _In_opt_ PISECURITY_DESCRIPTOR SecurityDescriptor) 217 { 218 UNICODE_STRING SidString; 219 PSID OwnerSid, GroupSid; 220 PACL Dacl, Sacl; 221 222 /* Don't dump anything if no SD was provided */ 223 if (!SecurityDescriptor) 224 { 225 return; 226 } 227 228 /* Cache the necessary security buffers to dump info from */ 229 OwnerSid = SepGetOwnerFromDescriptor(SecurityDescriptor); 230 GroupSid = SepGetGroupFromDescriptor(SecurityDescriptor); 231 Sacl = SepGetSaclFromDescriptor(SecurityDescriptor); 232 Dacl = SepGetDaclFromDescriptor(SecurityDescriptor); 233 234 DbgPrint("================== SECURITY DESCRIPTOR DUMP INFO ==================\n"); 235 DbgPrint("SecurityDescriptor -> 0x%p\n", SecurityDescriptor); 236 DbgPrint("SecurityDescriptor->Revision -> %u\n", SecurityDescriptor->Revision); 237 DbgPrint("SecurityDescriptor->Control:\n"); 238 SepDumpSdControlInfo(SecurityDescriptor->Control); 239 240 /* Dump the Owner SID if the SD belongs to an owner */ 241 if (OwnerSid) 242 { 243 RtlConvertSidToUnicodeString(&SidString, OwnerSid, TRUE); 244 DbgPrint("SD Owner SID -> %wZ\n", &SidString); 245 RtlFreeUnicodeString(&SidString); 246 } 247 248 /* Dump the Group SID if the SD belongs to a group */ 249 if (GroupSid) 250 { 251 RtlConvertSidToUnicodeString(&SidString, GroupSid, TRUE); 252 DbgPrint("SD Group SID -> %wZ\n", &SidString); 253 RtlFreeUnicodeString(&SidString); 254 } 255 256 /* Dump the ACL contents of SACL if this SD has one */ 257 if (Sacl) 258 { 259 SepDumpAclInfo(Sacl, TRUE); 260 } 261 262 /* Dump the ACL contents of DACL if this SD has one */ 263 if (Dacl) 264 { 265 SepDumpAclInfo(Dacl, FALSE); 266 } 267 } 268 269 /** 270 * @brief 271 * Dumps debug information of an access token to the debugger. 272 */ 273 VOID 274 SepDumpTokenDebugInfo( 275 _In_opt_ PTOKEN Token) 276 { 277 UNICODE_STRING SidString; 278 279 /* Don't dump anything if no token was provided */ 280 if (!Token) 281 { 282 return; 283 } 284 285 /* Dump relevant token info */ 286 DbgPrint("================== ACCESS TOKEN DUMP INFO ==================\n"); 287 DbgPrint("Token -> 0x%p\n", Token); 288 DbgPrint("Token->ImageFileName -> %s\n", Token->ImageFileName); 289 DbgPrint("Token->TokenSource.SourceName -> \"%-.*s\"\n", 290 RTL_NUMBER_OF(Token->TokenSource.SourceName), 291 Token->TokenSource.SourceName); 292 DbgPrint("Token->TokenSource.SourceIdentifier -> %lu.%lu\n", 293 Token->TokenSource.SourceIdentifier.HighPart, 294 Token->TokenSource.SourceIdentifier.LowPart); 295 296 RtlConvertSidToUnicodeString(&SidString, Token->PrimaryGroup, TRUE); 297 DbgPrint("Token primary group SID -> %wZ\n", &SidString); 298 RtlFreeUnicodeString(&SidString); 299 300 DbgPrint("Token user and groups SIDs:\n"); 301 SepDumpSidsOfToken(Token->UserAndGroups, Token->UserAndGroupCount); 302 303 if (SeTokenIsRestricted(Token)) 304 { 305 DbgPrint("Token restricted SIDs:\n"); 306 SepDumpSidsOfToken(Token->RestrictedSids, Token->RestrictedSidCount); 307 } 308 } 309 310 /** 311 * @brief 312 * Dumps security access rights to the debugger. 313 */ 314 VOID 315 SepDumpAccessRightsStats( 316 _In_opt_ PACCESS_CHECK_RIGHTS AccessRights) 317 { 318 /* Don't dump anything if no access check rights list was provided */ 319 if (!AccessRights) 320 { 321 return; 322 } 323 324 DbgPrint("================== ACCESS CHECK RIGHTS STATISTICS ==================\n"); 325 DbgPrint("Remaining access rights -> 0x%08lx\n", AccessRights->RemainingAccessRights); 326 DbgPrint("Granted access rights -> 0x%08lx\n", AccessRights->GrantedAccessRights); 327 DbgPrint("Denied access rights -> 0x%08lx\n", AccessRights->DeniedAccessRights); 328 } 329 330 /* EOF */ 331