xref: /reactos/drivers/ksfilter/ks/property.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/event.c
5  * PURPOSE:         KS property handling functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 /* SEH support with PSEH */
12 #include <pseh/pseh2.h>
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 const GUID KSPROPTYPESETID_General = {0x97E99BA0L, 0xBDEA, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
18 
19 NTSTATUS
FindPropertyHandler(IN PIO_STATUS_BLOCK IoStatus,IN const KSPROPERTY_SET * PropertySet,IN ULONG PropertySetCount,IN PKSPROPERTY Property,IN ULONG InputBufferLength,IN ULONG OutputBufferLength,OUT PVOID OutputBuffer,OUT PFNKSHANDLER * PropertyHandler,OUT PKSPROPERTY_SET * Set,OUT PKSPROPERTY_ITEM * PropertyItem)20 FindPropertyHandler(
21     IN PIO_STATUS_BLOCK IoStatus,
22     IN  const KSPROPERTY_SET* PropertySet,
23     IN ULONG PropertySetCount,
24     IN PKSPROPERTY Property,
25     IN ULONG InputBufferLength,
26     IN ULONG OutputBufferLength,
27     OUT PVOID OutputBuffer,
28     OUT PFNKSHANDLER *PropertyHandler,
29     OUT PKSPROPERTY_SET * Set,
30     OUT PKSPROPERTY_ITEM *PropertyItem)
31 {
32     ULONG Index, ItemIndex;
33     PULONG Flags;
34     PKSPROPERTY_DESCRIPTION Description;
35 
36     for(Index = 0; Index < PropertySetCount; Index++)
37     {
38         ASSERT(PropertySet[Index].Set);
39 
40         if (IsEqualGUIDAligned(&Property->Set, PropertySet[Index].Set))
41         {
42             for(ItemIndex = 0; ItemIndex < PropertySet[Index].PropertiesCount; ItemIndex++)
43             {
44 
45                 /* store property set */
46                 *Set = (PKSPROPERTY_SET)&PropertySet[Index];
47                 *PropertyItem = (PKSPROPERTY_ITEM)&PropertySet[Index].PropertyItem[ItemIndex];
48 
49 
50                 if (PropertySet[Index].PropertyItem[ItemIndex].PropertyId == Property->Id)
51                 {
52                     if (Property->Flags & KSPROPERTY_TYPE_BASICSUPPORT)
53                     {
54                         if (sizeof(ULONG) > OutputBufferLength)
55                         {
56                             /* too small buffer */
57                             return STATUS_INVALID_PARAMETER;
58                         }
59 
60                         /* get output buffer */
61                         Flags = (PULONG)OutputBuffer;
62 
63                         /* clear flags */
64                         *Flags = 0;
65 
66                         IoStatus->Information = sizeof(ULONG);
67 
68                         if (PropertySet[Index].PropertyItem[ItemIndex].SupportHandler)
69                         {
70                             /* use support handler from driver */
71                             *PropertyHandler = PropertySet[Index].PropertyItem[ItemIndex].SupportHandler;
72                             return STATUS_SUCCESS;
73                         }
74 
75                         if (PropertySet[Index].PropertyItem[ItemIndex].GetSupported)
76                             *Flags |= KSPROPERTY_TYPE_GET;
77 
78                         if (PropertySet[Index].PropertyItem[ItemIndex].SetSupported)
79                             *Flags |= KSPROPERTY_TYPE_SET;
80 
81                         if (OutputBufferLength >= sizeof(KSPROPERTY_DESCRIPTION))
82                         {
83                             /* get output buffer */
84                             Description = (PKSPROPERTY_DESCRIPTION)OutputBuffer;
85 
86                             /* store result */
87                             Description->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
88                             Description->PropTypeSet.Set = KSPROPTYPESETID_General;
89                             Description->PropTypeSet.Id = 0;
90                             Description->PropTypeSet.Flags = 0;
91                             Description->MembersListCount = 0;
92                             Description->Reserved = 0;
93 
94                             IoStatus->Information = sizeof(KSPROPERTY_DESCRIPTION);
95                         }
96                         return STATUS_SUCCESS;
97                     }
98 
99                     if (PropertySet[Index].PropertyItem[ItemIndex].MinProperty > InputBufferLength)
100                     {
101                         /* too small input buffer */
102                         IoStatus->Information = PropertySet[Index].PropertyItem[ItemIndex].MinProperty;
103                         return STATUS_INVALID_PARAMETER;
104                     }
105 
106                     if (PropertySet[Index].PropertyItem[ItemIndex].MinData > OutputBufferLength)
107                     {
108                         /* too small output buffer */
109                         IoStatus->Information = PropertySet[Index].PropertyItem[ItemIndex].MinData;
110                         return STATUS_MORE_ENTRIES;
111                     }
112 
113 
114                     if (Property->Flags & KSPROPERTY_TYPE_SET)
115                     {
116                         /* store property handler */
117                         *PropertyHandler = PropertySet[Index].PropertyItem[ItemIndex].SetPropertyHandler;
118                         return STATUS_SUCCESS;
119                     }
120 
121                     if (Property->Flags & KSPROPERTY_TYPE_GET)
122                     {
123                         /* store property handler */
124                         *PropertyHandler = PropertySet[Index].PropertyItem[ItemIndex].GetPropertyHandler;
125                         return STATUS_SUCCESS;
126                     }
127 
128 
129                 }
130             }
131         }
132     }
133     return STATUS_NOT_FOUND;
134 }
135 
136 
137 NTSTATUS
KspPropertyHandler(IN PIRP Irp,IN ULONG PropertySetsCount,IN const KSPROPERTY_SET * PropertySet,IN PFNKSALLOCATOR Allocator OPTIONAL,IN ULONG PropertyItemSize OPTIONAL)138 KspPropertyHandler(
139     IN PIRP Irp,
140     IN  ULONG PropertySetsCount,
141     IN  const KSPROPERTY_SET* PropertySet,
142     IN  PFNKSALLOCATOR Allocator OPTIONAL,
143     IN  ULONG PropertyItemSize OPTIONAL)
144 {
145     PKSPROPERTY Property;
146     PKSPROPERTY_ITEM PropertyItem;
147     PKSPROPERTY_SET Set;
148     PIO_STACK_LOCATION IoStack;
149     NTSTATUS Status;
150     PFNKSHANDLER PropertyHandler = NULL;
151     ULONG Index, InputBufferLength, OutputBufferLength, TotalSize;
152     LPGUID Guid;
153     //UNICODE_STRING GuidBuffer;
154 
155     /* get current irp stack */
156     IoStack = IoGetCurrentIrpStackLocation(Irp);
157 
158     /* get parameters */
159     OutputBufferLength = (IoStack->Parameters.DeviceIoControl.OutputBufferLength + 7) & ~7;
160     InputBufferLength = IoStack->Parameters.DeviceIoControl.InputBufferLength;
161 
162     /* check for invalid buffer length size */
163     if (OutputBufferLength < IoStack->Parameters.DeviceIoControl.OutputBufferLength)
164     {
165         /* unsigned overflow */
166         return STATUS_INVALID_BUFFER_SIZE;
167     }
168 
169     /* check for integer overflow */
170     if (InputBufferLength + OutputBufferLength < IoStack->Parameters.DeviceIoControl.OutputBufferLength)
171     {
172         /* overflow */
173         return STATUS_INVALID_BUFFER_SIZE;
174     }
175 
176     /* check if inputbuffer at least holds KSPROPERTY item */
177     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSPROPERTY))
178     {
179         /* invalid parameter */
180         return STATUS_INVALID_BUFFER_SIZE;
181     }
182 
183     /* get total size */
184     TotalSize = InputBufferLength + OutputBufferLength;
185 
186     /* get input property request */
187     Property = (PKSPROPERTY)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
188 
189     /* have the parameters been checked yet */
190     if (!Irp->AssociatedIrp.SystemBuffer)
191     {
192         /* is it from user mode */
193         if (Irp->RequestorMode == UserMode)
194         {
195             /* probe user buffer */
196             ProbeForRead(IoStack->Parameters.DeviceIoControl.Type3InputBuffer, InputBufferLength, 1);
197         }
198 
199         /* do we have an allocator */
200         if ((Allocator) && (Property->Flags & (KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_SET)))
201         {
202             /* call allocator */
203             Status = Allocator(Irp, TotalSize, (Property->Flags & KSPROPERTY_TYPE_GET));
204 
205             /* check for success */
206             if (!NT_SUCCESS(Status))
207                 return Status;
208         }
209         else
210         {
211             /* allocate buffer */
212             Irp->AssociatedIrp.SystemBuffer = AllocateItem(NonPagedPool, TotalSize);
213 
214             /* sanity check */
215             ASSERT(Irp->AssociatedIrp.SystemBuffer != NULL);
216 
217             /* mark irp as buffered so that changes the stream headers are propagated back */
218             Irp->Flags |= IRP_DEALLOCATE_BUFFER | IRP_BUFFERED_IO;
219         }
220 
221         /* now copy the buffer */
222         RtlCopyMemory((PVOID)((ULONG_PTR)Irp->AssociatedIrp.SystemBuffer + OutputBufferLength), IoStack->Parameters.DeviceIoControl.Type3InputBuffer, InputBufferLength);
223 
224         /* use new property buffer */
225         Property = (PKSPROPERTY)((ULONG_PTR)Irp->AssociatedIrp.SystemBuffer + OutputBufferLength);
226 
227         /* is it a set operation */
228         if (Property->Flags & KSPROPERTY_TYPE_SET)
229         {
230             /* for set operations, the output parameters need to be copied */
231             if (Irp->RequestorMode == UserMode)
232             {
233                 /* probe user parameter */
234                 ProbeForRead(Irp->UserBuffer, IoStack->Parameters.DeviceIoControl.OutputBufferLength, 1);
235             }
236 
237             /* copy parameters, needs un-aligned parameter length */
238             RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Irp->UserBuffer, IoStack->Parameters.DeviceIoControl.OutputBufferLength);
239         }
240 
241         /* is there an output buffer */
242         if (IoStack->Parameters.DeviceIoControl.OutputBufferLength)
243         {
244             /* is it from user mode */
245             if (Irp->RequestorMode == UserMode)
246             {
247                 /* probe buffer for writing */
248                 ProbeForWrite(Irp->UserBuffer, IoStack->Parameters.DeviceIoControl.OutputBufferLength, 1);
249             }
250 
251             if (!Allocator || !(Property->Flags & KSPROPERTY_TYPE_GET))
252             {
253                 /* it is an input operation */
254                 Irp->Flags |= IRP_INPUT_OPERATION;
255             }
256         }
257     }
258     else
259     {
260         /* use new property buffer */
261         Property = (PKSPROPERTY)((ULONG_PTR)Irp->AssociatedIrp.SystemBuffer + OutputBufferLength);
262     }
263 
264     //RtlStringFromGUID(&Property->Set, &GuidBuffer);
265 
266     //DPRINT("KspPropertyHandler Irp %p PropertySetsCount %u PropertySet %p Allocator %p PropertyItemSize %u ExpectedPropertyItemSize %u\n", Irp, PropertySetsCount, PropertySet, Allocator, PropertyItemSize, sizeof(KSPROPERTY_ITEM));
267     //DPRINT("PropertyId %lu PropertyFlags %x Guid %S\n", Property->Id, Property->Flags, GuidBuffer.Buffer);
268 
269     //RtlFreeUnicodeString(&GuidBuffer);
270 
271     /* sanity check */
272     ASSERT(PropertyItemSize == 0 || PropertyItemSize == sizeof(KSPROPERTY_ITEM));
273 
274     /* find the property handler */
275     Status = FindPropertyHandler(&Irp->IoStatus, PropertySet, PropertySetsCount, Property, InputBufferLength, OutputBufferLength, Irp->AssociatedIrp.SystemBuffer, &PropertyHandler, &Set, &PropertyItem);
276 
277     if (NT_SUCCESS(Status) && PropertyHandler)
278     {
279         /* store set */
280         KSPROPERTY_SET_IRP_STORAGE(Irp) = Set;
281 
282         /* are any custom property item sizes used */
283         if (PropertyItemSize)
284         {
285             /* store custom property item */
286             KSPROPERTY_ITEM_IRP_STORAGE(Irp) = PropertyItem;
287         }
288 
289         _SEH2_TRY
290         {
291             /* call property handler */
292             Status = PropertyHandler(Irp, Property, (OutputBufferLength > 0 ? Irp->AssociatedIrp.SystemBuffer : NULL));
293         }
294         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
295         {
296             _SEH2_YIELD(return _SEH2_GetExceptionCode());
297         }
298         _SEH2_END;
299 
300         if (Status == STATUS_BUFFER_TOO_SMALL)
301         {
302             /* output buffer is too small */
303             if (Allocator)
304             {
305                 /* allocate the requested amount */
306                 Status = Allocator(Irp, (ULONG)Irp->IoStatus.Information, FALSE);
307 
308                 /* check if the block was allocated */
309                 if (!NT_SUCCESS(Status))
310                 {
311                     /* no memory */
312                     return STATUS_INSUFFICIENT_RESOURCES;
313                 }
314                 _SEH2_TRY
315                 {
316                     /* re-call property handler */
317                     Status = PropertyHandler(Irp, Property, Irp->AssociatedIrp.SystemBuffer);
318                 }
319                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
320                 {
321                     Status =  _SEH2_GetExceptionCode();
322                 }
323                 _SEH2_END;
324             }
325         }
326     }
327     else if (IsEqualGUIDAligned(&Property->Set, &GUID_NULL) && Property->Id == 0 && (Property->Flags & KSPROPERTY_TYPE_SETSUPPORT) == KSPROPERTY_TYPE_SETSUPPORT)
328     {
329         // store output size
330         Irp->IoStatus.Information = sizeof(GUID) * PropertySetsCount;
331         if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GUID) * PropertySetsCount)
332         {
333             // buffer too small
334             return STATUS_MORE_ENTRIES;
335         }
336 
337         // get output buffer
338         Guid = (LPGUID)Irp->AssociatedIrp.SystemBuffer;
339 
340        // copy property guids from property sets
341        for(Index = 0; Index < PropertySetsCount; Index++)
342        {
343            RtlMoveMemory(&Guid[Index], PropertySet[Index].Set, sizeof(GUID));
344        }
345        Status = STATUS_SUCCESS;
346     }
347 
348     /* done */
349     return Status;
350 }
351 
352 /*
353     @implemented
354 */
355 KSDDKAPI
356 NTSTATUS
357 NTAPI
KsPropertyHandler(IN PIRP Irp,IN ULONG PropertySetsCount,IN const KSPROPERTY_SET * PropertySet)358 KsPropertyHandler(
359     IN  PIRP Irp,
360     IN  ULONG PropertySetsCount,
361     IN  const KSPROPERTY_SET* PropertySet)
362 {
363     return KspPropertyHandler(Irp, PropertySetsCount, PropertySet, NULL, 0);
364 }
365 
366 
367 /*
368     @implemented
369 */
_IRQL_requires_max_(PASSIVE_LEVEL)370 _IRQL_requires_max_(PASSIVE_LEVEL)
371 KSDDKAPI
372 NTSTATUS
373 NTAPI
374 KsPropertyHandlerWithAllocator(
375     _In_ PIRP Irp,
376     _In_ ULONG PropertySetsCount,
377     _In_reads_(PropertySetsCount) const KSPROPERTY_SET* PropertySet,
378     _In_opt_ PFNKSALLOCATOR Allocator,
379     _In_opt_ ULONG PropertyItemSize)
380 {
381     return KspPropertyHandler(Irp, PropertySetsCount, PropertySet, Allocator, PropertyItemSize);
382 }
383 
384 NTSTATUS
FindFastPropertyHandler(IN ULONG FastIoCount,IN const KSFASTPROPERTY_ITEM * FastIoTable,IN PKSPROPERTY PropertyId,OUT PFNKSFASTHANDLER * FastPropertyHandler)385 FindFastPropertyHandler(
386     IN ULONG FastIoCount,
387     IN const KSFASTPROPERTY_ITEM * FastIoTable,
388     IN PKSPROPERTY PropertyId,
389     OUT PFNKSFASTHANDLER * FastPropertyHandler)
390 {
391     ULONG Index;
392 
393     /* iterate through all items */
394     for(Index = 0; Index < FastIoCount; Index++)
395     {
396         if (PropertyId->Id == FastIoTable[Index].PropertyId)
397         {
398             if (PropertyId->Flags & KSPROPERTY_TYPE_SET)
399             {
400                 if (FastIoTable[Index].SetSupported)
401                 {
402                     *FastPropertyHandler = FastIoTable[Index].SetPropertyHandler;
403                     return STATUS_SUCCESS;
404                 }
405             }
406 
407             if (PropertyId->Flags & KSPROPERTY_TYPE_GET)
408             {
409                 if (FastIoTable[Index].GetSupported)
410                 {
411                     *FastPropertyHandler = FastIoTable[Index].GetPropertyHandler;
412                     return STATUS_SUCCESS;
413                 }
414             }
415         }
416 
417     }
418     /* no fast property handler found */
419     return STATUS_NOT_FOUND;
420 }
421 
422 
423 /*
424     @implemented
425 */
426 KSDDKAPI
427 BOOLEAN
428 NTAPI
KsFastPropertyHandler(IN PFILE_OBJECT FileObject,IN PKSPROPERTY UNALIGNED Property,IN ULONG PropertyLength,IN OUT PVOID UNALIGNED Data,IN ULONG DataLength,OUT PIO_STATUS_BLOCK IoStatus,IN ULONG PropertySetsCount,IN const KSPROPERTY_SET * PropertySet)429 KsFastPropertyHandler(
430     IN  PFILE_OBJECT FileObject,
431     IN  PKSPROPERTY UNALIGNED Property,
432     IN  ULONG PropertyLength,
433     IN  OUT PVOID UNALIGNED Data,
434     IN  ULONG DataLength,
435     OUT PIO_STATUS_BLOCK IoStatus,
436     IN  ULONG PropertySetsCount,
437     IN  const KSPROPERTY_SET* PropertySet)
438 {
439     KSPROPERTY PropRequest;
440     KPROCESSOR_MODE Mode;
441     NTSTATUS Status = STATUS_SUCCESS;
442     ULONG Index;
443     PFNKSFASTHANDLER FastPropertyHandler;
444 
445     if (PropertyLength < sizeof(KSPROPERTY))
446     {
447         /* invalid request */
448         return FALSE;
449     }
450 
451     /* get previous mode */
452     Mode = ExGetPreviousMode();
453 
454     if (Mode == KernelMode)
455     {
456         /* just copy it */
457         RtlMoveMemory(&PropRequest, Property, sizeof(KSPROPERTY));
458     }
459     else
460     {
461         /* need to probe the buffer */
462         _SEH2_TRY
463         {
464             ProbeForRead(Property, sizeof(KSPROPERTY), sizeof(UCHAR));
465             RtlMoveMemory(&PropRequest, Property, sizeof(KSPROPERTY));
466         }
467         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
468         {
469             /* Exception, get the error code */
470             Status = _SEH2_GetExceptionCode();
471         }_SEH2_END;
472 
473         if (!NT_SUCCESS(Status))
474             return FALSE;
475     }
476 
477     /* are there any property sets provided */
478     if (PropertySetsCount)
479     {
480         /* iterate through all property sets count */
481         Index = 0;
482         do
483         {
484             /* does the property id match */
485             if (IsEqualGUIDAligned(PropertySet[Index].Set, &PropRequest.Set))
486             {
487                 /* try to find a fast property handler */
488                 Status = FindFastPropertyHandler(PropertySet[Index].FastIoCount, PropertySet[Index].FastIoTable, &PropRequest, &FastPropertyHandler);
489 
490                 if (NT_SUCCESS(Status))
491                 {
492                     /* call fast property handler */
493                     ASSERT(PropertyLength == sizeof(KSPROPERTY)); /* FIXME check if property length is bigger -> copy params */
494                     ASSERT(Mode == KernelMode); /* FIXME need to probe usermode output buffer */
495                     return FastPropertyHandler(FileObject, &PropRequest, sizeof(KSPROPERTY), Data, DataLength, IoStatus);
496                 }
497             }
498             /* move to next item */
499             Index++;
500         }while(Index < PropertySetsCount);
501     }
502     return FALSE;
503 }
504 
505 /*
506     @implemented
507 */
508 KSDDKAPI
509 NTSTATUS
510 NTAPI
KsDispatchSpecificProperty(IN PIRP Irp,IN PFNKSHANDLER Handler)511 KsDispatchSpecificProperty(
512     IN  PIRP Irp,
513     IN  PFNKSHANDLER Handler)
514 {
515     PIO_STACK_LOCATION IoStack;
516 
517     /* get current irp stack location */
518     IoStack = IoGetCurrentIrpStackLocation(Irp);
519 
520     return Handler(Irp, IoStack->Parameters.DeviceIoControl.Type3InputBuffer, Irp->UserBuffer);
521 }
522 
523