xref: /reactos/drivers/filters/fltmgr/Object.c (revision 9215413a)
1 /*
2 * PROJECT:         Filesystem Filter Manager
3 * LICENSE:         GPL - See COPYING in the top level directory
4 * FILE:            drivers/filters/fltmgr/Object.c
5 * PURPOSE:         Miscellaneous library functions
6 * PROGRAMMERS:     Ged Murphy (gedmurphy@reactos.org)
7 */
8 
9 // NOTE: Split this file into filter object and device object functions
10 // when the code base grows sufficiently
11 
12 /* INCLUDES ******************************************************************/
13 
14 #include "fltmgr.h"
15 #include "fltmgrint.h"
16 
17 #define NDEBUG
18 #include <debug.h>
19 
20 
21 /* DATA *********************************************************************/
22 
23 #define ExpChangePushlock(x, y, z) InterlockedCompareExchangePointer((PVOID*)x, (PVOID)y, (PVOID)z)
24 
25 //
26 // Pushlock bits
27 //
28 #define EX_PUSH_LOCK_LOCK_V             ((ULONG_PTR)0x0)
29 #define EX_PUSH_LOCK_LOCK               ((ULONG_PTR)0x1)
30 #define EX_PUSH_LOCK_WAITING            ((ULONG_PTR)0x2)
31 #define EX_PUSH_LOCK_WAKING             ((ULONG_PTR)0x4)
32 #define EX_PUSH_LOCK_MULTIPLE_SHARED    ((ULONG_PTR)0x8)
33 #define EX_PUSH_LOCK_SHARE_INC          ((ULONG_PTR)0x10)
34 #define EX_PUSH_LOCK_PTR_BITS           ((ULONG_PTR)0xf)
35 
36 /* EXPORTED FUNCTIONS ******************************************************/
37 
38 
39 NTSTATUS
40 FLTAPI
FltObjectReference(_Inout_ PVOID Object)41 FltObjectReference(_Inout_ PVOID Object)
42 {
43     if (!FltpExAcquireRundownProtection(&((PFLT_OBJECT)Object)->RundownRef))
44     {
45         return STATUS_FLT_DELETING_OBJECT;
46     }
47 
48     return STATUS_SUCCESS;
49 }
50 
51 VOID
52 FLTAPI
FltObjectDereference(_Inout_ PVOID Object)53 FltObjectDereference(_Inout_ PVOID Object)
54 {
55     FltpExReleaseRundownProtection(&((PFLT_OBJECT)Object)->RundownRef);
56 }
57 
58 
59 _Acquires_lock_(_Global_critical_region_)
_IRQL_requires_max_(APC_LEVEL)60 _IRQL_requires_max_(APC_LEVEL)
61 VOID
62 FLTAPI
63 FltAcquirePushLockExclusive(_Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PEX_PUSH_LOCK PushLock)
64 {
65     KeEnterCriticalRegion();
66 
67     /* Try acquiring the lock */
68     if (InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_V))
69     {
70         /* Someone changed it, use the slow path */
71         ExfAcquirePushLockExclusive(PushLock);
72     }
73 
74     /* Sanity check */
75     FLT_ASSERT(PushLock->Locked);
76 }
77 
78 
79 _Acquires_lock_(_Global_critical_region_)
_IRQL_requires_max_(APC_LEVEL)80 _IRQL_requires_max_(APC_LEVEL)
81 VOID
82 FLTAPI
83 FltAcquirePushLockShared(_Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_) PEX_PUSH_LOCK PushLock)
84 {
85     EX_PUSH_LOCK NewValue;
86 
87     KeEnterCriticalRegion();
88 
89     /* Try acquiring the lock */
90     NewValue.Value = EX_PUSH_LOCK_LOCK | EX_PUSH_LOCK_SHARE_INC;
91     if (ExpChangePushlock(PushLock, NewValue.Ptr, 0))
92     {
93         /* Someone changed it, use the slow path */
94         ExfAcquirePushLockShared(PushLock);
95     }
96 
97     /* Sanity checks */
98     ASSERT(PushLock->Locked);
99 }
100 
101 _Releases_lock_(_Global_critical_region_)
_IRQL_requires_max_(APC_LEVEL)102 _IRQL_requires_max_(APC_LEVEL)
103 VOID
104 FLTAPI
105 FltReleasePushLock(_Inout_ _Requires_lock_held_(*_Curr_) _Releases_lock_(*_Curr_) PEX_PUSH_LOCK PushLock)
106 {
107     EX_PUSH_LOCK OldValue = *PushLock;
108     EX_PUSH_LOCK NewValue;
109 
110     /* Sanity checks */
111     FLT_ASSERT(OldValue.Locked);
112 
113     /* Check if the pushlock is shared */
114     if (OldValue.Shared > 1)
115     {
116         /* Decrease the share count */
117         NewValue.Value = OldValue.Value - EX_PUSH_LOCK_SHARE_INC;
118     }
119     else
120     {
121         /* Clear the pushlock entirely */
122         NewValue.Value = 0;
123     }
124 
125     /* Check if nobody is waiting on us and try clearing the lock here */
126     if ((OldValue.Waiting) ||
127         (ExpChangePushlock(PushLock, NewValue.Ptr, OldValue.Ptr) !=
128          OldValue.Ptr))
129     {
130         /* We have waiters, use the long path */
131         ExfReleasePushLock(PushLock);
132     }
133 
134     KeLeaveCriticalRegion();
135 }
136 
_IRQL_requires_max_(PASSIVE_LEVEL)137 _IRQL_requires_max_(PASSIVE_LEVEL)
138 NTSTATUS
139 FLTAPI
140 FltClose(_In_ HANDLE FileHandle)
141 {
142     PAGED_CODE();
143 
144     return ZwClose(FileHandle);
145 }
146 
147 _Must_inspect_result_
_IRQL_requires_max_(PASSIVE_LEVEL)148 _IRQL_requires_max_(PASSIVE_LEVEL)
149 NTSTATUS
150 FLTAPI
151 FltCreateFileEx(_In_ PFLT_FILTER Filter,
152                 _In_opt_ PFLT_INSTANCE Instance,
153                 _Out_ PHANDLE FileHandle,
154                 _Outptr_opt_ PFILE_OBJECT *FileObject,
155                 _In_ ACCESS_MASK DesiredAccess,
156                 _In_ POBJECT_ATTRIBUTES ObjectAttributes,
157                 _Out_ PIO_STATUS_BLOCK IoStatusBlock,
158                 _In_opt_ PLARGE_INTEGER AllocationSize,
159                 _In_ ULONG FileAttributes,
160                 _In_ ULONG ShareAccess,
161                 _In_ ULONG CreateDisposition,
162                 _In_ ULONG CreateOptions,
163                 _In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
164                 _In_ ULONG EaLength,
165                 _In_ ULONG Flags)
166 {
167     UNIMPLEMENTED;
168     return STATUS_NOT_IMPLEMENTED;
169 }
170 
171 _Must_inspect_result_
_IRQL_requires_max_(PASSIVE_LEVEL)172 _IRQL_requires_max_(PASSIVE_LEVEL)
173 NTSTATUS
174 FLTAPI
175 FltCreateFile(_In_ PFLT_FILTER Filter,
176               _In_opt_ PFLT_INSTANCE Instance,
177               _Out_ PHANDLE FileHandle,
178               _In_ ACCESS_MASK DesiredAccess,
179               _In_ POBJECT_ATTRIBUTES ObjectAttributes,
180               _Out_ PIO_STATUS_BLOCK IoStatusBlock,
181               _In_opt_ PLARGE_INTEGER AllocationSize,
182               _In_ ULONG FileAttributes,
183               _In_ ULONG ShareAccess,
184               _In_ ULONG CreateDisposition,
185               _In_ ULONG CreateOptions,
186               _In_reads_bytes_opt_(EaLength)PVOID EaBuffer,
187               _In_ ULONG EaLength,
188               _In_ ULONG Flags)
189 {
190     return FltCreateFileEx(Filter,
191                            Instance,
192                            FileHandle,
193                            NULL,
194                            DesiredAccess,
195                            ObjectAttributes,
196                            IoStatusBlock,
197                            AllocationSize,
198                            FileAttributes,
199                            ShareAccess,
200                            CreateDisposition,
201                            CreateOptions,
202                            EaBuffer,
203                            EaLength,
204                            Flags);
205 }
206 
207 
208 
209 /* INTERNAL FUNCTIONS ******************************************************/
210 
211 VOID
FltpExInitializeRundownProtection(_Out_ PEX_RUNDOWN_REF RundownRef)212 FltpExInitializeRundownProtection(_Out_ PEX_RUNDOWN_REF RundownRef)
213 {
214     ExInitializeRundownProtection(RundownRef);
215 }
216 
217 BOOLEAN
FltpExAcquireRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)218 FltpExAcquireRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
219 {
220     return ExAcquireRundownProtection(RundownRef);
221 }
222 
223 BOOLEAN
FltpExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)224 FltpExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RundownRef)
225 {
226     ExReleaseRundownProtection(RundownRef);
227     return TRUE;
228 }
229 
230 BOOLEAN
FltpExRundownCompleted(_Inout_ PEX_RUNDOWN_REF RundownRef)231 FltpExRundownCompleted(_Inout_ PEX_RUNDOWN_REF RundownRef)
232 {
233     return _InterlockedExchange((PLONG)RundownRef, 1);
234 }
235 
236 NTSTATUS
237 NTAPI
FltpObjectRundownWait(_Inout_ PEX_RUNDOWN_REF RundownRef)238 FltpObjectRundownWait(_Inout_ PEX_RUNDOWN_REF RundownRef)
239 {
240     //return FltpExWaitForRundownProtectionRelease(RundownRef);
241     return 0;
242 }
243 
244 NTSTATUS
FltpGetBaseDeviceObjectName(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PUNICODE_STRING ObjectName)245 FltpGetBaseDeviceObjectName(_In_ PDEVICE_OBJECT DeviceObject,
246                             _Inout_ PUNICODE_STRING ObjectName)
247 {
248     PDEVICE_OBJECT BaseDeviceObject;
249     NTSTATUS Status;
250 
251     /*
252     * Get the lowest device object on the stack, which may be the
253     * object we were passed, and lookup the name for that object
254     */
255     BaseDeviceObject = IoGetDeviceAttachmentBaseRef(DeviceObject);
256     Status = FltpGetObjectName(BaseDeviceObject, ObjectName);
257     ObDereferenceObject(BaseDeviceObject);
258 
259     return Status;
260 }
261 
262 NTSTATUS
FltpGetObjectName(_In_ PVOID Object,_Inout_ PUNICODE_STRING ObjectName)263 FltpGetObjectName(_In_ PVOID Object,
264                   _Inout_ PUNICODE_STRING ObjectName)
265 {
266     OBJECT_NAME_INFORMATION LocalNameInfo;
267     POBJECT_NAME_INFORMATION ObjectNameInfo = &LocalNameInfo;
268     ULONG ReturnLength;
269     NTSTATUS Status;
270 
271     if (ObjectName == NULL)
272         return STATUS_INVALID_PARAMETER;
273 
274     /* Get the size of the buffer required to hold the nameinfo */
275     Status = ObQueryNameString(Object,
276                                &LocalNameInfo,
277                                sizeof(LocalNameInfo),
278                                &ReturnLength);
279     if (Status == STATUS_INFO_LENGTH_MISMATCH)
280     {
281         ObjectNameInfo = ExAllocatePoolWithTag(PagedPool,
282                                                ReturnLength,
283                                                FM_TAG_UNICODE_STRING);
284         if (ObjectNameInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES;
285 
286         /* Get the actual name info now we have the buffer to hold it */
287         Status = ObQueryNameString(Object,
288                                    ObjectNameInfo,
289                                    ReturnLength,
290                                    &ReturnLength);
291     }
292 
293 
294     if (NT_SUCCESS(Status))
295     {
296         /* Make sure the buffer we were passed is large enough to hold the string */
297         if (ObjectName->MaximumLength < ObjectNameInfo->Name.Length)
298         {
299             /* It wasn't, let's enlarge the buffer */
300             Status = FltpReallocateUnicodeString(ObjectName,
301                                                  ObjectNameInfo->Name.Length,
302                                                  FALSE);
303 
304         }
305 
306         if (NT_SUCCESS(Status))
307         {
308             /* Copy the object name into the callers buffer */
309             RtlCopyUnicodeString(ObjectName, &ObjectNameInfo->Name);
310         }
311     }
312 
313     if (ObjectNameInfo != &LocalNameInfo)
314     {
315         ExFreePoolWithTag(ObjectNameInfo, FM_TAG_UNICODE_STRING);
316     }
317 
318     return Status;
319 }
320 
321 ULONG
FltpObjectPointerReference(_In_ PFLT_OBJECT Object)322 FltpObjectPointerReference(_In_ PFLT_OBJECT Object)
323 {
324     PULONG Result;
325 
326     /* Store the old count and increment */
327     Result = &Object->PointerCount;
328     InterlockedIncrementSizeT(&Object->PointerCount);
329 
330     /* Return the initial value */
331     return *Result;
332 }
333 
334 VOID
FltpObjectPointerDereference(_In_ PFLT_OBJECT Object)335 FltpObjectPointerDereference(_In_ PFLT_OBJECT Object)
336 {
337     if (InterlockedDecrementSizeT(&Object->PointerCount) == 0)
338     {
339         // Cleanup
340         FLT_ASSERT(FALSE);
341     }
342 }
343