xref: /reactos/ntoskrnl/se/sid.c (revision 171a9206)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:         Security Identifier (SID) implementation support and handling
5  * COPYRIGHT:       Copyright David Welch <welch@cwcom.net>
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include <ntoskrnl.h>
11 #define NDEBUG
12 #include <debug.h>
13 
14 /* GLOBALS ********************************************************************/
15 
16 #define SE_MAXIMUM_GROUP_LIMIT 0x1000
17 
18 SID_IDENTIFIER_AUTHORITY SeNullSidAuthority = {SECURITY_NULL_SID_AUTHORITY};
19 SID_IDENTIFIER_AUTHORITY SeWorldSidAuthority = {SECURITY_WORLD_SID_AUTHORITY};
20 SID_IDENTIFIER_AUTHORITY SeLocalSidAuthority = {SECURITY_LOCAL_SID_AUTHORITY};
21 SID_IDENTIFIER_AUTHORITY SeCreatorSidAuthority = {SECURITY_CREATOR_SID_AUTHORITY};
22 SID_IDENTIFIER_AUTHORITY SeNtSidAuthority = {SECURITY_NT_AUTHORITY};
23 
24 PSID SeNullSid = NULL;
25 PSID SeWorldSid = NULL;
26 PSID SeLocalSid = NULL;
27 PSID SeCreatorOwnerSid = NULL;
28 PSID SeCreatorGroupSid = NULL;
29 PSID SeCreatorOwnerServerSid = NULL;
30 PSID SeCreatorGroupServerSid = NULL;
31 PSID SeNtAuthoritySid = NULL;
32 PSID SeDialupSid = NULL;
33 PSID SeNetworkSid = NULL;
34 PSID SeBatchSid = NULL;
35 PSID SeInteractiveSid = NULL;
36 PSID SeServiceSid = NULL;
37 PSID SePrincipalSelfSid = NULL;
38 PSID SeLocalSystemSid = NULL;
39 PSID SeAuthenticatedUserSid = NULL;
40 PSID SeRestrictedCodeSid = NULL;
41 PSID SeAliasAdminsSid = NULL;
42 PSID SeAliasUsersSid = NULL;
43 PSID SeAliasGuestsSid = NULL;
44 PSID SeAliasPowerUsersSid = NULL;
45 PSID SeAliasAccountOpsSid = NULL;
46 PSID SeAliasSystemOpsSid = NULL;
47 PSID SeAliasPrintOpsSid = NULL;
48 PSID SeAliasBackupOpsSid = NULL;
49 PSID SeAuthenticatedUsersSid = NULL;
50 PSID SeRestrictedSid = NULL;
51 PSID SeAnonymousLogonSid = NULL;
52 PSID SeLocalServiceSid = NULL;
53 PSID SeNetworkServiceSid = NULL;
54 
55 typedef struct _SID_VALIDATE
56 {
57     UCHAR SubAuthorityCount;
58     PISID ProbeSid;
59 } SID_VALIDATE, *PSID_VALIDATE;
60 
61 /* FUNCTIONS ******************************************************************/
62 
63 /**
64  * @brief
65  * Frees all the known initialized SIDs in the system from the memory.
66  *
67  * @return
68  * Nothing.
69  */
70 VOID
71 NTAPI
72 FreeInitializedSids(VOID)
73 {
74     if (SeNullSid) ExFreePoolWithTag(SeNullSid, TAG_SID);
75     if (SeWorldSid) ExFreePoolWithTag(SeWorldSid, TAG_SID);
76     if (SeLocalSid) ExFreePoolWithTag(SeLocalSid, TAG_SID);
77     if (SeCreatorOwnerSid) ExFreePoolWithTag(SeCreatorOwnerSid, TAG_SID);
78     if (SeCreatorGroupSid) ExFreePoolWithTag(SeCreatorGroupSid, TAG_SID);
79     if (SeCreatorOwnerServerSid) ExFreePoolWithTag(SeCreatorOwnerServerSid, TAG_SID);
80     if (SeCreatorGroupServerSid) ExFreePoolWithTag(SeCreatorGroupServerSid, TAG_SID);
81     if (SeNtAuthoritySid) ExFreePoolWithTag(SeNtAuthoritySid, TAG_SID);
82     if (SeDialupSid) ExFreePoolWithTag(SeDialupSid, TAG_SID);
83     if (SeNetworkSid) ExFreePoolWithTag(SeNetworkSid, TAG_SID);
84     if (SeBatchSid) ExFreePoolWithTag(SeBatchSid, TAG_SID);
85     if (SeInteractiveSid) ExFreePoolWithTag(SeInteractiveSid, TAG_SID);
86     if (SeServiceSid) ExFreePoolWithTag(SeServiceSid, TAG_SID);
87     if (SePrincipalSelfSid) ExFreePoolWithTag(SePrincipalSelfSid, TAG_SID);
88     if (SeLocalSystemSid) ExFreePoolWithTag(SeLocalSystemSid, TAG_SID);
89     if (SeAuthenticatedUserSid) ExFreePoolWithTag(SeAuthenticatedUserSid, TAG_SID);
90     if (SeRestrictedCodeSid) ExFreePoolWithTag(SeRestrictedCodeSid, TAG_SID);
91     if (SeAliasAdminsSid) ExFreePoolWithTag(SeAliasAdminsSid, TAG_SID);
92     if (SeAliasUsersSid) ExFreePoolWithTag(SeAliasUsersSid, TAG_SID);
93     if (SeAliasGuestsSid) ExFreePoolWithTag(SeAliasGuestsSid, TAG_SID);
94     if (SeAliasPowerUsersSid) ExFreePoolWithTag(SeAliasPowerUsersSid, TAG_SID);
95     if (SeAliasAccountOpsSid) ExFreePoolWithTag(SeAliasAccountOpsSid, TAG_SID);
96     if (SeAliasSystemOpsSid) ExFreePoolWithTag(SeAliasSystemOpsSid, TAG_SID);
97     if (SeAliasPrintOpsSid) ExFreePoolWithTag(SeAliasPrintOpsSid, TAG_SID);
98     if (SeAliasBackupOpsSid) ExFreePoolWithTag(SeAliasBackupOpsSid, TAG_SID);
99     if (SeAuthenticatedUsersSid) ExFreePoolWithTag(SeAuthenticatedUsersSid, TAG_SID);
100     if (SeRestrictedSid) ExFreePoolWithTag(SeRestrictedSid, TAG_SID);
101     if (SeAnonymousLogonSid) ExFreePoolWithTag(SeAnonymousLogonSid, TAG_SID);
102 }
103 
104 /**
105  * @brief
106  * Initializes all the SIDs known in the system.
107  *
108  * @return
109  * Returns TRUE if all the SIDs have been initialized,
110  * FALSE otherwise.
111  */
112 CODE_SEG("INIT")
113 BOOLEAN
114 NTAPI
115 SepInitSecurityIDs(VOID)
116 {
117     ULONG SidLength0;
118     ULONG SidLength1;
119     ULONG SidLength2;
120     PULONG SubAuthority;
121 
122     SidLength0 = RtlLengthRequiredSid(0);
123     SidLength1 = RtlLengthRequiredSid(1);
124     SidLength2 = RtlLengthRequiredSid(2);
125 
126     /* create NullSid */
127     SeNullSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
128     SeWorldSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
129     SeLocalSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
130     SeCreatorOwnerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
131     SeCreatorGroupSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
132     SeCreatorOwnerServerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
133     SeCreatorGroupServerSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
134     SeNtAuthoritySid = ExAllocatePoolWithTag(PagedPool, SidLength0, TAG_SID);
135     SeDialupSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
136     SeNetworkSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
137     SeBatchSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
138     SeInteractiveSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
139     SeServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
140     SePrincipalSelfSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
141     SeLocalSystemSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
142     SeAuthenticatedUserSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
143     SeRestrictedCodeSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
144     SeAliasAdminsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
145     SeAliasUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
146     SeAliasGuestsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
147     SeAliasPowerUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
148     SeAliasAccountOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
149     SeAliasSystemOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
150     SeAliasPrintOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
151     SeAliasBackupOpsSid = ExAllocatePoolWithTag(PagedPool, SidLength2, TAG_SID);
152     SeAuthenticatedUsersSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
153     SeRestrictedSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
154     SeAnonymousLogonSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
155     SeLocalServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
156     SeNetworkServiceSid = ExAllocatePoolWithTag(PagedPool, SidLength1, TAG_SID);
157 
158     if (SeNullSid == NULL || SeWorldSid == NULL ||
159         SeLocalSid == NULL || SeCreatorOwnerSid == NULL ||
160         SeCreatorGroupSid == NULL || SeCreatorOwnerServerSid == NULL ||
161         SeCreatorGroupServerSid == NULL || SeNtAuthoritySid == NULL ||
162         SeDialupSid == NULL || SeNetworkSid == NULL || SeBatchSid == NULL ||
163         SeInteractiveSid == NULL || SeServiceSid == NULL ||
164         SePrincipalSelfSid == NULL || SeLocalSystemSid == NULL ||
165         SeAuthenticatedUserSid == NULL || SeRestrictedCodeSid == NULL ||
166         SeAliasAdminsSid == NULL || SeAliasUsersSid == NULL ||
167         SeAliasGuestsSid == NULL || SeAliasPowerUsersSid == NULL ||
168         SeAliasAccountOpsSid == NULL || SeAliasSystemOpsSid == NULL ||
169         SeAliasPrintOpsSid == NULL || SeAliasBackupOpsSid == NULL ||
170         SeAuthenticatedUsersSid == NULL || SeRestrictedSid == NULL ||
171         SeAnonymousLogonSid == NULL || SeLocalServiceSid == NULL ||
172         SeNetworkServiceSid == NULL)
173     {
174         FreeInitializedSids();
175         return FALSE;
176     }
177 
178     RtlInitializeSid(SeNullSid, &SeNullSidAuthority, 1);
179     RtlInitializeSid(SeWorldSid, &SeWorldSidAuthority, 1);
180     RtlInitializeSid(SeLocalSid, &SeLocalSidAuthority, 1);
181     RtlInitializeSid(SeCreatorOwnerSid, &SeCreatorSidAuthority, 1);
182     RtlInitializeSid(SeCreatorGroupSid, &SeCreatorSidAuthority, 1);
183     RtlInitializeSid(SeCreatorOwnerServerSid, &SeCreatorSidAuthority, 1);
184     RtlInitializeSid(SeCreatorGroupServerSid, &SeCreatorSidAuthority, 1);
185     RtlInitializeSid(SeNtAuthoritySid, &SeNtSidAuthority, 0);
186     RtlInitializeSid(SeDialupSid, &SeNtSidAuthority, 1);
187     RtlInitializeSid(SeNetworkSid, &SeNtSidAuthority, 1);
188     RtlInitializeSid(SeBatchSid, &SeNtSidAuthority, 1);
189     RtlInitializeSid(SeInteractiveSid, &SeNtSidAuthority, 1);
190     RtlInitializeSid(SeServiceSid, &SeNtSidAuthority, 1);
191     RtlInitializeSid(SePrincipalSelfSid, &SeNtSidAuthority, 1);
192     RtlInitializeSid(SeLocalSystemSid, &SeNtSidAuthority, 1);
193     RtlInitializeSid(SeAuthenticatedUserSid, &SeNtSidAuthority, 1);
194     RtlInitializeSid(SeRestrictedCodeSid, &SeNtSidAuthority, 1);
195     RtlInitializeSid(SeAliasAdminsSid, &SeNtSidAuthority, 2);
196     RtlInitializeSid(SeAliasUsersSid, &SeNtSidAuthority, 2);
197     RtlInitializeSid(SeAliasGuestsSid, &SeNtSidAuthority, 2);
198     RtlInitializeSid(SeAliasPowerUsersSid, &SeNtSidAuthority, 2);
199     RtlInitializeSid(SeAliasAccountOpsSid, &SeNtSidAuthority, 2);
200     RtlInitializeSid(SeAliasSystemOpsSid, &SeNtSidAuthority, 2);
201     RtlInitializeSid(SeAliasPrintOpsSid, &SeNtSidAuthority, 2);
202     RtlInitializeSid(SeAliasBackupOpsSid, &SeNtSidAuthority, 2);
203     RtlInitializeSid(SeAuthenticatedUsersSid, &SeNtSidAuthority, 1);
204     RtlInitializeSid(SeRestrictedSid, &SeNtSidAuthority, 1);
205     RtlInitializeSid(SeAnonymousLogonSid, &SeNtSidAuthority, 1);
206     RtlInitializeSid(SeLocalServiceSid, &SeNtSidAuthority, 1);
207     RtlInitializeSid(SeNetworkServiceSid, &SeNtSidAuthority, 1);
208 
209     SubAuthority = RtlSubAuthoritySid(SeNullSid, 0);
210     *SubAuthority = SECURITY_NULL_RID;
211     SubAuthority = RtlSubAuthoritySid(SeWorldSid, 0);
212     *SubAuthority = SECURITY_WORLD_RID;
213     SubAuthority = RtlSubAuthoritySid(SeLocalSid, 0);
214     *SubAuthority = SECURITY_LOCAL_RID;
215     SubAuthority = RtlSubAuthoritySid(SeCreatorOwnerSid, 0);
216     *SubAuthority = SECURITY_CREATOR_OWNER_RID;
217     SubAuthority = RtlSubAuthoritySid(SeCreatorGroupSid, 0);
218     *SubAuthority = SECURITY_CREATOR_GROUP_RID;
219     SubAuthority = RtlSubAuthoritySid(SeCreatorOwnerServerSid, 0);
220     *SubAuthority = SECURITY_CREATOR_OWNER_SERVER_RID;
221     SubAuthority = RtlSubAuthoritySid(SeCreatorGroupServerSid, 0);
222     *SubAuthority = SECURITY_CREATOR_GROUP_SERVER_RID;
223     SubAuthority = RtlSubAuthoritySid(SeDialupSid, 0);
224     *SubAuthority = SECURITY_DIALUP_RID;
225     SubAuthority = RtlSubAuthoritySid(SeNetworkSid, 0);
226     *SubAuthority = SECURITY_NETWORK_RID;
227     SubAuthority = RtlSubAuthoritySid(SeBatchSid, 0);
228     *SubAuthority = SECURITY_BATCH_RID;
229     SubAuthority = RtlSubAuthoritySid(SeInteractiveSid, 0);
230     *SubAuthority = SECURITY_INTERACTIVE_RID;
231     SubAuthority = RtlSubAuthoritySid(SeServiceSid, 0);
232     *SubAuthority = SECURITY_SERVICE_RID;
233     SubAuthority = RtlSubAuthoritySid(SePrincipalSelfSid, 0);
234     *SubAuthority = SECURITY_PRINCIPAL_SELF_RID;
235     SubAuthority = RtlSubAuthoritySid(SeLocalSystemSid, 0);
236     *SubAuthority = SECURITY_LOCAL_SYSTEM_RID;
237     SubAuthority = RtlSubAuthoritySid(SeAuthenticatedUserSid, 0);
238     *SubAuthority = SECURITY_AUTHENTICATED_USER_RID;
239     SubAuthority = RtlSubAuthoritySid(SeRestrictedCodeSid, 0);
240     *SubAuthority = SECURITY_RESTRICTED_CODE_RID;
241     SubAuthority = RtlSubAuthoritySid(SeAliasAdminsSid, 0);
242     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
243     SubAuthority = RtlSubAuthoritySid(SeAliasAdminsSid, 1);
244     *SubAuthority = DOMAIN_ALIAS_RID_ADMINS;
245     SubAuthority = RtlSubAuthoritySid(SeAliasUsersSid, 0);
246     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
247     SubAuthority = RtlSubAuthoritySid(SeAliasUsersSid, 1);
248     *SubAuthority = DOMAIN_ALIAS_RID_USERS;
249     SubAuthority = RtlSubAuthoritySid(SeAliasGuestsSid, 0);
250     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
251     SubAuthority = RtlSubAuthoritySid(SeAliasGuestsSid, 1);
252     *SubAuthority = DOMAIN_ALIAS_RID_GUESTS;
253     SubAuthority = RtlSubAuthoritySid(SeAliasPowerUsersSid, 0);
254     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
255     SubAuthority = RtlSubAuthoritySid(SeAliasPowerUsersSid, 1);
256     *SubAuthority = DOMAIN_ALIAS_RID_POWER_USERS;
257     SubAuthority = RtlSubAuthoritySid(SeAliasAccountOpsSid, 0);
258     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
259     SubAuthority = RtlSubAuthoritySid(SeAliasAccountOpsSid, 1);
260     *SubAuthority = DOMAIN_ALIAS_RID_ACCOUNT_OPS;
261     SubAuthority = RtlSubAuthoritySid(SeAliasSystemOpsSid, 0);
262     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
263     SubAuthority = RtlSubAuthoritySid(SeAliasSystemOpsSid, 1);
264     *SubAuthority = DOMAIN_ALIAS_RID_SYSTEM_OPS;
265     SubAuthority = RtlSubAuthoritySid(SeAliasPrintOpsSid, 0);
266     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
267     SubAuthority = RtlSubAuthoritySid(SeAliasPrintOpsSid, 1);
268     *SubAuthority = DOMAIN_ALIAS_RID_PRINT_OPS;
269     SubAuthority = RtlSubAuthoritySid(SeAliasBackupOpsSid, 0);
270     *SubAuthority = SECURITY_BUILTIN_DOMAIN_RID;
271     SubAuthority = RtlSubAuthoritySid(SeAliasBackupOpsSid, 1);
272     *SubAuthority = DOMAIN_ALIAS_RID_BACKUP_OPS;
273     SubAuthority = RtlSubAuthoritySid(SeAuthenticatedUsersSid, 0);
274     *SubAuthority = SECURITY_AUTHENTICATED_USER_RID;
275     SubAuthority = RtlSubAuthoritySid(SeRestrictedSid, 0);
276     *SubAuthority = SECURITY_RESTRICTED_CODE_RID;
277     SubAuthority = RtlSubAuthoritySid(SeAnonymousLogonSid, 0);
278     *SubAuthority = SECURITY_ANONYMOUS_LOGON_RID;
279     SubAuthority = RtlSubAuthoritySid(SeLocalServiceSid, 0);
280     *SubAuthority = SECURITY_LOCAL_SERVICE_RID;
281     SubAuthority = RtlSubAuthoritySid(SeNetworkServiceSid, 0);
282     *SubAuthority = SECURITY_NETWORK_SERVICE_RID;
283 
284     return TRUE;
285 }
286 
287 /**
288  * @brief
289  * Captures a SID.
290  *
291  * @param[in] InputSid
292  * A valid security identifier to be captured.
293  *
294  * @param[in] AccessMode
295  * Processor level access mode.
296  *
297  * @param[in] PoolType
298  * Pool memory type for the captured SID to assign upon
299  * allocation.
300  *
301  * @param[in] CaptureIfKernel
302  * If set to TRUE, the capturing is done within the kernel.
303  * Otherwise the capturing is done in a kernel mode driver.
304  *
305  * @param[out] CapturedSid
306  * The captured security identifier, returned to the caller.
307  *
308  * @return
309  * Returns STATUS_SUCCESS if the SID was captured. STATUS_INSUFFICIENT_RESOURCES
310  * is returned if memory pool allocation for the captured SID has failed.
311  */
312 NTSTATUS
313 NTAPI
314 SepCaptureSid(
315     _In_ PSID InputSid,
316     _In_ KPROCESSOR_MODE AccessMode,
317     _In_ POOL_TYPE PoolType,
318     _In_ BOOLEAN CaptureIfKernel,
319     _Out_ PSID *CapturedSid)
320 {
321     ULONG SidSize = 0;
322     PISID NewSid, Sid = (PISID)InputSid;
323 
324     PAGED_CODE();
325 
326     if (AccessMode != KernelMode)
327     {
328         _SEH2_TRY
329         {
330             ProbeForRead(Sid, FIELD_OFFSET(SID, SubAuthority), sizeof(UCHAR));
331             SidSize = RtlLengthRequiredSid(Sid->SubAuthorityCount);
332             ProbeForRead(Sid, SidSize, sizeof(UCHAR));
333         }
334         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
335         {
336             /* Return the exception code */
337             _SEH2_YIELD(return _SEH2_GetExceptionCode());
338         }
339         _SEH2_END;
340 
341         /* Allocate a SID and copy it */
342         NewSid = ExAllocatePoolWithTag(PoolType, SidSize, TAG_SID);
343         if (!NewSid)
344             return STATUS_INSUFFICIENT_RESOURCES;
345 
346         _SEH2_TRY
347         {
348             RtlCopyMemory(NewSid, Sid, SidSize);
349 
350             *CapturedSid = NewSid;
351         }
352         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
353         {
354             /* Free the SID and return the exception code */
355             ExFreePoolWithTag(NewSid, TAG_SID);
356             _SEH2_YIELD(return _SEH2_GetExceptionCode());
357         }
358         _SEH2_END;
359     }
360     else if (!CaptureIfKernel)
361     {
362         *CapturedSid = InputSid;
363     }
364     else
365     {
366         SidSize = RtlLengthRequiredSid(Sid->SubAuthorityCount);
367 
368         /* Allocate a SID and copy it */
369         NewSid = ExAllocatePoolWithTag(PoolType, SidSize, TAG_SID);
370         if (NewSid == NULL)
371             return STATUS_INSUFFICIENT_RESOURCES;
372 
373         RtlCopyMemory(NewSid, Sid, SidSize);
374 
375         *CapturedSid = NewSid;
376     }
377 
378     return STATUS_SUCCESS;
379 }
380 
381 /**
382  * @brief
383  * Releases a captured SID.
384  *
385  * @param[in] CapturedSid
386  * The captured SID to be released.
387  *
388  * @param[in] AccessMode
389  * Processor level access mode.
390  *
391  * @param[in] CaptureIfKernel
392  * If set to TRUE, the releasing is done within the kernel.
393  * Otherwise the releasing is done in a kernel mode driver.
394  *
395  * @return
396  * Nothing.
397  */
398 VOID
399 NTAPI
400 SepReleaseSid(
401     _In_ PSID CapturedSid,
402     _In_ KPROCESSOR_MODE AccessMode,
403     _In_ BOOLEAN CaptureIfKernel)
404 {
405     PAGED_CODE();
406 
407     if (CapturedSid != NULL &&
408         (AccessMode != KernelMode ||
409          (AccessMode == KernelMode && CaptureIfKernel)))
410     {
411         ExFreePoolWithTag(CapturedSid, TAG_SID);
412     }
413 }
414 
415 /**
416  * @brief
417  * Captures a SID with attributes.
418  *
419  * @param[in] SrcSidAndAttributes
420  * Source of the SID with attributes to be captured.
421  *
422  * @param[in] AttributeCount
423  * The number count of attributes, in total.
424  *
425  * @param[in] PreviousMode
426  * Processor access level mode.
427  *
428  * @param[in] AllocatedMem
429  * The allocated memory buffer for the captured SID. If the caller
430  * supplies no allocated block of memory then the function will
431  * allocate some buffer block of memory for the captured SID
432  * automatically.
433  *
434  * @param[in] AllocatedLength
435  * The length of the buffer that points to the allocated memory,
436  * in bytes.
437  *
438  * @param[in] PoolType
439  * The pool type for the captured SID and attributes to assign.
440  *
441  * @param[in] CaptureIfKernel
442  * If set to TRUE, the capturing is done within the kernel.
443  * Otherwise the capturing is done in a kernel mode driver.
444  *
445  * @param[out] CapturedSidAndAttributes
446  * The captured SID and attributes.
447  *
448  * @param[out] ResultLength
449  * The length of the captured SID and attributes, in bytes.
450  *
451  * @return
452  * Returns STATUS_SUCCESS if SID and attributes capturing
453  * has been completed successfully. STATUS_INVALID_PARAMETER
454  * is returned if the count of attributes exceeds the maximum
455  * threshold that the kernel can permit, with the purpose of
456  * avoiding integer overflows. STATUS_INSUFFICIENT_RESOURCES
457  * is returned if memory pool allocation for the captured SID has failed.
458  * STATUS_BUFFER_TOO_SMALL is returned if the length of the allocated
459  * buffer is less than the required size. STATUS_INVALID_SID is returned
460  * if a SID doesn't meet certain requirements to be considered a valid
461  * SID by the security manager. A failure NTSTATUS code is returned
462  * otherwise.
463  *
464  * @remarks
465  * A security identifier (SID) is a variable-length data structure that
466  * can change in size over time, depending on the factors that influence
467  * this effect in question. An attacker can take advantage of this fact
468  * and can potentially modify certain properties of a SID making it
469  * different in size than it was originally before. This is what we'd
470  * call, a TOCTOU vulnerability.
471  *
472  * For this reason, the logic of copying the SIDs and their attributes
473  * into a new buffer goes like this: first, allocate a buffer array
474  * that just holds the lengths and subauthority count of each SID.
475  * Such information is copied in the first loop. Then in a second loop,
476  * iterate over the array with SID provided and copy them into the final
477  * array. The moment we're doing this, validate the lengths of each SID
478  * basing upon the captured lengths we've got before. In this way we
479  * ensure that the SIDs have remained intact. The validation checks are
480  * done in user mode as a general rule that we just cannot trust UM and
481  * whatever data is coming from it.
482  */
483 NTSTATUS
484 NTAPI
485 SeCaptureSidAndAttributesArray(
486     _In_ PSID_AND_ATTRIBUTES SrcSidAndAttributes,
487     _In_ ULONG AttributeCount,
488     _In_ KPROCESSOR_MODE PreviousMode,
489     _In_opt_ PVOID AllocatedMem,
490     _In_ ULONG AllocatedLength,
491     _In_ POOL_TYPE PoolType,
492     _In_ BOOLEAN CaptureIfKernel,
493     _Out_ PSID_AND_ATTRIBUTES *CapturedSidAndAttributes,
494     _Out_ PULONG ResultLength)
495 {
496     ULONG ArraySize, RequiredLength, SidLength, i;
497     ULONG TempArrayValidate, TempLengthValidate;
498     PSID_AND_ATTRIBUTES SidAndAttributes;
499     _SEH2_VOLATILE PSID_VALIDATE ValidateArray;
500     PUCHAR CurrentDest;
501     PISID Sid;
502     NTSTATUS Status;
503     PAGED_CODE();
504 
505     ValidateArray = NULL;
506     SidAndAttributes = NULL;
507     *CapturedSidAndAttributes = NULL;
508     *ResultLength = 0;
509 
510     if (AttributeCount == 0)
511     {
512         return STATUS_SUCCESS;
513     }
514 
515     if (AttributeCount > SE_MAXIMUM_GROUP_LIMIT)
516     {
517         DPRINT1("SeCaptureSidAndAttributesArray(): Maximum group limit exceeded!\n");
518         return STATUS_INVALID_PARAMETER;
519     }
520 
521     if ((PreviousMode == KernelMode) && !CaptureIfKernel)
522     {
523         *CapturedSidAndAttributes = SrcSidAndAttributes;
524         return STATUS_SUCCESS;
525     }
526 
527     ArraySize = AttributeCount * sizeof(SID_AND_ATTRIBUTES);
528     RequiredLength = ALIGN_UP_BY(ArraySize, sizeof(ULONG));
529 
530     if (PreviousMode != KernelMode)
531     {
532         /* Check for user mode data */
533         _SEH2_TRY
534         {
535             /* First probe the whole array */
536             ProbeForRead(SrcSidAndAttributes, ArraySize, sizeof(ULONG));
537 
538             /* We're in user mode, set up the size for the temporary array */
539             TempArrayValidate = AttributeCount * sizeof(SID_VALIDATE);
540             TempLengthValidate = ALIGN_UP_BY(TempArrayValidate, sizeof(ULONG));
541 
542             /*
543              * Allocate a buffer for the array that we're going to
544              * temporarily hold the subauthority count and the SID
545              * elements. We'll be going to use this array to perform
546              * validation checks later.
547              */
548             ValidateArray = ExAllocatePoolWithTag(PoolType | POOL_RAISE_IF_ALLOCATION_FAILURE,
549                                                   TempLengthValidate,
550                                                   TAG_SID_VALIDATE);
551 
552             /* Loop the array elements */
553             for (i = 0; i < AttributeCount; i++)
554             {
555                 /* Get the SID and probe the minimal structure */
556                 Sid = SrcSidAndAttributes[i].Sid;
557                 ProbeForRead(Sid, sizeof(*Sid), sizeof(ULONG));
558 
559                 /*
560                  * Capture the subauthority count and hold it
561                  * into the temporary array for later validation.
562                  * This way we ensure that the said count of each
563                  * SID has remained the same.
564                  */
565                 ValidateArray[i].SubAuthorityCount = Sid->SubAuthorityCount;
566 
567                 /* Capture the SID */
568                 ValidateArray[i].ProbeSid = Sid;
569 
570                 /* Calculate the SID length and probe the full SID */
571                 SidLength = RtlLengthRequiredSid(ValidateArray[i].SubAuthorityCount);
572                 ProbeForRead(ValidateArray[i].ProbeSid, SidLength, sizeof(ULONG));
573 
574                 /* Add the aligned length to the required length */
575                 RequiredLength += ALIGN_UP_BY(SidLength, sizeof(ULONG));
576             }
577         }
578         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
579         {
580             Status = _SEH2_GetExceptionCode();
581             _SEH2_YIELD(goto Cleanup);
582         }
583         _SEH2_END;
584     }
585     else
586     {
587         /* Loop the array elements */
588         for (i = 0; i < AttributeCount; i++)
589         {
590             /* Get the SID and it's length */
591             Sid = SrcSidAndAttributes[i].Sid;
592             SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount);
593 
594             /* Add the aligned length to the required length */
595             RequiredLength += ALIGN_UP_BY(SidLength, sizeof(ULONG));
596         }
597     }
598 
599     /* Assume success */
600     Status = STATUS_SUCCESS;
601     *ResultLength = RequiredLength;
602 
603     /* Check if we have no buffer */
604     if (AllocatedMem == NULL)
605     {
606         /* Allocate a new buffer */
607         SidAndAttributes = ExAllocatePoolWithTag(PoolType,
608                                                  RequiredLength,
609                                                  TAG_SID_AND_ATTRIBUTES);
610         if (SidAndAttributes == NULL)
611         {
612             DPRINT1("SeCaptureSidAndAttributesArray(): Failed to allocate memory for SID and attributes array (requested size -> %lu)!\n", RequiredLength);
613             Status = STATUS_INSUFFICIENT_RESOURCES;
614             goto Cleanup;
615         }
616     }
617     /* Otherwise check if the buffer is large enough */
618     else if (AllocatedLength >= RequiredLength)
619     {
620         /* Buffer is large enough, use it */
621         SidAndAttributes = AllocatedMem;
622     }
623     else
624     {
625         /* Buffer is too small, fail */
626         DPRINT1("SeCaptureSidAndAttributesArray(): The provided buffer is small (expected size -> %lu || current size -> %lu)!\n", RequiredLength, AllocatedLength);
627         Status = STATUS_BUFFER_TOO_SMALL;
628         goto Cleanup;
629     }
630 
631     *CapturedSidAndAttributes = SidAndAttributes;
632 
633     /* Check again for user mode */
634     if (PreviousMode != KernelMode)
635     {
636         _SEH2_TRY
637         {
638             /* The rest of the data starts after the array */
639             CurrentDest = (PUCHAR)SidAndAttributes;
640             CurrentDest += ALIGN_UP_BY(ArraySize, sizeof(ULONG));
641 
642             /* Loop the array elements */
643             for (i = 0; i < AttributeCount; i++)
644             {
645                 /*
646                  * Get the SID length from the subauthority
647                  * count we've captured before.
648                  */
649                 SidLength = RtlLengthRequiredSid(ValidateArray[i].SubAuthorityCount);
650 
651                 /* Copy attributes */
652                 SidAndAttributes[i].Attributes = SrcSidAndAttributes[i].Attributes;
653 
654                 /* Copy the SID to the current destination address */
655                 SidAndAttributes[i].Sid = (PSID)CurrentDest;
656                 RtlCopyMemory(CurrentDest, ValidateArray[i].ProbeSid, SidLength);
657 
658                 /* Obtain the SID we've captured before for validation */
659                 Sid = SidAndAttributes[i].Sid;
660 
661                 /* Validate that the subauthority count hasn't changed */
662                 if (ValidateArray[i].SubAuthorityCount !=
663                     Sid->SubAuthorityCount)
664                 {
665                     /* It's changed, bail out */
666                     DPRINT1("SeCaptureSidAndAttributesArray(): The subauthority counts have changed (captured count -> %u || current count -> %u)\n",
667                             ValidateArray[i].SubAuthorityCount, Sid->SubAuthorityCount);
668                     Status = STATUS_INVALID_SID;
669                     goto Cleanup;
670                 }
671 
672                 /* Validate that the SID length is the same */
673                 if (SidLength != RtlLengthSid(Sid))
674                 {
675                     /* They're no longer the same, bail out */
676                     DPRINT1("SeCaptureSidAndAttributesArray(): The SID lengths have changed (captured length -> %lu || current length -> %lu)\n",
677                             SidLength, RtlLengthSid(Sid));
678                     Status = STATUS_INVALID_SID;
679                     goto Cleanup;
680                 }
681 
682                 /* Check that the SID is valid */
683                 if (!RtlValidSid(Sid))
684                 {
685                     DPRINT1("SeCaptureSidAndAttributesArray(): The SID is not valid!\n");
686                     Status = STATUS_INVALID_SID;
687                     goto Cleanup;
688                 }
689 
690                 /* Update the current destination address */
691                 CurrentDest += ALIGN_UP_BY(SidLength, sizeof(ULONG));
692             }
693         }
694         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
695         {
696             Status = _SEH2_GetExceptionCode();
697         }
698         _SEH2_END;
699     }
700     else
701     {
702         /* The rest of the data starts after the array */
703         CurrentDest = (PUCHAR)SidAndAttributes;
704         CurrentDest += ALIGN_UP_BY(ArraySize, sizeof(ULONG));
705 
706         /* Loop the array elements */
707         for (i = 0; i < AttributeCount; i++)
708         {
709             /* Get the SID and it's length */
710             Sid = SrcSidAndAttributes[i].Sid;
711             SidLength = RtlLengthRequiredSid(Sid->SubAuthorityCount);
712 
713             /* Copy attributes */
714             SidAndAttributes[i].Attributes = SrcSidAndAttributes[i].Attributes;
715 
716             /* Copy the SID to the current destination address */
717             SidAndAttributes[i].Sid = (PSID)CurrentDest;
718             RtlCopyMemory(CurrentDest, SrcSidAndAttributes[i].Sid, SidLength);
719 
720             /* Update the current destination address */
721             CurrentDest += ALIGN_UP_BY(SidLength, sizeof(ULONG));
722         }
723     }
724 
725 Cleanup:
726     /* Check for failure */
727     if (!NT_SUCCESS(Status))
728     {
729         /* Check if we allocated a new array */
730         if ((SidAndAttributes != AllocatedMem) && (SidAndAttributes != NULL))
731         {
732             /* Free the array */
733             ExFreePoolWithTag(SidAndAttributes, TAG_SID_AND_ATTRIBUTES);
734         }
735 
736         /* Set returned address to NULL */
737         *CapturedSidAndAttributes = NULL;
738     }
739 
740     /* Free the temporary validation array */
741     if ((PreviousMode != KernelMode) && (ValidateArray != NULL))
742     {
743         ExFreePoolWithTag(ValidateArray, TAG_SID_VALIDATE);
744     }
745 
746     return Status;
747 }
748 
749 /**
750  * @brief
751  * Releases a captured SID with attributes.
752  *
753  * @param[in] CapturedSidAndAttributes
754  * The captured SID with attributes to be released.
755  *
756  * @param[in] AccessMode
757  * Processor access level mode.
758  *
759  * @param[in] CaptureIfKernel
760  * If set to TRUE, the releasing is done within the kernel.
761  * Otherwise the releasing is done in a kernel mode driver.
762  *
763  * @return
764  * Nothing.
765  */
766 VOID
767 NTAPI
768 SeReleaseSidAndAttributesArray(
769     _In_ _Post_invalid_ PSID_AND_ATTRIBUTES CapturedSidAndAttributes,
770     _In_ KPROCESSOR_MODE AccessMode,
771     _In_ BOOLEAN CaptureIfKernel)
772 {
773     PAGED_CODE();
774 
775     if ((CapturedSidAndAttributes != NULL) &&
776         ((AccessMode != KernelMode) || CaptureIfKernel))
777     {
778         ExFreePoolWithTag(CapturedSidAndAttributes, TAG_SID_AND_ATTRIBUTES);
779     }
780 }
781 
782 /* EOF */
783