1 /*
2  * PROJECT:     ReactOS API Tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Small library with probing utilities for thread/process classes information
5  * COPYRIGHT:   Copyright 2020 George Bișoc <george.bisoc@reactos.org>
6  */
7 
8 #include "precomp.h"
9 #include <internal/ps_i.h>
10 
11 VOID
12 QuerySetProcessValidator(
13     _In_ ALIGNMENT_PROBE_MODE ValidationMode,
14     _In_ ULONG InfoClassIndex,
15     _In_ PVOID InfoPointer,
16     _In_ ULONG InfoLength,
17     _In_ NTSTATUS ExpectedStatus)
18 {
19     NTSTATUS Status, SpecialStatus = STATUS_SUCCESS;
20 
21     /* Before doing anything, check if we want query or set validation */
22     switch (ValidationMode)
23     {
24         case QUERY:
25         {
26             switch (InfoClassIndex)
27             {
28                 case ProcessWorkingSetWatch:
29                 {
30                     SpecialStatus = STATUS_UNSUCCESSFUL;
31                     break;
32                 }
33 
34                 case ProcessHandleTracing:
35                 {
36                     SpecialStatus = STATUS_INVALID_PARAMETER;
37                     break;
38                 }
39 
40                 /*
41                  * This class returns an arbitrary size pointed by InformationLength
42                  * which equates to the image filename of the process. Such status
43                  * is returned in an invalid address query (STATUS_ACCESS_VIOLATION)
44                  * where the function expects STATUS_INFO_LENGTH_MISMATCH instead.
45                 */
46                 case ProcessImageFileName:
47                 {
48                     SpecialStatus = STATUS_INFO_LENGTH_MISMATCH;
49                     break;
50                 }
51 
52                 /* This one works different from the others */
53                 case ProcessUserModeIOPL:
54                 {
55                     if (ExpectedStatus == STATUS_INFO_LENGTH_MISMATCH)
56                     {
57                         SpecialStatus = STATUS_ACCESS_VIOLATION;
58                     }
59                     else
60                     {
61                         SpecialStatus = STATUS_INVALID_INFO_CLASS;
62                     }
63                     break;
64                 }
65 
66                 /* These classes don't belong in the query group */
67                 case ProcessBasePriority:
68                 case ProcessRaisePriority:
69                 case ProcessExceptionPort:
70                 case ProcessAccessToken:
71                 case ProcessLdtSize:
72                 case ProcessIoPortHandlers:
73                 case ProcessEnableAlignmentFaultFixup:
74                 case ProcessAffinityMask:
75                 case ProcessForegroundInformation:
76                 {
77                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
78                     break;
79                 }
80 
81                 /* These classes don't exist in Server 2003 */
82                 case ProcessIoPriority:
83                 case ProcessTlsInformation:
84                 case ProcessCycleTime:
85                 case ProcessPagePriority:
86                 case ProcessInstrumentationCallback:
87                 case ProcessThreadStackAllocation:
88                 case ProcessWorkingSetWatchEx:
89                 case ProcessImageFileNameWin32:
90                 case ProcessImageFileMapping:
91                 case ProcessAffinityUpdateMode:
92                 case ProcessMemoryAllocationMode:
93                 {
94                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
95                     break;
96                 }
97             }
98 
99             /* Query the information */
100             Status = NtQueryInformationProcess(NtCurrentProcess(),
101                                                InfoClassIndex,
102                                                InfoPointer,
103                                                InfoLength,
104                                                NULL);
105 
106             /* And probe the results we've got */
107             ok(Status == ExpectedStatus || Status == SpecialStatus || Status == STATUS_DATATYPE_MISALIGNMENT,
108                 "0x%lx or special status (0x%lx) expected but got 0x%lx for class information %lu in query information process operation!\n", ExpectedStatus, SpecialStatus, Status, InfoClassIndex);
109             break;
110         }
111 
112         case SET:
113         {
114             switch (InfoClassIndex)
115             {
116                 case ProcessIoPortHandlers:
117                 {
118                     SpecialStatus = STATUS_INVALID_PARAMETER;
119                     break;
120                 }
121 
122                 /*
123                  * This class returns STATUS_SUCCESS when testing
124                  * for STATUS_ACCESS_VIOLATION (setting an invalid address).
125                  */
126                 case ProcessWorkingSetWatch:
127                 {
128                     SpecialStatus = STATUS_PORT_ALREADY_SET;
129                     break;
130                 }
131 
132                 /* This one works different from the others */
133                 case ProcessUserModeIOPL:
134                 {
135                     if (ExpectedStatus == STATUS_INFO_LENGTH_MISMATCH)
136                     {
137                         SpecialStatus = STATUS_ACCESS_VIOLATION;
138                     }
139                     else
140                     {
141                         SpecialStatus = STATUS_PRIVILEGE_NOT_HELD;
142                     }
143                     break;
144                 }
145 
146                 /* These classes don't belong in the set group */
147                 case ProcessBasicInformation:
148                 case ProcessIoCounters:
149                 case ProcessVmCounters:
150                 case ProcessTimes:
151                 case ProcessDebugPort:
152                 case ProcessPooledUsageAndLimits:
153                 case ProcessHandleCount:
154                 case ProcessWow64Information:
155                 case ProcessImageFileName:
156                 case ProcessLUIDDeviceMapsEnabled:
157                 case ProcessDebugObjectHandle:
158                 case ProcessCookie:
159                 case ProcessImageInformation:
160                 {
161                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
162                     break;
163                 }
164 
165                 /* These classes don't exist in Server 2003 */
166                 case ProcessIoPriority:
167                 case ProcessTlsInformation:
168                 case ProcessCycleTime:
169                 case ProcessPagePriority:
170                 case ProcessInstrumentationCallback:
171                 case ProcessThreadStackAllocation:
172                 case ProcessWorkingSetWatchEx:
173                 case ProcessImageFileNameWin32:
174                 case ProcessImageFileMapping:
175                 case ProcessAffinityUpdateMode:
176                 case ProcessMemoryAllocationMode:
177                 {
178                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
179                     break;
180                 }
181 
182                 /* Alignment probing is not performed for these classes */
183                 case ProcessEnableAlignmentFaultFixup:
184                 case ProcessPriorityClass:
185                 case ProcessForegroundInformation:
186                 {
187                     SpecialStatus = STATUS_ACCESS_VIOLATION;
188                     break;
189                 }
190             }
191 
192             /* Set the information */
193             Status = NtSetInformationProcess(NtCurrentProcess(),
194                                              InfoClassIndex,
195                                              InfoPointer,
196                                              InfoLength);
197 
198             /* And probe the results we've got */
199             ok(Status == ExpectedStatus || Status == SpecialStatus || Status == STATUS_DATATYPE_MISALIGNMENT || Status == STATUS_SUCCESS,
200                 "0x%lx or special status (0x%lx) expected but got 0x%lx for class information %lu in set information process operation!\n", ExpectedStatus, SpecialStatus, Status, InfoClassIndex);
201             break;
202         }
203 
204         default:
205             break;
206     }
207 }
208 
209 VOID
210 QuerySetThreadValidator(
211     _In_ ALIGNMENT_PROBE_MODE ValidationMode,
212     _In_ ULONG InfoClassIndex,
213     _In_ PVOID InfoPointer,
214     _In_ ULONG InfoLength,
215     _In_ NTSTATUS ExpectedStatus)
216 {
217     NTSTATUS Status, SpecialStatus = STATUS_SUCCESS;
218 
219     /* Before doing anything, check if we want query or set validation */
220     switch (ValidationMode)
221     {
222         case QUERY:
223         {
224             switch (InfoClassIndex)
225             {
226                 /* These classes don't belong in the query group */
227                 case ThreadPriority:
228                 case ThreadBasePriority:
229                 case ThreadAffinityMask:
230                 case ThreadImpersonationToken:
231                 case ThreadEnableAlignmentFaultFixup:
232                 case ThreadZeroTlsCell:
233                 case ThreadIdealProcessor:
234                 case ThreadSetTlsArrayAddress:
235                 case ThreadHideFromDebugger:
236                 case ThreadSwitchLegacyState:
237                 {
238                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
239                     break;
240                 }
241 
242                 /* These classes don't exist in Server 2003 SP2 */
243                 case ThreadEventPair_Reusable:
244                 case ThreadLastSystemCall:
245                 case ThreadIoPriority:
246                 case ThreadCycleTime:
247                 case ThreadPagePriority:
248                 case ThreadActualBasePriority:
249                 case ThreadTebInformation:
250                 case ThreadCSwitchMon:
251                 {
252                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
253                     break;
254                 }
255             }
256 
257             /* Query the information */
258             Status = NtQueryInformationThread(NtCurrentThread(),
259                                               InfoClassIndex,
260                                               InfoPointer,
261                                               InfoLength,
262                                               NULL);
263 
264             /* And probe the results we've got */
265             ok(Status == ExpectedStatus || Status == SpecialStatus || Status == STATUS_DATATYPE_MISALIGNMENT,
266                 "0x%lx or special status (0x%lx) expected but got 0x%lx for class information %lu in query information thread operation!\n", ExpectedStatus, SpecialStatus, Status, InfoClassIndex);
267             break;
268         }
269 
270         case SET:
271         {
272             switch (InfoClassIndex)
273             {
274                 /* This class is not implemented in Windows Server 2003 SP2 */
275                 case ThreadSwitchLegacyState:
276                 {
277                     SpecialStatus = STATUS_NOT_IMPLEMENTED;
278                     break;
279                 }
280 
281                 /*
282                  * This class doesn't take a strict type for size length.
283                  * The function happily succeds on an information length
284                  * mismatch scenario with STATUS_SUCCESS.
285                  */
286                 case ThreadHideFromDebugger:
287                 {
288                     SpecialStatus = STATUS_INFO_LENGTH_MISMATCH;
289                     break;
290                 }
291 
292                 /* These classes don't belong in the set group */
293                 case ThreadBasicInformation:
294                 case ThreadTimes:
295                 case ThreadDescriptorTableEntry:
296                 case ThreadPerformanceCount:
297                 case ThreadAmILastThread:
298                 case ThreadIsIoPending:
299                 case ThreadIsTerminated:
300                 {
301                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
302                     break;
303                 }
304 
305                 /* These classes don't exist in Server 2003 SP2 */
306                 case ThreadEventPair_Reusable:
307                 case ThreadLastSystemCall:
308                 case ThreadIoPriority:
309                 case ThreadCycleTime:
310                 case ThreadPagePriority:
311                 case ThreadActualBasePriority:
312                 case ThreadTebInformation:
313                 case ThreadCSwitchMon:
314                 {
315                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
316                     break;
317                 }
318 
319                 /* Alignment probing is not performed for this class */
320                 case ThreadEnableAlignmentFaultFixup:
321                 {
322                     SpecialStatus = STATUS_ACCESS_VIOLATION;
323                     break;
324                 }
325             }
326 
327             /* Set the information */
328             Status = NtSetInformationThread(NtCurrentThread(),
329                                             InfoClassIndex,
330                                             InfoPointer,
331                                             InfoLength);
332 
333             /* And probe the results we've got */
334             ok(Status == ExpectedStatus || Status == SpecialStatus || Status == STATUS_DATATYPE_MISALIGNMENT || Status == STATUS_SUCCESS,
335                 "0x%lx or special status (0x%lx) expected but got 0x%lx for class information %lu in set information thread operation!\n", ExpectedStatus, SpecialStatus, Status, InfoClassIndex);
336         }
337 
338         default:
339             break;
340     }
341 }
342