xref: /reactos/ntoskrnl/se/debug.c (revision 3c797b31)
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 #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  */
26 static
27 PCSTR
28 SepGetAceTypeString(
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  */
65 static
66 VOID
67 SepDumpAceFlags(
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  */
88 static
89 VOID
90 SepDumpAces(
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->Header.AceType, 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  */
137 static
138 VOID
139 SepDumpAclInfo(
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  */
157 static
158 VOID
159 SepDumpSdControlInfo(
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  */
191 static
192 VOID
193 SepDumpSidsOfToken(
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  */
216 VOID
217 SepDumpSdDebugInfo(
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  */
279 VOID
280 SepDumpTokenDebugInfo(
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  */
324 VOID
325 SepDumpAccessRightsStats(
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 /* EOF */
348