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                 /* These classes don't belong in the query group */
53                 case ProcessBasePriority:
54                 case ProcessRaisePriority:
55                 case ProcessExceptionPort:
56                 case ProcessAccessToken:
57                 case ProcessLdtSize:
58                 case ProcessIoPortHandlers:
59                 case ProcessUserModeIOPL:
60                 case ProcessEnableAlignmentFaultFixup:
61                 case ProcessAffinityMask:
62                 case ProcessForegroundInformation:
63                 {
64                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
65                     break;
66                 }
67 
68                 /* These classes don't exist in Server 2003 */
69                 case ProcessIoPriority:
70                 case ProcessTlsInformation:
71                 case ProcessCycleTime:
72                 case ProcessPagePriority:
73                 case ProcessInstrumentationCallback:
74                 case ProcessThreadStackAllocation:
75                 case ProcessWorkingSetWatchEx:
76                 case ProcessImageFileNameWin32:
77                 case ProcessImageFileMapping:
78                 case ProcessAffinityUpdateMode:
79                 case ProcessMemoryAllocationMode:
80                 {
81                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
82                     break;
83                 }
84             }
85 
86             /* Query the information */
87             Status = NtQueryInformationProcess(NtCurrentProcess(),
88                                                InfoClassIndex,
89                                                InfoPointer,
90                                                InfoLength,
91                                                NULL);
92 
93             /* And probe the results we've got */
94             ok(Status == ExpectedStatus || Status == SpecialStatus || Status == STATUS_DATATYPE_MISALIGNMENT,
95                 "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);
96             break;
97         }
98 
99         case SET:
100         {
101             switch (InfoClassIndex)
102             {
103                 case ProcessIoPortHandlers:
104                 {
105                     SpecialStatus = STATUS_INVALID_PARAMETER;
106                     break;
107                 }
108 
109                 /*
110                  * This class returns STATUS_SUCCESS when testing
111                  * for STATUS_ACCESS_VIOLATION (setting an invalid address).
112                  */
113                 case ProcessWorkingSetWatch:
114                 {
115                     SpecialStatus = STATUS_PORT_ALREADY_SET;
116                     break;
117                 }
118 
119                 case ProcessUserModeIOPL:
120                 {
121                     SpecialStatus = STATUS_PRIVILEGE_NOT_HELD;
122                     break;
123                 }
124 
125                 /* These classes don't belong in the set group */
126                 case ProcessBasicInformation:
127                 case ProcessIoCounters:
128                 case ProcessVmCounters:
129                 case ProcessTimes:
130                 case ProcessDebugPort:
131                 case ProcessPooledUsageAndLimits:
132                 case ProcessHandleCount:
133                 case ProcessWow64Information:
134                 case ProcessImageFileName:
135                 case ProcessLUIDDeviceMapsEnabled:
136                 case ProcessDebugObjectHandle:
137                 case ProcessCookie:
138                 case ProcessImageInformation:
139                 {
140                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
141                     break;
142                 }
143 
144                 /* These classes don't exist in Server 2003 */
145                 case ProcessIoPriority:
146                 case ProcessTlsInformation:
147                 case ProcessCycleTime:
148                 case ProcessPagePriority:
149                 case ProcessInstrumentationCallback:
150                 case ProcessThreadStackAllocation:
151                 case ProcessWorkingSetWatchEx:
152                 case ProcessImageFileNameWin32:
153                 case ProcessImageFileMapping:
154                 case ProcessAffinityUpdateMode:
155                 case ProcessMemoryAllocationMode:
156                 {
157                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
158                     break;
159                 }
160 
161                 /* Alignment probing is not performed for these classes */
162                 case ProcessEnableAlignmentFaultFixup:
163                 case ProcessPriorityClass:
164                 case ProcessForegroundInformation:
165                 {
166                     SpecialStatus = STATUS_ACCESS_VIOLATION;
167                     break;
168                 }
169             }
170 
171             /* Set the information */
172             Status = NtSetInformationProcess(NtCurrentProcess(),
173                                              InfoClassIndex,
174                                              InfoPointer,
175                                              InfoLength);
176 
177             /* And probe the results we've got */
178             ok(Status == ExpectedStatus || Status == SpecialStatus || Status == STATUS_DATATYPE_MISALIGNMENT || Status == STATUS_SUCCESS,
179                 "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);
180             break;
181         }
182 
183         default:
184             break;
185     }
186 }
187 
188 VOID
189 QuerySetThreadValidator(
190     _In_ ALIGNMENT_PROBE_MODE ValidationMode,
191     _In_ ULONG InfoClassIndex,
192     _In_ PVOID InfoPointer,
193     _In_ ULONG InfoLength,
194     _In_ NTSTATUS ExpectedStatus)
195 {
196     NTSTATUS Status, SpecialStatus = STATUS_SUCCESS;
197 
198     /* Before doing anything, check if we want query or set validation */
199     switch (ValidationMode)
200     {
201         case QUERY:
202         {
203             switch (InfoClassIndex)
204             {
205                 /* These classes don't belong in the query group */
206                 case ThreadPriority:
207                 case ThreadBasePriority:
208                 case ThreadAffinityMask:
209                 case ThreadImpersonationToken:
210                 case ThreadEnableAlignmentFaultFixup:
211                 case ThreadZeroTlsCell:
212                 case ThreadIdealProcessor:
213                 case ThreadSetTlsArrayAddress:
214                 case ThreadHideFromDebugger:
215                 case ThreadSwitchLegacyState:
216                 {
217                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
218                     break;
219                 }
220 
221                 /* These classes don't exist in Server 2003 SP2 */
222                 case ThreadEventPair_Reusable:
223                 case ThreadLastSystemCall:
224                 case ThreadIoPriority:
225                 case ThreadCycleTime:
226                 case ThreadPagePriority:
227                 case ThreadActualBasePriority:
228                 case ThreadTebInformation:
229                 case ThreadCSwitchMon:
230                 {
231                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
232                     break;
233                 }
234             }
235 
236             /* Query the information */
237             Status = NtQueryInformationThread(NtCurrentThread(),
238                                               InfoClassIndex,
239                                               InfoPointer,
240                                               InfoLength,
241                                               NULL);
242 
243             /* And probe the results we've got */
244             ok(Status == ExpectedStatus || Status == SpecialStatus || Status == STATUS_DATATYPE_MISALIGNMENT,
245                 "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);
246             break;
247         }
248 
249         case SET:
250         {
251             switch (InfoClassIndex)
252             {
253                 /* This class is not implemented in Windows Server 2003 SP2 */
254                 case ThreadSwitchLegacyState:
255                 {
256                     SpecialStatus = STATUS_NOT_IMPLEMENTED;
257                     break;
258                 }
259 
260                 /*
261                  * This class doesn't take a strict type for size length.
262                  * The function happily succeds on an information length
263                  * mismatch scenario with STATUS_SUCCESS.
264                  */
265                 case ThreadHideFromDebugger:
266                 {
267                     SpecialStatus = STATUS_INFO_LENGTH_MISMATCH;
268                     break;
269                 }
270 
271                 /* These classes don't belong in the set group */
272                 case ThreadBasicInformation:
273                 case ThreadTimes:
274                 case ThreadDescriptorTableEntry:
275                 case ThreadPerformanceCount:
276                 case ThreadAmILastThread:
277                 case ThreadIsIoPending:
278                 case ThreadIsTerminated:
279                 {
280                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
281                     break;
282                 }
283 
284                 /* These classes don't exist in Server 2003 SP2 */
285                 case ThreadEventPair_Reusable:
286                 case ThreadLastSystemCall:
287                 case ThreadIoPriority:
288                 case ThreadCycleTime:
289                 case ThreadPagePriority:
290                 case ThreadActualBasePriority:
291                 case ThreadTebInformation:
292                 case ThreadCSwitchMon:
293                 {
294                     SpecialStatus = STATUS_INVALID_INFO_CLASS;
295                     break;
296                 }
297 
298                 /* Alignment probing is not performed for this class */
299                 case ThreadEnableAlignmentFaultFixup:
300                 {
301                     SpecialStatus = STATUS_ACCESS_VIOLATION;
302                     break;
303                 }
304             }
305 
306             /* Set the information */
307             Status = NtSetInformationThread(NtCurrentThread(),
308                                             InfoClassIndex,
309                                             InfoPointer,
310                                             InfoLength);
311 
312             /* And probe the results we've got */
313             ok(Status == ExpectedStatus || Status == SpecialStatus || Status == STATUS_DATATYPE_MISALIGNMENT || Status == STATUS_SUCCESS,
314                 "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);
315         }
316 
317         default:
318             break;
319     }
320 }
321