ReactOS 0.4.16-dev-927-g467dec4
NtCreateProfile.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS API Tests
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Test for NtCreateProfile
5 * COPYRIGHT: Copyright 2021 Thomas Faber (thomas.faber@reactos.org)
6 */
7
8#include "precomp.h"
9
10#define SIZEOF_MDL (5 * sizeof(PVOID) + 2 * sizeof(ULONG))
12/* Maximum size that can be described by an MDL on 2003 and earlier */
13#define MAX_MDL_BUFFER_SIZE ((MAXUSHORT - SIZEOF_MDL) / sizeof(PFN_NUMBER) * PAGE_SIZE + PAGE_SIZE - 1)
14
15#define broken(cond) (strcmp(winetest_platform, "windows") ? 0 : cond)
16
18
19static
20void
22{
24 HANDLE ProfileHandle;
25
27 NULL,
28 NULL,
29 0,
30 0,
31 NULL,
32 0,
34 1);
36
37 /* For addresses below 0x10000, there's a special check for BufferSize<4 -- on x86 only */
38 {
40 NULL,
41 (PVOID)(ULONG_PTR)0xFFFF,
42 0,
43 0,
44 NULL,
45 3,
47 1);
48 if (sizeof(PVOID) > sizeof(ULONG) || IsWow64)
49 {
51 }
52 else
53 {
55 }
56
57 /* Increasing the pointer gets us past this */
59 NULL,
60 (PVOID)(ULONG_PTR)0x10000,
61 0,
62 0,
63 NULL,
64 3,
66 1);
68
69 /* So does increasing the size */
71 NULL,
72 (PVOID)(ULONG_PTR)0xFFFF,
73 0,
74 0,
75 NULL,
76 4,
78 1);
80
81 /* ... or, specifying a bucket size */
83 NULL,
84 (PVOID)(ULONG_PTR)0xFFFF,
85 0,
86 1,
87 NULL,
88 4,
90 1);
92 }
93
94 /* Bucket sizes less than two or larger than 31 are invalid */
95 {
97 NULL,
98 (PVOID)(ULONG_PTR)0x10000,
99 0x80000000,
100 1,
101 NULL,
102 1,
104 1);
106
108 NULL,
109 (PVOID)(ULONG_PTR)0x10000,
110 0x80000000,
111 32,
112 NULL,
113 1,
115 1);
117
118 /* But 2 and 31 are valid */
120 NULL,
121 (PVOID)(ULONG_PTR)0x10000,
122 0x80000000,
123 2,
124 NULL,
125 1,
127 1);
129
131 NULL,
132 (PVOID)(ULONG_PTR)0x10000,
133 0x80000000,
134 31,
135 NULL,
136 1,
138 1);
140 }
141
142 /* RangeSize validation has its own function */
143
144 /* RangeBase+RangeSize can overflow into kernel space, but can't wrap around.
145 * Note that a Wow64 test will never achieve overflow.
146 */
147 {
149 NULL,
150 (PVOID)(ULONG_PTR)0x10000,
151 SIZE_MAX / 2,
152 31,
153 NULL,
154 0x80000000,
156 1);
158
160 NULL,
161 (PVOID)(ULONG_PTR)0x10000,
162 SIZE_MAX - 0x10000,
163 31,
164 NULL,
165 0x80000000,
167 1);
169
171 NULL,
172 (PVOID)(ULONG_PTR)0x10000,
173 SIZE_MAX - 0x10000 + 1,
174 31,
175 NULL,
176 0x80000000,
178 1);
180
182 NULL,
183 (PVOID)(ULONG_PTR)0x10000,
184 SIZE_MAX,
185 31,
186 NULL,
187 0x80000000,
189 1);
191 }
192
193 /* Handle is probed first and requires no alignment, buffer requires ULONG alignment */
194 {
195 ULONG Buffer[1];
196
198 (HANDLE)(ULONG_PTR)1,
199 (PVOID)(ULONG_PTR)0x10002,
200 0x1000,
201 31,
202 (PVOID)(ULONG_PTR)2,
203 sizeof(ULONG),
205 1);
207
208 Status = NtCreateProfile(&ProfileHandle,
209 (HANDLE)(ULONG_PTR)1,
210 (PVOID)(ULONG_PTR)0x10000,
211 0x1000,
212 31,
213 (PVOID)(ULONG_PTR)2,
214 sizeof(ULONG),
216 1);
218
219 Status = NtCreateProfile(&ProfileHandle,
220 (HANDLE)(ULONG_PTR)1,
221 (PVOID)(ULONG_PTR)0x10000,
222 0x1000,
223 31,
224 (PVOID)(ULONG_PTR)4,
225 sizeof(ULONG),
227 1);
229
230 Status = NtCreateProfile(&ProfileHandle,
231 (HANDLE)(ULONG_PTR)1,
232 (PVOID)(ULONG_PTR)0x10000,
233 0x1000,
234 31,
235 Buffer,
236 sizeof(ULONG),
238 1);
240 }
241}
242
243/* There are bugs in this validation all the way through early Win10.
244 * Therefore we test this more thoroughly.
245 * See https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/profile/bugdemo.htm
246 */
247static
248void
250{
251 static const struct
252 {
253 INT Line;
254 SIZE_T RangeSize;
255 ULONG BucketSize;
257 NTSTATUS ExpectedStatus;
258 NTSTATUS BrokenStatus;
259 } Tests[] =
260 {
261 /* RangeSize=(1 << BucketSize) means we'll need exactly one ULONG */
262 { __LINE__, 0x4, 2, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
263 { __LINE__, 0x4, 2, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
264 { __LINE__, 0x8, 3, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
265 { __LINE__, 0x8, 3, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
266 { __LINE__, 0x400, 10, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
267 { __LINE__, 0x400, 10, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
268 { __LINE__, 0x40000000, 30, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
269 { __LINE__, 0x40000000, 30, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
270 { __LINE__, 0x80000000, 31, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
271 { __LINE__, 0x80000000, 31, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
272
273 /* RangeSize<(1 << BucketSize) also means we'll need one ULONG.
274 * However, old Windows versions get this wrong.
275 */
276 { __LINE__, 3, 2, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
277 { __LINE__, 3, 2, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
278 { __LINE__, 1, 2, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
279
280 /* Various sizes to show that the bug allows buffers that are a quarter of a bucket too big. */
281 { __LINE__, 8, 3, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
282 { __LINE__, 9, 3, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
283 { __LINE__, 10, 3, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
284
285 { __LINE__, 16, 4, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
286 { __LINE__, 17, 4, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
287 { __LINE__, 18, 4, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
288 { __LINE__, 19, 4, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
289 { __LINE__, 20, 4, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
290
291 { __LINE__, 32, 5, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
292 { __LINE__, 33, 5, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
293 { __LINE__, 39, 5, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
294 { __LINE__, 40, 5, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
295
296 { __LINE__, 256, 8, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
297 { __LINE__, 257, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
298 { __LINE__, 319, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
299 { __LINE__, 320, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
300
301 { __LINE__, 256, 8, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
302 { __LINE__, 257, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
303 { __LINE__, 319, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
304 { __LINE__, 320, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
305
306 { __LINE__, 0x80000000, 31, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
307 { __LINE__, 0x80000001, 31, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
308 { __LINE__, 0xBFFFFFFF, 31, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
309 { __LINE__, 0xA0000000, 31, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
310
311 /* Nothing checks against the max MDL size */
312 { __LINE__, 3, 2, MAX_MDL_BUFFER_SIZE, STATUS_ACCESS_VIOLATION },
313 { __LINE__, 3, 2, MAX_MDL_BUFFER_SIZE + 1, STATUS_ACCESS_VIOLATION },
314 { __LINE__, 3, 2, (MAX_MDL_BUFFER_SIZE + 1) * 2, STATUS_ACCESS_VIOLATION },
315
316 };
318 ULONG i;
319
320 for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
321 {
323 NULL,
324 (PVOID)(ULONG_PTR)0x10000,
325 Tests[i].RangeSize,
326 Tests[i].BucketSize,
327 NULL,
330 1);
331 if (Tests[i].BrokenStatus)
332 {
333 ok(Status == Tests[i].ExpectedStatus ||
334 broken(Status == Tests[i].BrokenStatus),
335 "[L%d] For RangeSize 0x%Ix, BucketSize %lu, BufferSize %lu, expected 0x%lx, got 0x%lx\n",
336 Tests[i].Line, Tests[i].RangeSize, Tests[i].BucketSize, Tests[i].BufferSize, Tests[i].ExpectedStatus, Status);
337 }
338 else
339 {
340 ok(Status == Tests[i].ExpectedStatus,
341 "[L%d] For RangeSize 0x%Ix, BucketSize %lu, BufferSize %lu, expected 0x%lx, got 0x%lx\n",
342 Tests[i].Line, Tests[i].RangeSize, Tests[i].BucketSize, Tests[i].BufferSize, Tests[i].ExpectedStatus, Status);
343 }
344 }
345}
346
348{
352}
static void TestParameterValidation(void)
#define MAX_MDL_BUFFER_SIZE
#define broken(cond)
static BOOL IsWow64
static void TestBufferSizeValidation(void)
ULONG_PTR PFN_NUMBER
struct test_data Tests[]
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
#define ok_hex(expression, result)
Definition: atltest.h:94
#define ok(value,...)
Definition: atltest.h:57
#define START_TEST(x)
Definition: atltest.h:75
LONG NTSTATUS
Definition: precomp.h:26
Definition: bufpool.h:45
#define STATUS_INVALID_HANDLE
Definition: d3dkmdt.h:40
#define BufferSize
Definition: mmc.h:75
#define NULL
Definition: types.h:112
#define GetCurrentProcess()
Definition: compat.h:759
#define IsWow64Process
Definition: compat.h:760
unsigned int BOOL
Definition: ntddk_ex.h:94
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
@ ProfileTime
Definition: winternl.h:2123
NTSTATUS NTAPI NtCreateProfile(OUT PHANDLE ProfileHandle, IN HANDLE Process OPTIONAL, IN PVOID RangeBase, IN SIZE_T RangeSize, IN ULONG BucketSize, IN PVOID Buffer, IN ULONG BufferSize, IN KPROFILE_SOURCE ProfileSource, IN KAFFINITY Affinity)
Definition: profile.c:89
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
#define STATUS_INVALID_PARAMETER_7
Definition: ntstatus.h:481
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
#define STATUS_DATATYPE_MISALIGNMENT
Definition: ntstatus.h:183
#define SIZE_MAX
Definition: compat.h:66
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
Definition: ncftp.h:79
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254