xref: /reactos/ntoskrnl/se/debug.c (revision 5efb6e3d)
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