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
TestsSeQueryInformationToken(PACCESS_TOKEN Token)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
START_TEST(SeQueryInfoToken)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