ReactOS 0.4.16-dev-1028-g8602629
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);
179 ok_hex(Status, (sizeof(PVOID) == 8) ? STATUS_BUFFER_TOO_SMALL :
182
184 NULL,
185 (PVOID)(ULONG_PTR)0x10000,
186 SIZE_MAX,
187 31,
188 NULL,
189 0x80000000,
191 1);
192 ok_hex(Status, (sizeof(PVOID) == 8) ? STATUS_BUFFER_TOO_SMALL :
195 }
196
197 /* Handle is probed first and requires no alignment, buffer requires ULONG alignment */
198 {
199 ULONG Buffer[1];
200
202 (HANDLE)(ULONG_PTR)1,
203 (PVOID)(ULONG_PTR)0x10002,
204 0x1000,
205 31,
206 (PVOID)(ULONG_PTR)2,
207 sizeof(ULONG),
209 1);
211
212 Status = NtCreateProfile(&ProfileHandle,
213 (HANDLE)(ULONG_PTR)1,
214 (PVOID)(ULONG_PTR)0x10000,
215 0x1000,
216 31,
217 (PVOID)(ULONG_PTR)2,
218 sizeof(ULONG),
220 1);
222
223 Status = NtCreateProfile(&ProfileHandle,
224 (HANDLE)(ULONG_PTR)1,
225 (PVOID)(ULONG_PTR)0x10000,
226 0x1000,
227 31,
228 (PVOID)(ULONG_PTR)4,
229 sizeof(ULONG),
231 1);
233
234 Status = NtCreateProfile(&ProfileHandle,
235 (HANDLE)(ULONG_PTR)1,
236 (PVOID)(ULONG_PTR)0x10000,
237 0x1000,
238 31,
239 Buffer,
240 sizeof(ULONG),
242 1);
244 }
245}
246
247/* There are bugs in this validation all the way through early Win10.
248 * Therefore we test this more thoroughly.
249 * See https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/profile/bugdemo.htm
250 */
251static
252void
254{
255 static const struct
256 {
257 INT Line;
258 SIZE_T RangeSize;
259 ULONG BucketSize;
261 NTSTATUS ExpectedStatus;
262 NTSTATUS BrokenStatus;
263 } Tests[] =
264 {
265 /* RangeSize=(1 << BucketSize) means we'll need exactly one ULONG */
266 { __LINE__, 0x4, 2, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
267 { __LINE__, 0x4, 2, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
268 { __LINE__, 0x8, 3, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
269 { __LINE__, 0x8, 3, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
270 { __LINE__, 0x400, 10, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
271 { __LINE__, 0x400, 10, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
272 { __LINE__, 0x40000000, 30, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
273 { __LINE__, 0x40000000, 30, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
274 { __LINE__, 0x80000000, 31, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL },
275 { __LINE__, 0x80000000, 31, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
276
277 /* RangeSize<(1 << BucketSize) also means we'll need one ULONG.
278 * However, old Windows versions get this wrong.
279 */
280 { __LINE__, 3, 2, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
281 { __LINE__, 3, 2, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
282 { __LINE__, 1, 2, sizeof(ULONG) - 1, STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
283
284 /* Various sizes to show that the bug allows buffers that are a quarter of a bucket too big. */
285 { __LINE__, 8, 3, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
286 { __LINE__, 9, 3, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
287 { __LINE__, 10, 3, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
288
289 { __LINE__, 16, 4, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
290 { __LINE__, 17, 4, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
291 { __LINE__, 18, 4, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
292 { __LINE__, 19, 4, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
293 { __LINE__, 20, 4, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
294
295 { __LINE__, 32, 5, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
296 { __LINE__, 33, 5, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
297 { __LINE__, 39, 5, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
298 { __LINE__, 40, 5, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
299
300 { __LINE__, 256, 8, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
301 { __LINE__, 257, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
302 { __LINE__, 319, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
303 { __LINE__, 320, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
304
305 { __LINE__, 256, 8, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
306 { __LINE__, 257, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
307 { __LINE__, 319, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
308 { __LINE__, 320, 8, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
309
310 { __LINE__, 0x80000000, 31, sizeof(ULONG), STATUS_ACCESS_VIOLATION },
311 { __LINE__, 0x80000001, 31, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
312 { __LINE__, 0xBFFFFFFF, 31, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL, STATUS_ACCESS_VIOLATION },
313 { __LINE__, 0xA0000000, 31, sizeof(ULONG), STATUS_BUFFER_TOO_SMALL },
314
315 /* Nothing checks against the max MDL size */
316 { __LINE__, 3, 2, MAX_MDL_BUFFER_SIZE, STATUS_ACCESS_VIOLATION },
317 { __LINE__, 3, 2, MAX_MDL_BUFFER_SIZE + 1, STATUS_ACCESS_VIOLATION },
318 { __LINE__, 3, 2, (MAX_MDL_BUFFER_SIZE + 1) * 2, STATUS_ACCESS_VIOLATION },
319
320 };
322 ULONG i;
323
324 for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
325 {
327 NULL,
328 (PVOID)(ULONG_PTR)0x10000,
329 Tests[i].RangeSize,
330 Tests[i].BucketSize,
331 NULL,
334 1);
335 if (Tests[i].BrokenStatus)
336 {
337 ok(Status == Tests[i].ExpectedStatus ||
338 broken(Status == Tests[i].BrokenStatus),
339 "[L%d] For RangeSize 0x%Ix, BucketSize %lu, BufferSize %lu, expected 0x%lx, got 0x%lx\n",
340 Tests[i].Line, Tests[i].RangeSize, Tests[i].BucketSize, Tests[i].BufferSize, Tests[i].ExpectedStatus, Status);
341 }
342 else
343 {
344 ok(Status == Tests[i].ExpectedStatus,
345 "[L%d] For RangeSize 0x%Ix, BucketSize %lu, BufferSize %lu, expected 0x%lx, got 0x%lx\n",
346 Tests[i].Line, Tests[i].RangeSize, Tests[i].BucketSize, Tests[i].BufferSize, Tests[i].ExpectedStatus, Status);
347 }
348 }
349}
350
352{
356}
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