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 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 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 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 */ 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 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 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 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