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