1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test for Zw*SymbolicLinkObject
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 static
14 VOID
15 TestQueryLink(
16     _In_ HANDLE LinkHandle,
17     _In_ PCUNICODE_STRING ExpectedTarget)
18 {
19     NTSTATUS Status;
20     WCHAR QueriedTargetBuffer[32];
21     UNICODE_STRING QueriedTarget;
22     ULONG ResultLength;
23     PULONG pResultLength;
24     ULONG i;
25 
26     for (i = 0; i < 2; i++)
27     {
28         if (i == 0)
29         {
30             pResultLength = &ResultLength;
31         }
32         else
33         {
34             pResultLength = NULL;
35         }
36 
37         /* Query with NULL Buffer just gives us the length */
38         RtlInitEmptyUnicodeString(&QueriedTarget, NULL, 0);
39         if (pResultLength) ResultLength = 0x55555555;
40         Status = ZwQuerySymbolicLinkObject(LinkHandle,
41                                            &QueriedTarget,
42                                            pResultLength);
43         ok_eq_hex(Status, STATUS_BUFFER_TOO_SMALL);
44         ok_eq_uint(QueriedTarget.Length, 0);
45         ok_eq_uint(QueriedTarget.MaximumLength, 0);
46         ok_eq_pointer(QueriedTarget.Buffer, NULL);
47         if (pResultLength) ok_eq_ulong(ResultLength, ExpectedTarget->MaximumLength);
48 
49         /* Query with Length-1 buffer */
50         RtlInitEmptyUnicodeString(&QueriedTarget,
51                                   QueriedTargetBuffer,
52                                   ExpectedTarget->Length - 1);
53         RtlFillMemory(&QueriedTargetBuffer, sizeof(QueriedTargetBuffer), 0x55);
54         if (pResultLength) ResultLength = 0x55555555;
55         Status = ZwQuerySymbolicLinkObject(LinkHandle,
56                                            &QueriedTarget,
57                                            pResultLength);
58         ok_eq_hex(Status, STATUS_BUFFER_TOO_SMALL);
59         ok_eq_uint(QueriedTarget.Length, 0);
60         ok_eq_uint(QueriedTarget.MaximumLength, ExpectedTarget->Length - 1);
61         ok_eq_pointer(QueriedTarget.Buffer, QueriedTargetBuffer);
62         ok_eq_uint(QueriedTarget.Buffer[0], 0x5555);
63         if (pResultLength) ok_eq_ulong(ResultLength, ExpectedTarget->MaximumLength);
64 
65         /* Query with Length buffer */
66         RtlInitEmptyUnicodeString(&QueriedTarget,
67                                   QueriedTargetBuffer,
68                                   ExpectedTarget->Length);
69         RtlFillMemory(&QueriedTargetBuffer, sizeof(QueriedTargetBuffer), 0x55);
70         if (pResultLength) ResultLength = 0x55555555;
71         Status = ZwQuerySymbolicLinkObject(LinkHandle,
72                                            &QueriedTarget,
73                                            pResultLength);
74         ok_eq_uint(QueriedTarget.MaximumLength, ExpectedTarget->Length);
75         ok_eq_pointer(QueriedTarget.Buffer, QueriedTargetBuffer);
76         if (pResultLength &&
77             QueriedTarget.MaximumLength < ExpectedTarget->MaximumLength)
78         {
79             ok_eq_hex(Status, STATUS_BUFFER_TOO_SMALL);
80             ok_eq_uint(QueriedTarget.Length, 0);
81             ok_eq_uint(QueriedTarget.Buffer[0], 0x5555);
82             if (pResultLength) ok_eq_ulong(ResultLength, ExpectedTarget->MaximumLength);
83         }
84         else
85         {
86             ok_eq_hex(Status, STATUS_SUCCESS);
87             ok_eq_uint(QueriedTarget.Length, ExpectedTarget->Length);
88             ok(RtlEqualUnicodeString(&QueriedTarget, ExpectedTarget, FALSE), "%wZ != %wZ\n", &QueriedTarget, ExpectedTarget);
89             ok_eq_uint(QueriedTarget.Buffer[QueriedTarget.Length / sizeof(WCHAR)], 0x5555);
90         }
91 
92         /* Query with Length+1 buffer */
93         RtlInitEmptyUnicodeString(&QueriedTarget,
94                                   QueriedTargetBuffer,
95                                   ExpectedTarget->Length + 1);
96         RtlFillMemory(&QueriedTargetBuffer, sizeof(QueriedTargetBuffer), 0x55);
97         if (pResultLength) ResultLength = 0x55555555;
98         Status = ZwQuerySymbolicLinkObject(LinkHandle,
99                                            &QueriedTarget,
100                                            pResultLength);
101         ok_eq_uint(QueriedTarget.MaximumLength, ExpectedTarget->Length + 1);
102         ok_eq_pointer(QueriedTarget.Buffer, QueriedTargetBuffer);
103         if (pResultLength &&
104             QueriedTarget.MaximumLength < ExpectedTarget->MaximumLength)
105         {
106             ok_eq_hex(Status, STATUS_BUFFER_TOO_SMALL);
107             ok_eq_uint(QueriedTarget.Length, 0);
108             ok_eq_uint(QueriedTarget.Buffer[0], 0x5555);
109             if (pResultLength) ok_eq_ulong(ResultLength, ExpectedTarget->MaximumLength);
110         }
111         else
112         {
113             ok_eq_hex(Status, STATUS_SUCCESS);
114             ok_eq_uint(QueriedTarget.Length, ExpectedTarget->Length);
115             ok(RtlEqualUnicodeString(&QueriedTarget, ExpectedTarget, FALSE), "%wZ != %wZ\n", &QueriedTarget, ExpectedTarget);
116             ok_eq_uint(QueriedTarget.Buffer[QueriedTarget.Length / sizeof(WCHAR)], 0x5555);
117         }
118 
119         /* Query with Length+2 buffer */
120         RtlInitEmptyUnicodeString(&QueriedTarget,
121                                   QueriedTargetBuffer,
122                                   ExpectedTarget->Length + sizeof(WCHAR));
123         RtlFillMemory(&QueriedTargetBuffer, sizeof(QueriedTargetBuffer), 0x55);
124         if (pResultLength) ResultLength = 0x55555555;
125         Status = ZwQuerySymbolicLinkObject(LinkHandle,
126                                            &QueriedTarget,
127                                            pResultLength);
128         ok_eq_hex(Status, STATUS_SUCCESS);
129         ok_eq_uint(QueriedTarget.Length, ExpectedTarget->Length);
130         ok_eq_uint(QueriedTarget.MaximumLength, ExpectedTarget->Length + sizeof(WCHAR));
131         ok_eq_pointer(QueriedTarget.Buffer, QueriedTargetBuffer);
132         ok(RtlEqualUnicodeString(&QueriedTarget, ExpectedTarget, FALSE), "%wZ != %wZ\n", &QueriedTarget, ExpectedTarget);
133         if (pResultLength)
134         {
135             if (ExpectedTarget->MaximumLength >= ExpectedTarget->Length + sizeof(UNICODE_NULL))
136                 ok_eq_uint(QueriedTarget.Buffer[QueriedTarget.Length / sizeof(WCHAR)], 0);
137             ok_eq_ulong(ResultLength, ExpectedTarget->MaximumLength);
138         }
139         else
140         {
141             ok_eq_uint(QueriedTarget.Buffer[QueriedTarget.Length / sizeof(WCHAR)], 0x5555);
142         }
143 
144         /* Query with full-sized buffer */
145         RtlInitEmptyUnicodeString(&QueriedTarget,
146                                   QueriedTargetBuffer,
147                                   sizeof(QueriedTargetBuffer));
148         RtlFillMemory(&QueriedTargetBuffer, sizeof(QueriedTargetBuffer), 0x55);
149         if (pResultLength) ResultLength = 0x55555555;
150         Status = ZwQuerySymbolicLinkObject(LinkHandle,
151                                            &QueriedTarget,
152                                            pResultLength);
153         ok_eq_hex(Status, STATUS_SUCCESS);
154         ok_eq_uint(QueriedTarget.Length, ExpectedTarget->Length);
155         ok_eq_uint(QueriedTarget.MaximumLength, sizeof(QueriedTargetBuffer));
156         ok_eq_pointer(QueriedTarget.Buffer, QueriedTargetBuffer);
157         ok(RtlEqualUnicodeString(&QueriedTarget, ExpectedTarget, FALSE), "%wZ != %wZ\n", &QueriedTarget, ExpectedTarget);
158         if (pResultLength)
159         {
160             if (ExpectedTarget->MaximumLength >= ExpectedTarget->Length + sizeof(UNICODE_NULL))
161                 ok_eq_uint(QueriedTarget.Buffer[QueriedTarget.Length / sizeof(WCHAR)], 0);
162             ok_eq_ulong(ResultLength, ExpectedTarget->MaximumLength);
163         }
164         else
165         {
166             ok_eq_uint(QueriedTarget.Buffer[QueriedTarget.Length / sizeof(WCHAR)], 0x5555);
167         }
168     }
169 }
170 
171 START_TEST(ObSymbolicLink)
172 {
173     NTSTATUS Status;
174     HANDLE LinkHandle;
175     HANDLE LinkHandle2;
176     UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"\\Device\\ObSymbolicLinkKmtestNamedPipe");
177     OBJECT_ATTRIBUTES ObjectAttributes;
178     UNICODE_STRING DefaultLinkTarget = RTL_CONSTANT_STRING(L"\\Device\\NamedPipe");
179     UNICODE_STRING LinkTarget = DefaultLinkTarget;
180 
181     InitializeObjectAttributes(&ObjectAttributes,
182                                &LinkName,
183                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
184                                NULL,
185                                NULL);
186     LinkHandle = KmtInvalidPointer;
187     Status = ZwOpenSymbolicLinkObject(&LinkHandle,
188                                       SYMBOLIC_LINK_QUERY,
189                                       &ObjectAttributes);
190     ok_eq_hex(Status, STATUS_OBJECT_NAME_NOT_FOUND);
191     ok_eq_pointer(LinkHandle, NULL);
192     if (NT_SUCCESS(Status)) ObCloseHandle(LinkHandle, KernelMode);
193 
194     /* Create it */
195     LinkHandle = KmtInvalidPointer;
196     Status = ZwCreateSymbolicLinkObject(&LinkHandle,
197                                         SYMBOLIC_LINK_QUERY,
198                                         &ObjectAttributes,
199                                         &LinkTarget);
200     ok_eq_hex(Status, STATUS_SUCCESS);
201     ok(LinkHandle != NULL && LinkHandle != KmtInvalidPointer, "LinkHandle = %p\n", LinkHandle);
202     if (skip(NT_SUCCESS(Status), "Failed to create link\n"))
203     {
204         return;
205     }
206 
207     /* Now we should be able to open it */
208     LinkHandle2 = KmtInvalidPointer;
209     Status = ZwOpenSymbolicLinkObject(&LinkHandle2,
210                                       SYMBOLIC_LINK_QUERY,
211                                       &ObjectAttributes);
212     ok_eq_hex(Status, STATUS_SUCCESS);
213     ok(LinkHandle2 != NULL && LinkHandle2 != KmtInvalidPointer, "LinkHandle = %p\n", LinkHandle2);
214     if (!skip(NT_SUCCESS(Status), "Failed to open symlink\n"))
215     {
216         TestQueryLink(LinkHandle2, &LinkTarget);
217         ObCloseHandle(LinkHandle2, KernelMode);
218     }
219 
220     /* Close it */
221     ObCloseHandle(LinkHandle, KernelMode);
222 
223     /* Open fails again */
224     LinkHandle = KmtInvalidPointer;
225     Status = ZwOpenSymbolicLinkObject(&LinkHandle,
226                                       SYMBOLIC_LINK_QUERY,
227                                       &ObjectAttributes);
228     ok_eq_hex(Status, STATUS_OBJECT_NAME_NOT_FOUND);
229     ok_eq_pointer(LinkHandle, NULL);
230     if (NT_SUCCESS(Status)) ObCloseHandle(LinkHandle, KernelMode);
231 
232     /* Create with broken LinkTarget */
233     LinkHandle = KmtInvalidPointer;
234     LinkTarget.Buffer = NULL;
235     Status = ZwCreateSymbolicLinkObject(&LinkHandle,
236                                         SYMBOLIC_LINK_QUERY,
237                                         &ObjectAttributes,
238                                         &LinkTarget);
239     ok_eq_hex(Status, STATUS_ACCESS_VIOLATION);
240     ok(LinkHandle == KmtInvalidPointer, "LinkHandle = %p\n", LinkHandle);
241     if (NT_SUCCESS(Status)) ObCloseHandle(LinkHandle, KernelMode);
242 
243     /* Since it failed, open should also fail */
244     LinkHandle = KmtInvalidPointer;
245     Status = ZwOpenSymbolicLinkObject(&LinkHandle,
246                                       SYMBOLIC_LINK_QUERY,
247                                       &ObjectAttributes);
248     ok_eq_hex(Status, STATUS_OBJECT_NAME_NOT_FOUND);
249     ok_eq_pointer(LinkHandle, NULL);
250     if (NT_SUCCESS(Status)) ObCloseHandle(LinkHandle, KernelMode);
251 
252     /* Create with valid, but not null-terminated LinkTarget */
253     LinkTarget = DefaultLinkTarget;
254     LinkTarget.MaximumLength = LinkTarget.Length;
255     LinkHandle = KmtInvalidPointer;
256     Status = ZwCreateSymbolicLinkObject(&LinkHandle,
257                                         SYMBOLIC_LINK_QUERY,
258                                         &ObjectAttributes,
259                                         &LinkTarget);
260     ok_eq_hex(Status, STATUS_SUCCESS);
261     ok(LinkHandle != NULL && LinkHandle != KmtInvalidPointer, "LinkHandle = %p\n", LinkHandle);
262     if (skip(NT_SUCCESS(Status), "Failed to create link\n"))
263     {
264         return;
265     }
266 
267     /* Now we should be able to open it */
268     LinkHandle2 = KmtInvalidPointer;
269     Status = ZwOpenSymbolicLinkObject(&LinkHandle2,
270                                       SYMBOLIC_LINK_QUERY,
271                                       &ObjectAttributes);
272     ok_eq_hex(Status, STATUS_SUCCESS);
273     ok(LinkHandle2 != NULL && LinkHandle2 != KmtInvalidPointer, "LinkHandle = %p\n", LinkHandle2);
274     if (!skip(NT_SUCCESS(Status), "Failed to open symlink\n"))
275     {
276         TestQueryLink(LinkHandle2, &LinkTarget);
277         ObCloseHandle(LinkHandle2, KernelMode);
278     }
279 
280     /* Close it */
281     ObCloseHandle(LinkHandle, KernelMode);
282 }
283