1 /*
2  * PROJECT:         ReactOS kernel-mode tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Kernel-Mode Test Suite Object Handle test
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include <kmt_test.h>
9 #define NDEBUG
10 #include <debug.h>
11 
12 #define CheckObject(Handle, Pointers, Handles, Attrib, Access) do   \
13 {                                                                   \
14     PUBLIC_OBJECT_BASIC_INFORMATION ObjectInfo;                     \
15     Status = ZwQueryObject(Handle, ObjectBasicInformation,          \
16                            &ObjectInfo, sizeof ObjectInfo, NULL);   \
17     ok_eq_hex(Status, STATUS_SUCCESS);                              \
18     ok_eq_hex(ObjectInfo.Attributes, Attrib);                       \
19     ok_eq_hex(ObjectInfo.GrantedAccess, Access);                    \
20     ok_eq_ulong(ObjectInfo.PointerCount, Pointers);                 \
21     ok_eq_ulong(ObjectInfo.HandleCount, Handles);                   \
22 } while (0)
23 
24 #define KERNEL_HANDLE_FLAG ((ULONG_PTR)0xFFFFFFFF80000000)
25 #define IsUserHandle(h)   (((ULONG_PTR)(h) & KERNEL_HANDLE_FLAG) == 0)
26 #define IsKernelHandle(h) (((ULONG_PTR)(h) & KERNEL_HANDLE_FLAG) == KERNEL_HANDLE_FLAG)
27 
28 static HANDLE SystemProcessHandle;
29 
30 static
31 VOID
32 TestDuplicate(
33     _In_ HANDLE Handle)
34 {
35     NTSTATUS Status;
36     HANDLE NewHandle;
37     struct
38     {
39         ACCESS_MASK DesiredAccess;
40         ULONG RequestedAttributes;
41         ULONG Options;
42         ACCESS_MASK GrantedAccess;
43         ULONG ExpectedAttributes;
44     } Tests[] =
45     {
46         { DIRECTORY_ALL_ACCESS, 0,                  0,
47           DIRECTORY_ALL_ACCESS, 0 },
48         { DIRECTORY_ALL_ACCESS, OBJ_KERNEL_HANDLE,  0,
49           DIRECTORY_ALL_ACCESS, 0 },
50         { DIRECTORY_QUERY,      0,                  0,
51           DIRECTORY_QUERY,      0 },
52         { DIRECTORY_QUERY,      OBJ_INHERIT,        0,
53           DIRECTORY_QUERY,      OBJ_INHERIT },
54         { DIRECTORY_QUERY,      OBJ_INHERIT,        DUPLICATE_SAME_ACCESS,
55           DIRECTORY_ALL_ACCESS, OBJ_INHERIT },
56         /* 5 */
57         { DIRECTORY_QUERY,      OBJ_INHERIT,        DUPLICATE_SAME_ATTRIBUTES,
58           DIRECTORY_QUERY,      0 },
59         { DIRECTORY_QUERY,      OBJ_INHERIT,        DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
60           DIRECTORY_ALL_ACCESS, 0 },
61     };
62     ULONG i;
63 
64     for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
65     {
66         trace("Test %lu\n", i);
67         Status = ZwDuplicateObject(ZwCurrentProcess(),
68                                    Handle,
69                                    ZwCurrentProcess(),
70                                    &NewHandle,
71                                    Tests[i].DesiredAccess,
72                                    Tests[i].RequestedAttributes,
73                                    Tests[i].Options);
74         ok_eq_hex(Status, STATUS_SUCCESS);
75         if (!skip(NT_SUCCESS(Status), "DuplicateHandle failed\n"))
76         {
77             ok(IsUserHandle(NewHandle), "New handle = %p\n", NewHandle);
78             CheckObject(NewHandle, 3UL, 2UL, Tests[i].ExpectedAttributes, Tests[i].GrantedAccess);
79             CheckObject(Handle, 3UL, 2UL, 0UL, DIRECTORY_ALL_ACCESS);
80 
81             Status = ObCloseHandle(NewHandle, UserMode);
82             ok_eq_hex(Status, STATUS_SUCCESS);
83             CheckObject(Handle, 2UL, 1UL, 0UL, DIRECTORY_ALL_ACCESS);
84         }
85     }
86 
87     /* If TargetProcess is the System process, we do get a kernel handle */
88     Status = ZwDuplicateObject(ZwCurrentProcess(),
89                                Handle,
90                                SystemProcessHandle,
91                                &NewHandle,
92                                DIRECTORY_ALL_ACCESS,
93                                OBJ_KERNEL_HANDLE,
94                                0);
95     ok_eq_hex(Status, STATUS_SUCCESS);
96     if (!skip(NT_SUCCESS(Status), "DuplicateHandle failed\n"))
97     {
98         ok(IsKernelHandle(NewHandle), "New handle = %p\n", NewHandle);
99         CheckObject(NewHandle, 3UL, 2UL, 0, DIRECTORY_ALL_ACCESS);
100         CheckObject(Handle, 3UL, 2UL, 0UL, DIRECTORY_ALL_ACCESS);
101 
102         Status = ObCloseHandle(NewHandle, UserMode);
103         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
104         CheckObject(NewHandle, 3UL, 2UL, 0, DIRECTORY_ALL_ACCESS);
105         CheckObject(Handle, 3UL, 2UL, 0UL, DIRECTORY_ALL_ACCESS);
106 
107         if (IsKernelHandle(NewHandle))
108         {
109             Status = ObCloseHandle(NewHandle, KernelMode);
110             ok_eq_hex(Status, STATUS_SUCCESS);
111             CheckObject(Handle, 2UL, 1UL, 0UL, DIRECTORY_ALL_ACCESS);
112         }
113     }
114 }
115 
116 START_TEST(ObHandle)
117 {
118     NTSTATUS Status;
119     OBJECT_ATTRIBUTES ObjectAttributes;
120     HANDLE KernelDirectoryHandle;
121     HANDLE UserDirectoryHandle;
122 
123     Status = ObOpenObjectByPointer(PsInitialSystemProcess,
124                                    OBJ_KERNEL_HANDLE,
125                                    NULL,
126                                    PROCESS_ALL_ACCESS,
127                                    *PsProcessType,
128                                    KernelMode,
129                                    &SystemProcessHandle);
130     ok_eq_hex(Status, STATUS_SUCCESS);
131     if (skip(NT_SUCCESS(Status), "No handle for system process\n"))
132     {
133         SystemProcessHandle = NULL;
134     }
135 
136     InitializeObjectAttributes(&ObjectAttributes,
137                                NULL,
138                                0,
139                                NULL,
140                                NULL);
141     Status = ZwCreateDirectoryObject(&UserDirectoryHandle,
142                                      DIRECTORY_ALL_ACCESS,
143                                      &ObjectAttributes);
144     ok_eq_hex(Status, STATUS_SUCCESS);
145     if (!skip(NT_SUCCESS(Status), "No directory handle\n"))
146     {
147         ok(IsUserHandle(UserDirectoryHandle), "User handle = %p\n", UserDirectoryHandle);
148         CheckObject(UserDirectoryHandle, 2UL, 1UL, 0UL, DIRECTORY_ALL_ACCESS);
149 
150         TestDuplicate(UserDirectoryHandle);
151 
152         Status = ObCloseHandle(UserDirectoryHandle, UserMode);
153         ok_eq_hex(Status, STATUS_SUCCESS);
154     }
155 
156     InitializeObjectAttributes(&ObjectAttributes,
157                                NULL,
158                                OBJ_KERNEL_HANDLE,
159                                NULL,
160                                NULL);
161     Status = ZwCreateDirectoryObject(&KernelDirectoryHandle,
162                                      DIRECTORY_ALL_ACCESS,
163                                      &ObjectAttributes);
164     ok_eq_hex(Status, STATUS_SUCCESS);
165     if (!skip(NT_SUCCESS(Status), "No directory handle\n"))
166     {
167         ok(IsKernelHandle(KernelDirectoryHandle), "Kernel handle = %p\n", KernelDirectoryHandle);
168         CheckObject(KernelDirectoryHandle, 2UL, 1UL, 0UL, DIRECTORY_ALL_ACCESS);
169 
170         TestDuplicate(KernelDirectoryHandle);
171 
172         Status = ObCloseHandle(KernelDirectoryHandle, UserMode);
173         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
174         CheckObject(KernelDirectoryHandle, 2UL, 1UL, 0UL, DIRECTORY_ALL_ACCESS);
175 
176         Status = ObCloseHandle(KernelDirectoryHandle, KernelMode);
177         ok_eq_hex(Status, STATUS_SUCCESS);
178     }
179 
180     /* Tests for closing handles */
181     KmtStartSeh()
182         /* NtClose must accept everything */
183         DPRINT("Closing null handle (NtClose)\n");
184         Status = NtClose(NULL);
185         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
186         DPRINT("Closing null kernel handle (NtClose)\n");
187         Status = NtClose(LongToHandle(0x80000000));
188         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
189         DPRINT("Closing -1 handle (NtClose)\n");
190         Status = NtClose(LongToHandle(0x7FFFFFFF));
191         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
192         DPRINT("Closing -1 kernel handle (NtClose)\n");
193         Status = NtClose(LongToHandle(0xFFFFFFFF));
194         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
195         DPRINT("Closing 123 handle (NtClose)\n");
196         Status = NtClose(LongToHandle(123));
197         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
198         DPRINT("Closing 123 kernel handle (NtClose)\n");
199         Status = NtClose(LongToHandle(123 | 0x80000000));
200         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
201 
202         /* ObCloseHandle with UserMode accepts everything */
203         DPRINT("Closing null handle (ObCloseHandle, UserMode)\n");
204         Status = ObCloseHandle(NULL, UserMode);
205         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
206         DPRINT("Closing null kernel handle (ObCloseHandle, UserMode)\n");
207         Status = ObCloseHandle(LongToHandle(0x80000000), UserMode);
208         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
209         DPRINT("Closing -1 handle (ObCloseHandle, UserMode)\n");
210         Status = ObCloseHandle(LongToHandle(0x7FFFFFFF), UserMode);
211         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
212         DPRINT("Closing -1 kernel handle (ObCloseHandle, UserMode)\n");
213         Status = ObCloseHandle(LongToHandle(0xFFFFFFFF), UserMode);
214         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
215         DPRINT("Closing 123 handle (ObCloseHandle, UserMode)\n");
216         Status = ObCloseHandle(LongToHandle(123), UserMode);
217         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
218         DPRINT("Closing 123 kernel handle (ObCloseHandle, UserMode)\n");
219         Status = ObCloseHandle(LongToHandle(123 | 0x80000000), UserMode);
220         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
221 
222         /* ZwClose only accepts 0 and -1 */
223         DPRINT("Closing null handle (ZwClose)\n");
224         Status = ZwClose(NULL);
225         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
226         DPRINT("Closing null kernel handle (ZwClose)\n");
227         Status = ZwClose(LongToHandle(0x80000000));
228         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
229         /* INVALID_KERNEL_HANDLE, 0x7FFFFFFF
230         Status = ZwClose((HANDLE)0x7FFFFFFF);*/
231         DPRINT("Closing -1 kernel handle (ZwClose)\n");
232         Status = ZwClose(LongToHandle(0xFFFFFFFF));
233         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
234         /* INVALID_KERNEL_HANDLE, 0x7B, 1, 0, 0
235         Status = ZwClose(LongToHandle(123));
236         Status = ZwClose(LongToHandle(123 | 0x80000000));*/
237 
238         /* ObCloseHandle with KernelMode accepts only 0 and -1 */
239         DPRINT("Closing null handle (ObCloseHandle, KernelMode)\n");
240         Status = ObCloseHandle(NULL, KernelMode);
241         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
242         DPRINT("Closing null kernel handle (ObCloseHandle, KernelMode)\n");
243         Status = ObCloseHandle(LongToHandle(0x80000000), KernelMode);
244         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
245         /* INVALID_KERNEL_HANDLE, 0x7FFFFFFF, 1, 0, 0
246         Status = ObCloseHandle((HANDLE)0x7FFFFFFF, KernelMode);*/
247         DPRINT("Closing -1 kernel handle (ObCloseHandle, KernelMode)\n");
248         Status = ObCloseHandle(LongToHandle(0xFFFFFFFF), KernelMode);
249         ok_eq_hex(Status, STATUS_INVALID_HANDLE);
250         /* INVALID_KERNEL_HANDLE, 0x7B, 1, 0, 0
251         Status = ObCloseHandle(LongToHandle(123), KernelMode);
252         Status = ObCloseHandle(LongToHandle(123 | 0x80000000), KernelMode);*/
253     KmtEndSeh(STATUS_SUCCESS);
254 
255     if (SystemProcessHandle)
256     {
257         ObCloseHandle(SystemProcessHandle, KernelMode);
258     }
259 }
260