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