1 /* 2 * PROJECT: ReactOS kernel-mode tests 3 * LICENSE: GPLv2+ - See COPYING in the top level directory 4 * PURPOSE: Kernel-Mode Test Suite Process Notification Routines test 5 * PROGRAMMER: Constantine Belev (Moscow State Technical University) 6 * Denis Grishin (Moscow State Technical University) 7 * Egor Sinitsyn (Moscow State Technical University) 8 */ 9 10 #include <kmt_test.h> 11 #include <ntifs.h> 12 13 #define NDEBUG 14 #include <debug.h> 15 16 // Copied from PspProcessMapping -- although the values don't matter much for 17 // the most part. 18 static GENERIC_MAPPING ProcessGenericMapping = 19 { 20 STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 21 STANDARD_RIGHTS_WRITE | PROCESS_CREATE_PROCESS | PROCESS_CREATE_THREAD | 22 PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_DUP_HANDLE | 23 PROCESS_TERMINATE | PROCESS_SET_QUOTA | PROCESS_SET_INFORMATION | 24 PROCESS_SUSPEND_RESUME, 25 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, 26 PROCESS_ALL_ACCESS 27 }; 28 29 //------------------------------------------------------------------------------// 30 // Testing Functions // 31 //------------------------------------------------------------------------------// 32 33 // Testing function for SQIT 34 35 void TestsSeQueryInformationToken(PACCESS_TOKEN Token) 36 { 37 NTSTATUS Status; 38 PVOID Buffer = NULL; 39 PSID sid; 40 PTOKEN_OWNER Towner; 41 PTOKEN_DEFAULT_DACL TDefDacl; 42 PTOKEN_GROUPS TGroups; 43 ULONG GroupCount; 44 PACL acl; 45 PTOKEN_STATISTICS TStats; 46 PTOKEN_TYPE TType; 47 PTOKEN_USER TUser; 48 BOOLEAN Flag; 49 ULONG i; 50 51 //----------------------------------------------------------------// 52 // Testing SeQueryInformationToken with various args // 53 //----------------------------------------------------------------// 54 55 ok(Token != NULL, "Token is not captured. Testing SQIT interrupted\n\n"); 56 57 if (Token == NULL) return; 58 59 Status = SeQueryInformationToken(Token, TokenOwner, &Buffer); 60 ok((Status == STATUS_SUCCESS), "SQIT with TokenOwner arg fails with status 0x%08X\n", Status); 61 if (Status == STATUS_SUCCESS) 62 { 63 ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenOwner arg. But Buffer == NULL\n"); 64 65 if (Buffer) 66 { 67 Towner = (TOKEN_OWNER *)Buffer; 68 sid = Towner->Owner; 69 ok((RtlValidSid(sid) == TRUE), "TokenOwner's SID is not a valid SID\n"); 70 ExFreePool(Buffer); 71 } 72 } 73 74 //----------------------------------------------------------------// 75 76 Buffer = NULL; 77 Status = SeQueryInformationToken(Token, TokenDefaultDacl, &Buffer); 78 ok(Status == STATUS_SUCCESS, "SQIT with TokenDefaultDacl fails with status 0x%08X\n", Status); 79 if (Status == STATUS_SUCCESS) 80 { 81 ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenDefaultDacl arg. But Buffer == NULL\n"); 82 if (Buffer) 83 { 84 TDefDacl = (PTOKEN_DEFAULT_DACL)Buffer; 85 acl = TDefDacl->DefaultDacl; 86 ok(((acl->AclRevision == ACL_REVISION || acl->AclRevision == ACL_REVISION_DS) == TRUE), "DACL is invalid\n"); 87 ExFreePool(Buffer); 88 } 89 } 90 91 //----------------------------------------------------------------// 92 93 Buffer = NULL; 94 Status = SeQueryInformationToken(Token, TokenGroups, &Buffer); 95 ok(Status == STATUS_SUCCESS, "SQIT with TokenGroups fails with status 0x%08X\n", Status); 96 if (Status == STATUS_SUCCESS) 97 { 98 ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenGroups arg. But Buffer == NULL\n"); 99 if (Buffer) 100 { 101 TGroups = (PTOKEN_GROUPS)Buffer; 102 GroupCount = TGroups->GroupCount; 103 Flag = TRUE; 104 for (i = 0; i < GroupCount; i++) 105 { 106 sid = TGroups->Groups[i].Sid; 107 if (!RtlValidSid(sid)) 108 { 109 Flag = FALSE; 110 break; 111 } 112 } 113 ok((Flag == TRUE), "TokenGroup's SIDs are not valid\n"); 114 ExFreePool(Buffer); 115 } 116 } 117 118 //----------------------------------------------------------------// 119 120 // Call SQIT with TokenImpersonationLevel argument. Although our token 121 // is not an impersonation token, the call will outright fail. 122 123 Buffer = NULL; 124 Status = SeQueryInformationToken(Token, TokenImpersonationLevel, &Buffer); 125 ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenImpersonationLevel must return STATUS_INVALID_INFO_CLASS but got 0x%08X\n", Status); 126 ok(Buffer == NULL, "SQIT has failed to query the impersonation level but buffer is not NULL!\n"); 127 128 //----------------------------------------------------------------// 129 130 // Call SQIT with the 4 classes (TokenOrigin, TokenGroupsAndPrivileges, 131 // TokenRestrictedSids and TokenSandBoxInert) are not supported by 132 // SeQueryInformationToken (only NtQueryInformationToken supports them). 133 // 134 135 Buffer = NULL; 136 Status = SeQueryInformationToken(Token, TokenOrigin, &Buffer); 137 ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenOrigin failed with Status 0x%08X; expected STATUS_INVALID_INFO_CLASS\n", Status); 138 ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n"); 139 140 Buffer = NULL; 141 Status = SeQueryInformationToken(Token, TokenGroupsAndPrivileges, &Buffer); 142 ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenGroupsAndPrivileges failed with Status 0x%08X; expected STATUS_INVALID_INFO_CLASS\n", Status); 143 ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n"); 144 145 Buffer = NULL; 146 Status = SeQueryInformationToken(Token, TokenRestrictedSids, &Buffer); 147 ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenRestrictedSids failed with Status 0x%08X; expected STATUS_INVALID_INFO_CLASS\n", Status); 148 ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n"); 149 150 Buffer = NULL; 151 Status = SeQueryInformationToken(Token, TokenSandBoxInert, &Buffer); 152 ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenSandBoxInert failed with Status 0x%08X; expected STATUS_INVALID_INFO_CLASS\n", Status); 153 ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n"); 154 155 //----------------------------------------------------------------// 156 157 Buffer = NULL; 158 Status = SeQueryInformationToken(Token, TokenStatistics, &Buffer); 159 ok(Status == STATUS_SUCCESS, "SQIT with TokenStatistics fails with status 0x%08X\n", Status); 160 if (Status == STATUS_SUCCESS) 161 { 162 ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenStatistics arg. But Buffer == NULL\n"); 163 if (Buffer) 164 { 165 TStats = (PTOKEN_STATISTICS)Buffer; 166 // just put 0 into 1st arg or use trace to print TokenStatistics 167 ok(1, "print statistics:\n\tTokenID = %u_%d\n\tSecurityImperLevel = %d\n\tPrivCount = %d\n\tGroupCount = %d\n\n", TStats->TokenId.LowPart, 168 TStats->TokenId.HighPart, 169 TStats->ImpersonationLevel, 170 TStats->PrivilegeCount, 171 TStats->GroupCount 172 ); 173 ExFreePool(Buffer); 174 } 175 } else { 176 ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n"); 177 } 178 179 //----------------------------------------------------------------// 180 181 Buffer = NULL; 182 Status = SeQueryInformationToken(Token, TokenType, &Buffer); 183 ok(Status == STATUS_SUCCESS, "SQIT with TokenType fails with status 0x%08X\n", Status); 184 if (Status == STATUS_SUCCESS) 185 { 186 ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenType arg. But Buffer == NULL\n"); 187 if (Buffer) 188 { 189 TType = (PTOKEN_TYPE)Buffer; 190 ok((*TType == TokenPrimary || *TType == TokenImpersonation), "TokenType in not a primary nor impersonation. FAILED\n"); 191 ExFreePool(Buffer); 192 } 193 } 194 195 //----------------------------------------------------------------// 196 197 Buffer = NULL; 198 Status = SeQueryInformationToken(Token, TokenUser, &Buffer); 199 ok(Status == STATUS_SUCCESS, "SQIT with TokenUser fails\n"); 200 if (Status == STATUS_SUCCESS) 201 { 202 ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenUser arg. But Buffer == NULL\n"); 203 if (Buffer) 204 { 205 TUser = (PTOKEN_USER)Buffer; 206 ok(RtlValidSid(TUser->User.Sid), "TokenUser has an invalid Sid\n"); 207 ExFreePool(Buffer); 208 } 209 } 210 211 //----------------------------------------------------------------// 212 213 Buffer = NULL; 214 Status = SeQueryInformationToken(Token, TokenSandBoxInert, &Buffer); 215 ok(Status != STATUS_SUCCESS, "SQIT must fail with wrong TOKEN_INFORMATION_CLASS arg\n"); 216 } 217 218 //------------------------------------------------------------------------------// 219 220 //------------------------------------------------------------------------------// 221 // Body of the main test // 222 //------------------------------------------------------------------------------// 223 224 START_TEST(SeQueryInfoToken) 225 { 226 PACCESS_STATE AccessState; 227 ACCESS_MASK AccessMask = MAXIMUM_ALLOWED; 228 ACCESS_MASK DesiredAccess = MAXIMUM_ALLOWED; 229 NTSTATUS Status = STATUS_SUCCESS; 230 PAUX_ACCESS_DATA AuxData = NULL; 231 PPRIVILEGE_SET NewPrivilegeSet; 232 ULONG InitialPrivilegeCount; 233 BOOLEAN Checker; 234 PPRIVILEGE_SET Privileges = NULL; 235 PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL; 236 PACCESS_TOKEN Token = NULL; 237 PTOKEN_PRIVILEGES TPrivileges; 238 PVOID Buffer; 239 ULONG i; 240 241 SubjectContext = ExAllocatePool(PagedPool, sizeof(SECURITY_SUBJECT_CONTEXT)); 242 243 SeCaptureSubjectContext(SubjectContext); 244 SeLockSubjectContext(SubjectContext); 245 Token = SeQuerySubjectContextToken(SubjectContext); 246 247 // Testing SQIT with current Token 248 TestsSeQueryInformationToken(Token); 249 250 //----------------------------------------------------------------// 251 // Creating an ACCESS_STATE structure // 252 //----------------------------------------------------------------// 253 254 AccessState = ExAllocatePool(PagedPool, sizeof(ACCESS_STATE)); 255 // AUX_ACCESS_DATA gets larger in newer Windows version. 256 // This is the largest known size, found in Windows 10/11. 257 AuxData = ExAllocatePoolZero(PagedPool, 0xE0, 'QSmK'); 258 259 Status = SeCreateAccessState(AccessState, 260 AuxData, 261 DesiredAccess, 262 &ProcessGenericMapping 263 ); 264 265 ok((Status == STATUS_SUCCESS), "SeCreateAccessState failed with Status 0x%08X\n", Status); 266 267 SeCaptureSubjectContext(&AccessState->SubjectSecurityContext); 268 SeLockSubjectContext(&AccessState->SubjectSecurityContext); 269 Token = SeQuerySubjectContextToken(&AccessState->SubjectSecurityContext); 270 271 // Testing SQIT with AccessState Token 272 TestsSeQueryInformationToken(Token); 273 274 //----------------------------------------------------------------// 275 // Testing other functions // 276 //----------------------------------------------------------------// 277 278 //----------------------------------------------------------------// 279 // Testing SeAppendPrivileges // 280 //----------------------------------------------------------------// 281 282 InitialPrivilegeCount = AuxData->PrivilegesUsed->PrivilegeCount; 283 trace("Initial privilege count = %lu\n", InitialPrivilegeCount); 284 285 // Testing SeAppendPrivileges. Must change PrivilegeCount to 2 (1 + 1) 286 287 NewPrivilegeSet = ExAllocatePoolZero(PagedPool, 288 FIELD_OFFSET(PRIVILEGE_SET, Privilege[1]), 289 'QSmK'); 290 NewPrivilegeSet->PrivilegeCount = 1; 291 292 Status = SeAppendPrivileges(AccessState, NewPrivilegeSet); 293 ok(Status == STATUS_SUCCESS, "SeAppendPrivileges failed\n"); 294 ok_eq_ulong(AuxData->PrivilegesUsed->PrivilegeCount, InitialPrivilegeCount + 1); 295 ExFreePoolWithTag(NewPrivilegeSet, 'QSmK'); 296 297 //----------------------------------------------------------------// 298 299 // Testing SeAppendPrivileges. Must change PrivilegeCount to 6 (2 + 4) 300 301 NewPrivilegeSet = ExAllocatePoolZero(PagedPool, 302 FIELD_OFFSET(PRIVILEGE_SET, Privilege[4]), 303 'QSmK'); 304 NewPrivilegeSet->PrivilegeCount = 4; 305 306 Status = SeAppendPrivileges(AccessState, NewPrivilegeSet); 307 ok(Status == STATUS_SUCCESS, "SeAppendPrivileges failed\n"); 308 ok_eq_ulong(AuxData->PrivilegesUsed->PrivilegeCount, InitialPrivilegeCount + 5); 309 ExFreePoolWithTag(NewPrivilegeSet, 'QSmK'); 310 311 //----------------------------------------------------------------// 312 // Testing SePrivilegeCheck // 313 //----------------------------------------------------------------// 314 315 // KPROCESSOR_MODE is set to KernelMode ===> Always return TRUE 316 ok(SePrivilegeCheck(AuxData->PrivilegesUsed, &(AccessState->SubjectSecurityContext), KernelMode), "SePrivilegeCheck failed with KernelMode mode arg\n"); 317 // and call it again 318 ok(SePrivilegeCheck(AuxData->PrivilegesUsed, &(AccessState->SubjectSecurityContext), KernelMode), "SePrivilegeCheck failed with KernelMode mode arg\n"); 319 320 //----------------------------------------------------------------// 321 322 // KPROCESSOR_MODE is set to UserMode. Expect false 323 ok(!SePrivilegeCheck(AuxData->PrivilegesUsed, &(AccessState->SubjectSecurityContext), UserMode), "SePrivilegeCheck unexpected success with UserMode arg\n"); 324 325 //----------------------------------------------------------------// 326 327 //----------------------------------------------------------------// 328 // Testing SeFreePrivileges // 329 //----------------------------------------------------------------// 330 331 // FIXME: KernelMode will automatically get all access granted without 332 // getting Privileges filled in. For UserMode, Privileges will only get 333 // filled if either WRITE_OWNER or ACCESS_SYSTEM_SECURITY is requested 334 // and granted. So this doesn't really test SeFreePrivileges. 335 Privileges = NULL; 336 Checker = SeAccessCheck( 337 AccessState->SecurityDescriptor, 338 &AccessState->SubjectSecurityContext, 339 FALSE, 340 AccessState->OriginalDesiredAccess, 341 AccessState->PreviouslyGrantedAccess, 342 &Privileges, 343 &ProcessGenericMapping, 344 KernelMode, 345 &AccessMask, 346 &Status 347 ); 348 ok(Checker, "Checker is NULL\n"); 349 ok(Privileges == NULL, "Privileges is not NULL\n"); 350 if (Privileges) 351 { 352 trace("AuxData->PrivilegesUsed->PrivilegeCount = %d ; Privileges->PrivilegeCount = %d\n", 353 AuxData->PrivilegesUsed->PrivilegeCount, Privileges->PrivilegeCount); 354 } 355 if (Privileges) SeFreePrivileges(Privileges); 356 357 358 //----------------------------------------------------------------// 359 // Testing SePrivilegeCheck // 360 //----------------------------------------------------------------// 361 // I'm trying to make success call of SePrivilegeCheck from UserMode 362 // If we sets Privileges properly, can we expect true from SePrivilegeCheck? 363 // answer: yes 364 // This test demonstrates it 365 366 Buffer = NULL; 367 Status = SeQueryInformationToken(Token, TokenPrivileges, &Buffer); 368 if (Status == STATUS_SUCCESS) 369 { 370 ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenPrivileges arg. But Buffer == NULL\n"); 371 if (Buffer) 372 { 373 TPrivileges = (PTOKEN_PRIVILEGES)(Buffer); 374 //trace("TPCount = %u\n\n", TPrivileges->PrivilegeCount); 375 376 NewPrivilegeSet = ExAllocatePoolZero(PagedPool, 377 FIELD_OFFSET(PRIVILEGE_SET, Privilege[14]), 378 'QSmK'); 379 NewPrivilegeSet->PrivilegeCount = 14; 380 381 ok((SeAppendPrivileges(AccessState, NewPrivilegeSet)) == STATUS_SUCCESS, "SeAppendPrivileges failed\n"); 382 ok_eq_ulong(AuxData->PrivilegesUsed->PrivilegeCount, InitialPrivilegeCount + 19); 383 ExFreePoolWithTag(NewPrivilegeSet, 'QSmK'); 384 for (i = 0; i < AuxData->PrivilegesUsed->PrivilegeCount; i++) 385 { 386 AuxData->PrivilegesUsed->Privilege[i].Attributes = TPrivileges->Privileges[i].Attributes; 387 AuxData->PrivilegesUsed->Privilege[i].Luid = TPrivileges->Privileges[i].Luid; 388 } 389 //trace("AccessState->privCount = %u\n\n", ((PAUX_ACCESS_DATA)(AccessState->AuxData))->PrivilegesUsed->PrivilegeCount); 390 391 ok(SePrivilegeCheck(AuxData->PrivilegesUsed, &(AccessState->SubjectSecurityContext), UserMode), "SePrivilegeCheck fails in UserMode, but I wish it will success\n"); 392 } 393 } 394 395 // Call SeFreePrivileges again 396 397 // FIXME: See other SeAccessCheck call above, we're not really testing 398 // SeFreePrivileges here. 399 Privileges = NULL; 400 Checker = SeAccessCheck( 401 AccessState->SecurityDescriptor, 402 &AccessState->SubjectSecurityContext, 403 TRUE, 404 AccessState->OriginalDesiredAccess, 405 AccessState->PreviouslyGrantedAccess, 406 &Privileges, 407 &ProcessGenericMapping, 408 KernelMode, 409 &AccessMask, 410 &Status 411 ); 412 ok(Checker, "Checker is NULL\n"); 413 ok(Privileges == NULL, "Privileges is not NULL\n"); 414 if (Privileges) 415 { 416 trace("AuxData->PrivilegesUsed->PrivilegeCount = %d ; Privileges->PrivilegeCount = %d\n", 417 AuxData->PrivilegesUsed->PrivilegeCount, Privileges->PrivilegeCount); 418 } 419 if (Privileges) SeFreePrivileges(Privileges); 420 421 //----------------------------------------------------------------// 422 // Missing for now // 423 //----------------------------------------------------------------// 424 425 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext); 426 SeUnlockSubjectContext(SubjectContext); 427 428 SeDeleteAccessState(AccessState); 429 430 if (SubjectContext) ExFreePool(SubjectContext); 431 if (AuxData) ExFreePoolWithTag(AuxData, 'QSmK'); 432 if (AccessState) ExFreePool(AccessState); 433 } 434