1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxRequest.cpp
8 
9 Abstract:
10 
11     This module implements FxRequest object
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19     Both kernel and user mode
20 
21 Revision History:
22 
23 
24 --*/
25 
26 #include "coreprivshared.hpp"
27 
28 // Tracing support
29 extern "C" {
30 // #include "FxRequest.tmh"
31 }
32 
FxRequest(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in MdIrp Irp,__in FxRequestIrpOwnership Ownership,__in FxRequestConstructorCaller Caller,__in USHORT ObjectSize)33 FxRequest::FxRequest(
34     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
35     __in MdIrp Irp,
36     __in FxRequestIrpOwnership Ownership,
37     __in FxRequestConstructorCaller Caller,
38     __in USHORT ObjectSize
39     ) :
40     FxRequestBase(FxDriverGlobals,
41                   ObjectSize,
42                   Irp,
43                   Ownership,
44                   Caller)
45 {
46     m_OutputBufferOffset = FIELD_OFFSET(FxRequest, m_OutputBufferOffset);
47     m_SystemBufferOffset = FIELD_OFFSET(FxRequest, m_SystemBufferOffset);
48     m_IoQueue  = NULL;
49 
50     m_PowerStopState = FxRequestPowerStopUnknown;
51 
52     InitializeListHead(&m_OwnerListEntry);
53     InitializeListHead(&m_OwnerListEntry2);
54     InitializeListHead(&m_ForwardProgressList);
55 
56     m_Presented = (Caller == FxRequestConstructorCallerIsDriver) ? TRUE : FALSE;
57     m_Reserved = FALSE;
58     m_ForwardProgressQueue = NULL;
59     m_ForwardRequestToParent = FALSE;
60     m_InternalContext = NULL;
61 }
62 
63 #if DBG
~FxRequest(VOID)64 FxRequest::~FxRequest(
65     VOID
66     )
67 {
68     ASSERT(IsListEmpty(&m_OwnerListEntry));
69     ASSERT(IsListEmpty(&m_OwnerListEntry2));
70 }
71 #endif // DBG
72 
73 _Must_inspect_result_
74 NTSTATUS
_CreateForPackage(__in CfxDevice * Device,__in PWDF_OBJECT_ATTRIBUTES RequestAttributes,__in MdIrp Irp,__deref_out FxRequest ** Request)75 FxRequest::_CreateForPackage(
76     __in CfxDevice* Device,
77     __in PWDF_OBJECT_ATTRIBUTES RequestAttributes,
78     __in MdIrp Irp,
79     __deref_out FxRequest** Request
80    )
81 /*++
82 
83 Routine Description:
84 
85     Creates an FxRequest object and returns its pointer to the caller.
86 
87 Arguments:
88 
89     Device - Pointer to FxDevice object request will be associated with
90 
91     RequestAttributes - Specifies the object's attributes for the request.
92 
93     Irp    - Pointer to Irp
94 
95     Request - Pointer to location to store the returned FxRequest pointer
96 
97 Return Value:
98 
99     NTSTATUS
100 
101 --*/
102 {
103     NTSTATUS  status;
104     FxRequest* pRequest;
105 
106     *Request = NULL;
107 
108     //
109     // Allocate the new FxRequest object in the per driver tracking pool
110     //
111     pRequest = new(Device, RequestAttributes) FxRequestFromLookaside(Device, Irp);
112 
113     if (pRequest == NULL) {
114         DoTraceLevelMessage(
115             Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
116             "Memory allocation failed %!STATUS!",
117             STATUS_INSUFFICIENT_RESOURCES);
118         return STATUS_INSUFFICIENT_RESOURCES;
119     }
120 
121     //
122     // For forward progress the IRP can be NULL.
123     //
124     if (Irp != NULL) {
125         pRequest->AssignMemoryBuffers(Device->GetIoTypeForReadWriteBufferAccess());
126     }
127 
128     //
129     // Improve I/O perf by not parenting it to device. However, if verifier is
130     // turned on, the request is parented to the device to help track reference
131     // leaks.
132     //
133     if (Device->GetDriverGlobals()->FxRequestParentOptimizationOn) {
134         status = pRequest->Commit(RequestAttributes,
135                                   NULL,
136                                   NULL,
137                                   FALSE);
138     }
139     else {
140         status = pRequest->Commit(RequestAttributes,
141                                   NULL,
142                                   Device,
143                                   FALSE);
144     }
145 
146     if (NT_SUCCESS(status)) {
147         *Request = pRequest;
148     }
149     else {
150         DoTraceLevelMessage(
151             Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
152             "Could not commit FxRequest %!STATUS!", status);
153         pRequest->DeleteFromFailedCreate();
154     }
155 
156     return status;
157 }
158 
159 _Must_inspect_result_
160 NTSTATUS
_Create(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes,__in_opt MdIrp Irp,__in_opt FxIoTarget * Target,__in FxRequestIrpOwnership Ownership,__in FxRequestConstructorCaller Caller,__deref_out FxRequest ** Request)161 FxRequest::_Create(
162     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
163     __in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes,
164     __in_opt MdIrp Irp,
165     __in_opt FxIoTarget* Target,
166     __in FxRequestIrpOwnership Ownership,
167     __in FxRequestConstructorCaller Caller,
168     __deref_out FxRequest** Request
169     )
170 {
171     WDFOBJECT hRequest;
172     NTSTATUS status;
173     FxRequest* pRequest;
174 
175     *Request = NULL;
176 
177     status = FxValidateObjectAttributes(FxDriverGlobals, RequestAttributes);
178     if (!NT_SUCCESS(status)) {
179         return status;
180     }
181 
182     pRequest = new (FxDriverGlobals, RequestAttributes)
183         FxRequest(FxDriverGlobals,
184                   Irp,
185                   Ownership,
186                   Caller,
187                   sizeof(FxRequest));
188 
189     if (pRequest != NULL) {
190         if (Target != NULL) {
191             status = pRequest->ValidateTarget(Target);
192         }
193 
194         if (NT_SUCCESS(status)) {
195             status = pRequest->Commit(RequestAttributes, &hRequest, NULL, TRUE);
196         }
197 
198         if (NT_SUCCESS(status)) {
199             *Request = pRequest;
200         }
201         else {
202             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
203                                 "Handle create failed %!STATUS!", status);
204 
205             if (Irp != NULL) {
206                 //
207                 // Clear the irp out of the request so that the destructor does
208                 // not free it.  Since we are returning failure, the caller does
209                 // not expect the PIRP passed in to be freed.
210                 //
211                 pRequest->SetSubmitIrp(NULL, FALSE);
212             }
213 
214             pRequest->DeleteFromFailedCreate();
215         }
216     }
217     else {
218         status = STATUS_INSUFFICIENT_RESOURCES;
219     }
220 
221     DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
222                         "Irp %p Ownership %!FxRequestIrpOwnership! FxRequest %p, status %!STATUS!",
223                         Irp, Ownership, *Request, status);
224 
225     return status;
226 }
227 
228 NTSTATUS
SetInformation(__in ULONG_PTR Information)229 FxRequest::SetInformation(
230     __in ULONG_PTR Information
231     )
232 /*++
233 
234 Routine Description:
235 
236     Set the IRP's IoStatus.Information field.
237 
238     NOTE: If the caller calls Complete(status, information), as opposed
239           to Complete(status), the value will get overwritten.
240 
241 Arguments:
242 
243     Information - Information value to set
244 
245 Returns:
246 
247     NTSTATUS
248 
249 --*/
250 {
251     PFX_DRIVER_GLOBALS pFxDriverGlobals;
252 
253     pFxDriverGlobals = GetDriverGlobals();
254 
255     if (pFxDriverGlobals->FxVerifierIO) {
256         NTSTATUS status;
257         KIRQL irql;
258 
259         Lock(&irql);
260 
261         status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
262         if (NT_SUCCESS(status)) {
263             m_Irp.SetInformation(Information);
264         }
265 
266         Unlock(irql);
267 
268         return status;
269     }
270     else {
271         m_Irp.SetInformation(Information);
272         return STATUS_SUCCESS;
273     }
274 }
275 
276 ULONG_PTR
GetInformation(VOID)277 FxRequest::GetInformation(
278     VOID
279     )
280 /*++
281 
282 Routine Description:
283 
284     Get the IRP's IoStatus.Information field.
285 
286 
287 Arguments:
288 
289     None
290 
291 Returns:
292 
293     ULONG_PTR
294 
295 --*/
296 {
297     PFX_DRIVER_GLOBALS pFxDriverGlobals;
298 
299     pFxDriverGlobals = GetDriverGlobals();
300 
301     // Verifier
302     if (pFxDriverGlobals->FxVerifierIO) {
303         ULONG_PTR info;
304         KIRQL irql;
305         NTSTATUS status;
306 
307         Lock(&irql);
308 
309         status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
310         if (!NT_SUCCESS(status)) {
311             info = NULL;
312         }
313         else {
314             info = m_Irp.GetInformation();
315         }
316 
317         Unlock(irql);
318 
319         return info;
320     }
321     else {
322         return m_Irp.GetInformation();
323     }
324 }
325 
326 KPROCESSOR_MODE
GetRequestorMode(VOID)327 FxRequest::GetRequestorMode(
328     VOID
329     )
330 /*++
331 
332 Routine Description:
333     Get the Irp->RequestorMode value.
334 
335 Arguments:
336     None
337 
338 Returns:
339     KPROCESSOR_MODE
340 
341 --*/
342 {
343     PFX_DRIVER_GLOBALS pFxDriverGlobals;
344 
345     pFxDriverGlobals = GetDriverGlobals();
346 
347     if (pFxDriverGlobals->FxVerifierIO) {
348         KPROCESSOR_MODE mode;
349         KIRQL irql;
350         NTSTATUS status;
351 
352         Lock(&irql);
353 
354         status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
355         if (!NT_SUCCESS(status)) {
356             mode = UserMode;
357         } else {
358             mode = m_Irp.GetRequestorMode();
359         }
360 
361         Unlock(irql);
362 
363         return mode;
364     }
365     else {
366         return m_Irp.GetRequestorMode();
367     }
368 }
369 
370 
371 VOID
FX_VF_METHOD(FxRequest,VerifyCompleteInternal)372 FX_VF_METHOD(FxRequest, VerifyCompleteInternal)(
373     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
374     _In_ NTSTATUS Status
375     )
376 {
377     UNREFERENCED_PARAMETER(FxDriverGlobals);
378     ULONG length;
379     KIRQL irql;
380     BOOLEAN validateLength;
381 
382     PAGED_CODE_LOCKED();
383 
384     Lock(&irql);
385 
386     if (GetDriverGlobals()->FxVerifierIO ) {
387         (VOID) VerifyRequestIsNotCompleted(GetDriverGlobals());
388     } else {
389         ASSERT(m_Completed == FALSE);
390     }
391 
392 
393     if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_CANCELABLE) &&
394         (m_VerifierFlags & FXREQUEST_FLAG_CANCELLED) == 0x0) {
395 
396         //
397         // We could trace each sentence separate, but that takes up valuable
398         // room in the IFR.  Instead, trace the entire "paragraph" as one
399         // message so that we have more room in the IFR.
400         //
401         DoTraceLevelMessage(
402             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
403             "Completing Cancelable WDFREQUEST %p.  "
404 
405             "This results in a race condition in the device driver that can "
406             "cause double completions.  "
407 
408             "Call WdfRequestUnmarkCancelable before WdfRequestComplete.  "
409 
410             "If WdfRequestUnmarkCancelable returns STATUS_CANCELLED, "
411             "do not complete the request until the EvtIoCancel handler is called.  "
412 
413             "The straightforward way to ensure this is to complete a canceled "
414             "request from the EvIoCancel callback.",
415 
416             GetHandle()
417             );
418 
419             FxVerifierDbgBreakPoint(GetDriverGlobals());
420 
421     }
422 
423     validateLength = FALSE;
424     length = 0;
425 
426     switch (m_Irp.GetMajorFunction()) {
427     case IRP_MJ_READ:
428         length = m_Irp.GetParameterReadLength();
429         validateLength = TRUE;
430         break;
431 
432     case IRP_MJ_WRITE:
433         length = m_Irp.GetParameterWriteLength();
434         validateLength = TRUE;
435         break;
436 
437     case IRP_MJ_DEVICE_CONTROL:
438         if (m_Irp.GetRequestorMode() == UserMode) {
439             length = m_Irp.GetParameterIoctlOutputBufferLength();
440 
441             if (length > 0) {
442                 validateLength = TRUE;
443             }
444             else {
445                 //
446                 // For an output length == 0, a driver can indicate the number
447                 // of bytes used of the input buffer.
448                 //
449                 DO_NOTHING();
450             }
451         }
452         else {
453             //
454             // If the IOCTL came from kernel mode, the same reasoning applies
455             // here as for an internal IOCTL...we don't know deterministically
456             // how to find the output buffer length.
457             //
458             DO_NOTHING();
459         }
460         break;
461 
462     case IRP_MJ_INTERNAL_DEVICE_CONTROL:
463         //
464         // Because the current stack location can use any part of the union
465         // (like Parameters.Others instead of Parameters.DeviceIoControl), we
466         // cannot deterministically figure out the output buffer length for
467         // internal IOCTLs.
468         //
469         //    ||   || Fall through ||   ||
470         //    \/   \/              \/   \/
471     default:
472         DO_NOTHING();
473     }
474 
475     //
476     // We shouldn't validate the information field if the status is warning
477     // because it's valid for a driver to fill partial data in the buffer
478     // and ask for large buffer size.
479     //
480     if (validateLength &&
481             NT_SUCCESS(Status) &&
482                 m_Irp.GetInformation() > length) {
483 
484         WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA data;
485 
486         DoTraceLevelMessage(
487             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
488             "WDFREQUEST %p, MJ 0x%x, Information 0x%I64x is greater then "
489             "buffer length 0x%x", GetHandle(), m_Irp.GetMajorFunction(),
490             m_Irp.GetInformation(), length);
491 
492         data.Request = GetHandle();
493         data.Irp = reinterpret_cast<PIRP>(m_Irp.GetIrp());
494         data.OutputBufferLength = length;
495         data.Information = m_Irp.GetInformation();
496         data.MajorFunction = m_Irp.GetMajorFunction();
497 
498         FxVerifierBugCheck(
499             GetDriverGlobals(),
500             WDF_REQUEST_FATAL_ERROR,
501             WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH,
502             (ULONG_PTR) &data
503             );
504 
505         // will not get here
506     }
507 
508     // Set IRP to NULL when NT IRP is completed
509     m_Completed = TRUE;
510 
511     Unlock(irql);
512 }
513 
514 NTSTATUS
CompleteInternal(__in NTSTATUS Status)515 FxRequest::CompleteInternal(
516     __in NTSTATUS Status
517     )
518 
519 /*++
520 
521 Routine Description:
522 
523     Internal worker to complete the current request object.
524 
525     This is called with the FxRequest object lock held, and
526     state validation as far as IRP completion already done.
527 
528     Callers must use Complete(Status), or Complete(Status,Information)
529 
530     It returns with the FxRequest object locked *released*
531 
532 Arguments:
533 
534     Status - Status to complete the request with
535 
536 Returns:
537 
538     NTSTATUS
539 
540 --*/
541 
542 {
543     PFX_DRIVER_GLOBALS pFxDriverGlobals;
544     MdIrp               pIrp;
545     FxRequestCompletionState state;
546     FxIoQueue*          queue;
547     CfxDevice*           pRefedDevice;
548 
549     pFxDriverGlobals = GetDriverGlobals();
550     queue = NULL;
551     //
552     // Store off the irp into a local variable
553     //
554     pIrp = m_Irp.GetIrp();
555 
556     //
557     // Lock is no longer required, since it's only used
558     // by verifier for already completed requests. This is a
559     // serious driver error anyway
560     //
561 
562 
563     VerifyCompleteInternal(pFxDriverGlobals, Status);
564 
565     if (pFxDriverGlobals->FxVerifierOn == FALSE) {
566         //
567         // No lock needed in non-verifier case since this is only
568         // used to detect double completions with verifier on
569         //
570         ASSERT(m_Completed == FALSE);
571         m_Completed = TRUE;
572     }
573 
574 
575 
576 
577 
578 
579 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
580 
581 
582 
583 
584 
585 
586 
587     ULONG flagsMasked = m_Irp.GetFlags() & IRP_INPUT_OPERATION;
588     if (m_Irp.GetMajorFunction()== IRP_MJ_DEVICE_CONTROL &&
589         m_Irp.GetParameterIoctlCodeBufferMethod() == METHOD_BUFFERED &&
590         m_Irp.GetRequestorMode() == UserMode &&
591         m_Irp.GetParameterIoctlOutputBufferLength()== 0 &&
592         (flagsMasked != 0)) {
593 
594         DoTraceLevelMessage(
595             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
596             "Driver that handled WDFREQUEST 0x%p is requesting data to  "
597             " be written back to the UserBuffer by returing a non zero value "
598             " in the Irp 0x%p Information field even though the OutputBufferLength "
599             " is zero", GetObjectHandle(), pIrp);
600 
601         //
602         // We will assert only if the Information field is not zero to warn
603         // the developer that it's a bad thing to do. However, we do avoid
604         // corruption of UserBuffer on completion by clearing the flag
605         // erroneously set by the I/O manager.
606         //
607         if (m_Irp.GetInformation() != 0L) {
608             FxVerifierDbgBreakPoint(pFxDriverGlobals);
609         }
610 
611         //
612         // Clear the flag to prevent the I/O manager from coping the
613         // data back from the SystemBuffer to Irp->UserBuffer
614         //
615         m_Irp.SetFlags(m_Irp.GetFlags() & (~IRP_INPUT_OPERATION));
616     }
617 #endif
618 
619     //
620     // If the status code is one of the framework facility codes,
621     // map it to a standard NTSTATUS
622     //
623 
624 
625     if ((Status & 0x0FFF0000) == (FACILITY_DRIVER_FRAMEWORK << 16)) {
626         DoTraceLevelMessage(
627             pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
628             "Converting WDF NTSTATUS value 0x%x...", Status);
629 
630         switch (Status) {
631         case STATUS_WDF_PAUSED:
632         case STATUS_WDF_BUSY:
633             Status = STATUS_DEVICE_BUSY;
634             break;
635 
636         case STATUS_WDF_INTERNAL_ERROR:
637             Status = STATUS_INTERNAL_ERROR;
638             break;
639 
640         case STATUS_WDF_TOO_FRAGMENTED:
641             Status = STATUS_INVALID_DEVICE_REQUEST;
642             break;
643 
644         default:
645             DoTraceLevelMessage(
646                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
647                 "Unknown WDF NTSTATUS 0x%x", Status);
648             Status = STATUS_INVALID_DEVICE_REQUEST;
649             break;
650         }
651 
652         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
653                             "... to %!STATUS!", Status);
654     }
655 
656     if (IsAllocatedFromIo() == FALSE && IsCanComplete() == FALSE) {
657         FxVerifierDbgBreakPoint(pFxDriverGlobals);
658     }
659 
660     //
661     // It is invalid to complete any requests on an IRPQUEUE
662     //
663     ASSERTMSG("WDFREQUEST is part of a WDFQUEUE, it could be Cancellable\n",
664               (m_IrpQueue == NULL));
665 
666     state = (FxRequestCompletionState) m_CompletionState;
667     queue = m_IoQueue;
668 
669     //
670     // Some I/O request cleanup. Do not do this for driver created requests.
671     //
672     if (IsAllocatedFromIo()) {
673         //
674         // Set the completion state to none
675         //
676         m_CompletionState = FxRequestCompletionStateNone;
677 
678         if (IsReserved() == FALSE) {
679             //
680             // Don't set the Queue to NULL for reserved requests.
681             //
682             m_IoQueue = NULL;
683         }
684     }
685 
686     //
687     // IMPORTANT:  the context must free its references before the request is
688     // completed.  Any of these references could be on a memory interface that is
689     // an embedded interface in this object.  If this reference
690     // is left outstanding when we check m_IrpReferenceCount below, we would
691     // bugcheck (and the driver writer would be unaware of why things are going
692     // wrong).
693     //
694     // Also, if the driver is freeing the referenced mmemory interface in its
695     // cleanup routine, we don't want an oustanding reference against it.
696     //
697     if (m_RequestContext != NULL) {
698         //
699         // m_RequestContext will be freed when the FxRequest's desctructor runs
700         //
701         m_RequestContext->ReleaseAndRestore(this);
702     }
703 
704     //
705     // If the request is not presented to the driver then clear the
706     // cleanup & destroy callbacks before calling PerformEarlyDispose.
707     //
708     if (m_Presented == FALSE) {
709         ClearEvtCallbacks();
710     }
711 
712     if (IsReserved() == FALSE && IsAllocatedFromIo()) {
713         //
714         // Fire the driver supplied Cleanup callback if set
715         //
716         // This will allow the driver to release any IRP specific resources such
717         // as MDLs before we complete the IRP back to the OS, and release the
718         // process/thread reference.
719         //
720         // This is also the callback used to tell the driver the WDM IRP is going
721         // away if it has used the WDM "escape" API's to either get the IRP, or
722         // any resources it references.
723         //
724 
725         //
726         // If a cleanup callback has been registered, we call it
727         // just before completing the IRP to WDM, which can cause any
728         // associated buffers, MDLs, or memory interfaces to be invalidated.
729         //
730         if (EarlyDispose() == FALSE) {
731             VerifierBreakpoint_RequestEarlyDisposeDeferred(GetDriverGlobals());
732         }
733 
734         //
735         // Now that the entire tree is disposed, we want to destroy all of the
736         // children.  This will not put this object in the destroyed state.  For
737         // m_IrpReferenceCount to go to zero, we need to destroy the child WDFMEMORYs
738         // that were created when we probed and locked the buffers.
739         //
740         DestroyChildren();
741     }
742     else {
743         //
744         // We don't call cleanup callback for Reserved Requests.
745         // The driver can perform any cleanp it wants before completing the Request
746         // or before reusing the Reserved Request in its Dispatch callback.
747 
748 
749 
750 
751 
752 
753         DO_NOTHING();
754     }
755 
756     //
757     // If this is non-zero, indicates a reference count problem on any
758     // WDFMEMORY objects returned to the device driver from this WDFREQUEST.
759     //
760     if (m_IrpReferenceCount != 0) {
761         //
762         // NOTE: you cannot call GetBuffer or GetMdl
763         DoTraceLevelMessage(
764             pFxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGREQUEST,
765             "WDFREQUEST 0x%p, PIRP 0x%p, Major Function 0x%x,  completed with "
766             "outstanding references on WDFMEMORY 0x%p or 0x%p retrieved from "
767             "this request",
768             GetObjectHandle(), m_Irp.GetIrp(), m_Irp.GetMajorFunction(),
769             ((m_RequestBaseFlags & FxRequestBaseSystemMdlMapped) ||
770              (m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid)) ?
771                 m_SystemBuffer.GetHandle() : NULL,
772             ((m_RequestBaseFlags & FxRequestBaseOutputMdlMapped) ||
773              (m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid)) ?
774                 m_OutputBuffer.GetHandle() : NULL
775             );
776 
777         if ((m_RequestBaseFlags & FxRequestBaseSystemMdlMapped) ||
778             (m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid)) {
779             DoTraceLevelMessage(
780                 pFxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGREQUEST,
781                 "WDFMEMORY 0x%p, buffer %p, PMDL %p, length %I64d bytes",
782                 m_SystemBuffer.GetHandle(), m_SystemBuffer.GetBuffer(),
783                 m_SystemBuffer.GetMdl(), m_SystemBuffer.GetBufferSize());
784         }
785 
786         if ((m_RequestBaseFlags & FxRequestBaseOutputMdlMapped) ||
787             (m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid)) {
788             DoTraceLevelMessage(
789                 pFxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGREQUEST,
790                 "IOCTL output WDFMEMORY 0x%p, buffer %p, PMDL %p, length %I64d bytes",
791                 m_OutputBuffer.GetHandle(), m_OutputBuffer.GetBuffer(),
792                 m_OutputBuffer.GetMdl(), m_OutputBuffer.GetBufferSize());
793         }
794 
795         FxVerifierBugCheck(pFxDriverGlobals,
796                            WDF_VERIFIER_FATAL_ERROR,
797                            (ULONG_PTR) GetObjectHandle(),
798                            (ULONG_PTR) m_IrpReferenceCount);
799     }
800 
801     FxIrp irp(pIrp);
802 
803     //
804     // Complete the NT IRP through the frameworks FxIrp
805     //
806     irp.SetStatus(Status);
807 
808     ASSERT(IsCancelRoutineSet() == FALSE);
809 
810     //
811     // For driver created requests we need to use two phase
812     // completion (pre and post) to detach the request from the queue before the
813     // IRP is completed, and then allow a new request to be dispatched.
814     // Note that the IRP is actually completed when the reference on this object
815     // goes to 1 (See FxRequest::Release() for more info).
816     //
817     if (IsAllocatedFromIo() == FALSE) {
818         //
819         // Do not touch the request after this call.
820         // Do not clear the request's IRP field before making this call.
821         //
822         PreProcessCompletionForDriverRequest(state, queue);
823     }
824     else {
825         //
826         // We only clear the irp from this object after PerformEarlyDispose has been
827         // called.  m_SystemBuffer and m_OutputBuffer use m_Irp to return their
828         // buffers and their WDFMEMORY handles should be valid in the cleanup routine
829         // for the WDFREQUEST.  We also keep m_Irp valid until after the
830         // m_IrpReferenceCount check, so we can trace out the buffers in case of
831         // error.
832         //
833         m_Irp.SetIrp(NULL);
834 
835         if (irp.GetMajorFunction() == IRP_MJ_CREATE) {
836             //
837             // If this is the last handle to be closed on the device, then the call
838             // to CreateCompleted can cause the device to be deleted if the create
839             // has failed.  We add a reference so that we make sure we have a device
840             // to free the request memory back to.
841             //
842             pRefedDevice = GetDevice();
843             pRefedDevice->ADDREF(&irp);
844 
845             pRefedDevice->m_PkgGeneral->CreateCompleted(&irp);
846         }
847         else {
848             pRefedDevice = NULL;
849         }
850 
851         //
852         // WDM IRP is completed.
853         //
854         irp.CompleteRequest(GetPriorityBoost());
855 
856         if (IsReserved() == FALSE) {
857             PostProcessCompletion(state, queue);
858         }
859         else {
860             PostProcessCompletionForReserved(state, queue);
861         }
862 
863         if (pRefedDevice != NULL) {
864             pRefedDevice->RELEASE(&irp);
865             pRefedDevice = NULL;
866         }
867     }
868 
869     return Status;
870 }
871 
872 
873 VOID
PostProcessCompletion(__in FxRequestCompletionState State,__in FxIoQueue * Queue)874 FxRequest::PostProcessCompletion(
875     __in FxRequestCompletionState State,
876     __in FxIoQueue* Queue
877     )
878 {
879     //
880     // Fire frameworks internal callback event if one is set
881     // (FxIoQueue or IoTarget's internal use)
882     //
883     if (State != FxRequestCompletionStateNone) {
884         //
885         // NOTE: This occurs after the IRP has already been released,
886         //       and is only used for notification that the request
887         //       has completed.
888         //
889         if (State & FxRequestCompletionStateIoPkgFlag) {
890             GetDevice()->m_PkgIo->RequestCompletedCallback(this);
891         }
892         else {
893             ASSERT(Queue != NULL);
894             Queue->RequestCompletedCallback(this);
895             //FxIoQueueToMx::RequestCompletedCallback(Queue, this);
896         }
897 
898         //
899         // DeleteObject will dereference the object reference taken when the callback
900         // was registered
901         //
902         DeleteEarlyDisposedObject();
903     }
904     else {
905         //
906         // Caller still wants the FxRequest class to be valid on return,
907         // but must call DeleteObject in order to ensure the object is
908         // no longer assigned any child objects, etc.
909         //
910         ADDREF(FXREQUEST_COMPLETE_TAG);
911         DeleteObject();
912     }
913 }
914 
915 VOID
PostProcessCompletionForReserved(__in FxRequestCompletionState State,__in FxIoQueue * Queue)916 FxRequest::PostProcessCompletionForReserved(
917     __in FxRequestCompletionState State,
918     __in FxIoQueue* Queue
919     )
920 {
921     //
922     // Fire frameworks internal callback event if one is set
923     // (FxIoQueue or IoTarget's internal use)
924     //
925     if (State != FxRequestCompletionStateNone) {
926         //
927         // NOTE: This occurs after the IRP has already been released,
928         //       and is only used for notification that the request
929         //       has completed.
930         //
931         if (State & FxRequestCompletionStateIoPkgFlag) {
932             GetDevice()->m_PkgIo->RequestCompletedCallback(this);
933         }
934         else {
935             ASSERT(m_IoQueue == Queue);
936             Queue->RequestCompletedCallback(this);
937         }
938     }
939     else {
940         //
941         // Caller still wants the FxRequest class to be valid on return,
942         // but must call DeleteObject in order to ensure the object is
943         // no longer assigned any child objects, etc.
944         //
945         ADDREF(FXREQUEST_COMPLETE_TAG);
946     }
947 
948     RELEASE(FXREQUEST_FWDPRG_TAG);
949 }
950 
951 //
952 // Handles pre-process completion for driver-created-requests queued by the driver.
953 //
954 VOID
PreProcessCompletionForDriverRequest(__in FxRequestCompletionState State,__in FxIoQueue * Queue)955 FxRequest::PreProcessCompletionForDriverRequest(
956     __in FxRequestCompletionState State,
957     __in FxIoQueue* Queue
958     )
959 {
960     ASSERT(State == FxRequestCompletionStateNone ||
961            State == FxRequestCompletionStateQueue);
962     //
963     // Fire frameworks internal callback (pre) event if one is set.
964     //
965     if (FxRequestCompletionStateQueue == State) {
966         //
967         // NOTE: This occurs before the IRP has already been released,
968         //       and is only used to notify the queue to remove this request from this queue's
969         //       internal lists. A second notification (lPostProcessCompletionForAllocatedDriver)
970         //       is made after the IRP is completed.
971         //
972         Queue->PreRequestCompletedCallback(this);
973     }
974     else if (Queue != NULL){
975         //
976         // On return from PostProcessCompletionForDriverRequest, caller (framework)
977         // will try to release the last ref. Increase the ref count so request stays alive until
978         // driver invokes WdfObjectDelete on this request.
979         //
980         ADDREF(FXREQUEST_COMPLETE_TAG);
981     }
982 
983     //
984     // Let the system know that it is OK to complete this request.
985     //
986     RELEASE(FXREQUEST_DCRC_TAG);
987 }
988 
989 //
990 // Handles post-process completion for driver-created-requests queued by the driver.
991 // On return the driver can delete the request with WdfObjectDelete.
992 // NOTE: request may be already gone/reused. Do not dereference this or access any of its
993 // members... its pointer is only used for logging.
994 //
995 VOID
PostProcessCompletionForDriverRequest(__in FxRequestCompletionState State,__in FxIoQueue * Queue)996 FxRequest::PostProcessCompletionForDriverRequest(
997     __in FxRequestCompletionState State,
998     __in FxIoQueue* Queue
999     )
1000 {
1001     //
1002     // NOTE: Do not touch the request object here. The request object may already be
1003     //           re-used or deleted.
1004     //
1005 
1006     ASSERT(State == FxRequestCompletionStateNone ||
1007            State == FxRequestCompletionStateQueue);
1008     //
1009     // Fire frameworks internal callback (post) event if one is set.
1010     //
1011     if (FxRequestCompletionStateQueue == State) {
1012         //
1013         // NOTE: This occurs after the IRP has already been released,  and is only used
1014         //       to notify the queue to update its internal state and if appropriate, send
1015         //       another request.
1016         //
1017         Queue->PostRequestCompletedCallback(this);
1018     }
1019 }
1020 
1021 VOID
FreeRequest(VOID)1022 FxRequest::FreeRequest(
1023     VOID
1024     )
1025 /*++
1026 
1027 Routine Description:
1028 
1029     This routine is called to free a reserved request or in case of Fxpkgio
1030     a non-reserved request.
1031 
1032 --*/
1033 {
1034     //
1035     // Restore any fields if necessary
1036     //
1037     if (m_RequestContext != NULL) {
1038         //
1039         // m_RequestContext will be freed when the FxRequest's destructor runs
1040         //
1041         m_RequestContext->ReleaseAndRestore(this);
1042     }
1043 
1044     //
1045     // If the request is not presented to the driver then clear the
1046     // cleanup & destroy callbacks before calling PerformEarlyDispose.
1047     //
1048     if (m_Presented == FALSE) {
1049         ClearEvtCallbacks();
1050     }
1051 
1052     DeleteObject();
1053 }
1054 
1055 VOID
FX_VF_METHOD(FxRequest,VerifyPreProcessSendAndForget)1056 FX_VF_METHOD(FxRequest, VerifyPreProcessSendAndForget) (
1057     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
1058     )
1059 {
1060     PAGED_CODE_LOCKED();
1061 
1062     if (m_CompletionRoutine.m_Completion != NULL) {
1063         DoTraceLevelMessage(
1064             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
1065             "WDFREQUEST %p cannot send and forget will not execute completion "
1066             "routine %p",
1067             GetHandle(), m_CompletionRoutine.m_Completion);
1068 
1069         FxVerifierDbgBreakPoint(FxDriverGlobals);
1070 
1071 
1072 
1073 
1074 
1075 
1076 
1077 
1078     }
1079 
1080     //
1081     // You cannot fire and forget a create irp if we created a WDFFILEOBJECT
1082     // for it since you must post process the status of the create because
1083     // the create can fail in the driver to which we are sending the irp.
1084     //
1085     if ((m_Irp.GetMajorFunction() == IRP_MJ_CREATE)
1086         &&
1087         (FxFileObjectClassNormalize(GetDevice()->GetFileObjectClass()) !=
1088             WdfFileObjectNotRequired)) {
1089 
1090         DoTraceLevelMessage(
1091             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
1092             "WDFREQUEST %p cannot send and forget a create request which "
1093             "has a WDFFILEOBJECT created for it, it must have a completion "
1094             "routine and be post processsed", GetHandle());
1095 
1096         FxVerifierDbgBreakPoint(FxDriverGlobals);
1097     }
1098 }
1099 
1100 VOID
PreProcessSendAndForget(VOID)1101 FxRequest::PreProcessSendAndForget(
1102     VOID
1103     )
1104 {
1105     VerifyPreProcessSendAndForget(GetDriverGlobals());
1106 
1107     //
1108     // To be sent and forgotten, the irp must have been presented
1109     //
1110     ASSERT(m_Presented);
1111 
1112     //
1113     // To be sent and forgotten, the irp must not have a formatted IO context.
1114     //
1115     ASSERT(HasContext() == FALSE);
1116 
1117     //
1118     // If the driver writer setup the next stack location using the current
1119     // stack location or did a manual IO_STACK_LOCATION copy, we do not want to
1120     // skip the current stack location that their format is used by the target
1121     // driver.
1122     //
1123     if (m_NextStackLocationFormatted == FALSE) {
1124         m_Irp.SkipCurrentIrpStackLocation();
1125     }
1126 
1127     if (IsReserved() == FALSE) {
1128 
1129         //
1130         // If a cleanup callback has been registered, we call it
1131         // just before sending the IRP on its way.  The contract is that the cleanup
1132         // routine for a WDFREQUEST is called while the PIRP is still valid.
1133         //
1134         if (EarlyDispose() == FALSE) {
1135             VerifierBreakpoint_RequestEarlyDisposeDeferred(GetDriverGlobals());
1136         }
1137 
1138         //
1139         // Now that the entire tree is disposed, we want to destroy all of the
1140         // children.  This will not put this object in the destroyed state.  For
1141         // m_IrpReferenceCount to go to zero, we need to destroy the child WDFMEMORYs
1142         // that were created when we probed and locked the buffers.
1143         //
1144         DestroyChildren();
1145     }
1146 }
1147 
1148 VOID
PostProcessSendAndForget(VOID)1149 FxRequest::PostProcessSendAndForget(
1150     VOID
1151     )
1152 {
1153     FxRequestCompletionState state;
1154     FxIoQueue* pQueue;
1155 
1156     m_Irp.SetIrp(NULL);
1157 
1158     //
1159     // Capture the m_IoQueue value before making any other calls.
1160     // Note: m_IoQueue could be NULL if the request is freed before it's queued.
1161     //
1162     pQueue = m_IoQueue;
1163 
1164     ASSERT(m_CompletionState != FxRequestCompletionStateNone);
1165 
1166     state = (FxRequestCompletionState) m_CompletionState;
1167     m_CompletionState = FxRequestCompletionStateNone;
1168 
1169     //
1170     // Technically we did not complete the irp, but a send and forget is
1171     // functionally the same.  We  no longer own the irp.
1172     //
1173     if (IsReserved() == FALSE) {
1174         PostProcessCompletion(state, pQueue);
1175         }
1176         else {
1177             //
1178             // Release checks m_Completed flag to decide whether to return
1179             // the request to reserved pool.
1180             //
1181             m_Completed = TRUE;
1182         PostProcessCompletionForReserved(state, pQueue);
1183     }
1184 }
1185 
1186 NTSTATUS
GetStatus(VOID)1187 FxRequest::GetStatus(
1188     VOID
1189     )
1190 {
1191     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1192     NTSTATUS status;
1193 
1194     pFxDriverGlobals = GetDriverGlobals();
1195 
1196     if (pFxDriverGlobals->FxVerifierIO) {
1197         KIRQL irql;
1198 
1199         Lock(&irql);
1200 
1201 
1202 
1203 
1204 
1205 
1206 
1207 
1208         status = m_Irp.GetStatus();
1209 
1210         Unlock(irql);
1211 
1212         return status;
1213     }
1214     else {
1215         return m_Irp.GetStatus();
1216     }
1217 }
1218 
1219 _Must_inspect_result_
1220 NTSTATUS
GetParameters(__out PWDF_REQUEST_PARAMETERS Parameters)1221 FxRequest::GetParameters(
1222     __out PWDF_REQUEST_PARAMETERS Parameters
1223     )
1224 {
1225     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1226 
1227     pFxDriverGlobals = GetDriverGlobals();
1228 
1229     //
1230     // No lock needed. Only reason this may be invalid is due
1231     // to previous completion, which is a serious driver bug
1232     // that will result in a crash anyway.
1233     //
1234 
1235     if (pFxDriverGlobals->FxVerifierIO) {
1236         KIRQL irql;
1237         NTSTATUS status;
1238 
1239         Lock(&irql);
1240 
1241         status = VerifyRequestIsCurrentStackValid(pFxDriverGlobals);
1242         if (NT_SUCCESS(status)) {
1243             status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
1244         }
1245 
1246         Unlock(irql);
1247 
1248         if (!NT_SUCCESS(status)) {
1249             return status;
1250         }
1251     }
1252 
1253     ASSERT(Parameters->Size >= sizeof(WDF_REQUEST_PARAMETERS));
1254 
1255     // How much we copied
1256     Parameters->Size = sizeof(WDF_REQUEST_PARAMETERS);
1257 
1258 
1259     // Copy parameters
1260     Parameters->Type = (WDF_REQUEST_TYPE)m_Irp.GetMajorFunction();
1261     Parameters->MinorFunction = m_Irp.GetMinorFunction();
1262 
1263     // Copy the Parameters structure which we are a subset of
1264     m_Irp.CopyParameters(Parameters);
1265 
1266     if (pFxDriverGlobals->FxVerifierIO) {
1267         //
1268         // If verifier is on, and the operation is an IRP_MJ_DEVICE_CONTROL
1269         // with METHOD_NEITHER, then set Type3InputBuffer to zero since
1270         // this should not be used to pass parameters in the normal path
1271         //
1272         if((m_Irp.GetMajorFunction() == IRP_MJ_DEVICE_CONTROL) &&
1273             m_Irp.GetParameterIoctlCodeBufferMethod() == METHOD_NEITHER) {
1274             Parameters->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
1275         }
1276     }
1277 
1278     return STATUS_SUCCESS;
1279 }
1280 
1281 
1282 _Must_inspect_result_
1283 NTSTATUS
GetMemoryObject(__deref_out IFxMemory ** MemoryObject,__out PVOID * Buffer,__out size_t * Length)1284 FxRequest::GetMemoryObject(
1285     __deref_out IFxMemory** MemoryObject,
1286     __out PVOID* Buffer,
1287     __out size_t* Length
1288     )
1289 {
1290     PMDL  pMdl;
1291     NTSTATUS status;
1292     ULONG length;
1293     KIRQL irql;
1294     BOOLEAN mapMdl;
1295     UCHAR majorFunction;
1296 
1297     status = STATUS_SUCCESS;
1298     length = 0x0;
1299     mapMdl = FALSE;
1300     irql = PASSIVE_LEVEL;
1301     majorFunction = m_Irp.GetMajorFunction();
1302 
1303 
1304     //
1305     // Verifier
1306     //
1307     if (GetDriverGlobals()->FxVerifierIO) {
1308         status = VerifyRequestIsNotCompleted(GetDriverGlobals());
1309         if (!NT_SUCCESS(status)) {
1310             goto Done;
1311         }
1312         if (m_Irp.GetRequestorMode() == UserMode
1313             &&
1314             (majorFunction == IRP_MJ_WRITE ||
1315              majorFunction == IRP_MJ_READ)
1316             &&
1317             GetDevice()->GetIoType() == WdfDeviceIoNeither) {
1318             status = STATUS_INVALID_DEVICE_REQUEST;
1319 
1320             DoTraceLevelMessage(
1321                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1322                 "Attempt to get UserMode Buffer Pointer for WDFDEVICE 0x%p, "
1323                 "WDFREQUEST 0x%p, %!STATUS!",
1324                 GetDevice()->GetHandle(), GetHandle(), status);
1325 
1326             DoTraceLevelMessage(
1327                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1328                 "Driver must use buffered or direct I/O for this call, or use "
1329                 "WdfDeviceInitSetIoInCallerContextCallback to probe and lock "
1330                 "user mode memory");
1331 
1332             FxVerifierDbgBreakPoint(GetDriverGlobals());
1333         }
1334     }
1335 
1336     if ((m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid) == 0x00) {
1337         Lock(&irql);
1338     }
1339 
1340     //
1341     // We must dig into the IRP to get the buffer, length, and readonly status
1342     //
1343 
1344     switch (majorFunction) {
1345     case IRP_MJ_DEVICE_CONTROL:
1346     case IRP_MJ_INTERNAL_DEVICE_CONTROL:
1347         length = m_Irp.GetParameterIoctlInputBufferLength();
1348 
1349         if (length == 0) {
1350             status = STATUS_BUFFER_TOO_SMALL;
1351 
1352             DoTraceLevelMessage(
1353                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1354                 "WDFREQUEST %p InputBufferLength length is zero, %!STATUS!",
1355                 GetObjectHandle(), status);
1356 
1357             goto Done;
1358         }
1359 
1360         if (m_Irp.GetParameterIoctlCodeBufferMethod() == METHOD_NEITHER) {
1361             //
1362             // Internal device controls are kernel mode to kernel mode, and deal
1363             // with direct unmapped pointers.
1364             //
1365             // In addition, a normal device control with
1366             // RequestorMode == KernelMode is also treated as kernel mode
1367             // to kernel mode since the I/O Manager will not generate requests
1368             // with this setting from a user mode request.
1369             //
1370             if ((m_Irp.GetRequestorMode() == KernelMode) ||
1371                 (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) {
1372                 DO_NOTHING();
1373             }
1374             else {
1375                 status = STATUS_INVALID_DEVICE_REQUEST;
1376 
1377                 DoTraceLevelMessage(
1378                     GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1379                     "Attempt to get UserMode Buffer Pointer for METHOD_NEITHER "
1380                     "DeviceControl 0x%x, WDFDEVICE 0x%p, WDFREQUEST 0x%p, "
1381                     "%!STATUS!",
1382                     m_Irp.GetParameterIoctlCode(),
1383                     GetDevice()->GetHandle(), GetHandle(), status);
1384 
1385                 DoTraceLevelMessage(
1386                     GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1387                     "Driver must use METHOD_BUFFERED or METHOD_xx_DIRECT I/O for "
1388                     "this call, or use WdfDeviceInitSetIoInCallerContextCallback to "
1389                     "probe and lock user mode memory %!STATUS!",
1390                     STATUS_INVALID_DEVICE_REQUEST);
1391 
1392                 goto Done;
1393             }
1394         }
1395         break;
1396 
1397     case IRP_MJ_READ:
1398         length = m_Irp.GetParameterReadLength();
1399 
1400         if (GetDevice()->GetIoTypeForReadWriteBufferAccess() == WdfDeviceIoDirect) {
1401             KMDF_ONLY_CODE_PATH_ASSERT();
1402             mapMdl = TRUE;
1403         }
1404         break;
1405 
1406     case IRP_MJ_WRITE:
1407         length = m_Irp.GetParameterWriteLength();
1408 
1409         if (GetDevice()->GetIoTypeForReadWriteBufferAccess() == WdfDeviceIoDirect) {
1410             KMDF_ONLY_CODE_PATH_ASSERT();
1411             mapMdl = TRUE;
1412         }
1413         break;
1414 
1415     default:
1416         DoTraceLevelMessage(
1417             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1418             "Unrecognized Major Function 0x%x on WDFDEVICE 0x%p WDFREQUEST 0x%p",
1419             majorFunction, GetDevice()->GetHandle(), GetHandle());
1420 
1421         FxVerifierDbgBreakPoint(GetDriverGlobals());
1422 
1423         status = STATUS_INVALID_DEVICE_REQUEST;
1424         goto Done;
1425     }
1426 
1427     if (length == 0) {
1428         status = STATUS_BUFFER_TOO_SMALL;
1429 
1430         DoTraceLevelMessage(
1431             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1432             "WDFREQUEST 0x%p length is zero, %!STATUS!",
1433             GetHandle(), status);
1434 
1435         goto Done;
1436     }
1437 
1438     //
1439     // See if we need to map
1440     //
1441     if (mapMdl && (m_RequestBaseFlags & FxRequestBaseSystemMdlMapped) == 0x00) {
1442         pMdl = m_Irp.GetMdl();
1443 
1444         if (pMdl == NULL) {
1445             //
1446             // Zero length transfer
1447             //
1448             status = STATUS_BUFFER_TOO_SMALL;
1449 
1450             DoTraceLevelMessage(
1451                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1452                 "WDFREQUEST 0x%p, direct io device, PMDL is NULL, "
1453                 "%!STATUS!", GetHandle(), status);
1454 
1455             ASSERT(length == 0);
1456         }
1457         else {
1458             PVOID pVA;
1459 
1460             //
1461             // PagePriority may need to be a property, and/or parameter to
1462             // this call
1463             //
1464             //
1465             // Upon success, MmGetSystemAddressForMdlSafe stores the mapped
1466             // VA pointer in the pMdl and upon subsequent calls to
1467             // MmGetSystemAddressForMdlSafe, no mapping is done, just
1468             // the stored VA is returned.  FxRequestSystemBuffer relies
1469             // on this behavior and, more importantly, relies on this function
1470             // to do the initial mapping so that FxRequestSystemBuffer::GetBuffer()
1471             // will not return a NULL pointer.
1472             //
1473             pVA = Mx::MxGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
1474 
1475             if (pVA == NULL) {
1476                 status = STATUS_INSUFFICIENT_RESOURCES;
1477 
1478                 DoTraceLevelMessage(
1479                     GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1480                     "WDFREQUEST 0x%p could not get a system address for PMDL "
1481                     "0x%p, %!STATUS!", GetHandle(), pMdl, status);
1482             }
1483             else {
1484                 //
1485                 // System will automatically release the mapping PTE's when
1486                 // the MDL is released by the I/O request
1487                 //
1488 
1489 
1490 
1491 
1492 
1493                 m_SystemBuffer.SetMdl(m_Irp.GetMdl());
1494 
1495                 m_RequestBaseFlags |= FxRequestBaseSystemMdlMapped;
1496             }
1497         }
1498     }
1499 
1500 Done:
1501     if ((m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid) == 0x00) {
1502         Unlock(irql);
1503     }
1504 
1505     if (NT_SUCCESS(status)) {
1506         *MemoryObject = &m_SystemBuffer;
1507 
1508         if (mapMdl) {
1509             *Buffer = Mx::MxGetSystemAddressForMdlSafe(m_SystemBuffer.m_Mdl,
1510                                                    NormalPagePriority);
1511         }
1512         else {
1513             *Buffer = m_SystemBuffer.m_Buffer;
1514         }
1515 
1516         *Length = length;
1517     }
1518 
1519     return status;
1520 }
1521 
1522 _Must_inspect_result_
1523 NTSTATUS
GetDeviceControlOutputMemoryObject(__deref_out IFxMemory ** MemoryObject,__out PVOID * Buffer,__out size_t * Length)1524 FxRequest::GetDeviceControlOutputMemoryObject(
1525     __deref_out IFxMemory** MemoryObject,
1526     __out PVOID* Buffer,
1527     __out size_t* Length
1528     )
1529 /*++
1530 
1531 Routine Description:
1532 
1533     Return the IRP_MJ_DEVICE_CONTROL OutputBuffer.
1534 
1535     The memory buffer is valid in any thread/process context,
1536     and may be accessed at IRQL > PASSIVE_LEVEL.
1537 
1538     The memory buffer is automatically released when the request
1539     is completed.
1540 
1541     The memory buffer is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL,
1542     or for any request other than IRP_MJ_DEVICE_CONTROL.
1543 
1544     The Memory buffer is as follows for each buffering mode:
1545 
1546     METHOD_BUFFERED:
1547 
1548         Irp->UserBuffer  // This is actually a system address
1549 
1550     METHOD_IN_DIRECT:
1551 
1552         MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)
1553 
1554     METHOD_OUT_DIRECT:
1555 
1556         MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)
1557 
1558     METHOD_NEITHER:
1559 
1560         NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order
1561         to access the request in the calling threads address space before
1562         it is placed into any I/O Queues.
1563 
1564     The buffer is only valid until the request is completed.
1565 
1566 Arguments:
1567 
1568     MemoryObject - Pointer location to return the memory object interface.
1569 
1570     Buffer - Pointer location to return buffer ptr
1571 
1572     Length - Pointer location to return buffer length.
1573 
1574 Returns:
1575 
1576     NTSTATUS
1577 
1578 --*/
1579 {
1580     size_t length;
1581     NTSTATUS status;
1582     KIRQL irql;
1583     BOOLEAN mapMdl;
1584     UCHAR majorFunction;
1585 
1586     UNREFERENCED_PARAMETER(Buffer);
1587     UNREFERENCED_PARAMETER(Length);
1588 
1589     status = STATUS_SUCCESS;
1590     length = 0;
1591     irql = PASSIVE_LEVEL;
1592     mapMdl = FALSE;
1593 
1594     //
1595     // Verifier
1596     //
1597     if (GetDriverGlobals()->FxVerifierIO ) {
1598         status = VerifyRequestIsNotCompleted(GetDriverGlobals());
1599         if (!NT_SUCCESS(status)) {
1600             return status;
1601         }
1602     }
1603 
1604     if ((m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid) == 0x00) {
1605         Lock(&irql);
1606     }
1607 
1608     //
1609     // See if we already have a validated buffer
1610     //
1611     //if (m_RequestBaseFlags & FxRequestBaseOutputBufferValid) {
1612     //    status = STATUS_SUCCESS;
1613     //}
1614 
1615     majorFunction = m_Irp.GetMajorFunction();
1616 
1617     ASSERT(majorFunction == IRP_MJ_DEVICE_CONTROL ||
1618            majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
1619 
1620     length = m_Irp.GetParameterIoctlOutputBufferLength();
1621 
1622     if (length == 0) {
1623         status = STATUS_BUFFER_TOO_SMALL;
1624 
1625         DoTraceLevelMessage(
1626             GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1627             "WDFREQUEST 0x%p IOCTL output buffer length is zero, %!STATUS!",
1628             GetHandle(), status);
1629 
1630         goto Done;
1631     }
1632 
1633     switch (m_Irp.GetParameterIoctlCodeBufferMethod()) {
1634     //
1635     // InputBuffer is in SystemBuffer
1636     // OutputBuffer is in MdlAddress with read access
1637     //
1638     case METHOD_IN_DIRECT:
1639         //  ||  ||   fall     ||  ||
1640         //  \/  \/   through  \/  \/
1641 
1642     //
1643     // InputBuffer is in SystemBuffer
1644     // OutputBuffer is in MdlAddress with read access
1645     //
1646     case METHOD_OUT_DIRECT:
1647         mapMdl = TRUE;
1648         break;
1649 
1650     case METHOD_NEITHER:
1651         //
1652         // Internal device controls are kernel mode to kernel mode, and deal
1653         // with direct unmapped pointers.
1654         //
1655         // In addition, a normal device control with
1656         // RequestorMode == KernelMode is also treated as kernel mode
1657         // to kernel mode since the I/O Manager will not generate requests
1658         // with this setting from a user mode request.
1659         //
1660         if ((m_Irp.GetRequestorMode() == KernelMode) ||
1661             (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) {
1662             DO_NOTHING();
1663         }
1664         else {
1665             status = STATUS_INVALID_DEVICE_REQUEST;
1666 
1667             DoTraceLevelMessage(
1668                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1669                 "Attempt to get UserMode Buffer Pointer for "
1670                 "METHOD_NEITHER DeviceControl 0x%x, WDFDEVICE 0x%p, "
1671                 "WDFREQUEST 0x%p, %!STATUS!",
1672                 m_Irp.GetParameterIoctlCode(),
1673                 GetDevice()->GetHandle(), GetObjectHandle(), status);
1674 
1675             DoTraceLevelMessage(
1676                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1677                 "Driver must use METHOD_BUFFERED or METHOD_xx_DIRECT "
1678                 "I/O for this call, or use "
1679                 "WdfDeviceInitSetIoInCallerContextCallback to probe and "
1680                 "lock user mode memory");
1681         }
1682         break;
1683     }
1684 
1685     if (mapMdl && (m_RequestBaseFlags & FxRequestBaseOutputMdlMapped) == 0x0) {
1686         PMDL pMdl;
1687         PVOID pVA;
1688 
1689 
1690         pMdl = m_Irp.GetMdl();
1691 
1692         if (pMdl == NULL) {
1693             //
1694             // Zero length transfer
1695             //
1696             status = STATUS_BUFFER_TOO_SMALL;
1697 
1698             DoTraceLevelMessage(
1699                 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1700                 "WDFREQUEST 0x%p, METHOD_IN_DIRECT IOCTL PMDL is NULL, "
1701                 "%!STATUS!", GetHandle(), status);
1702 
1703             ASSERT(
1704                 m_Irp.GetParameterIoctlOutputBufferLength()== 0
1705                 );
1706         }
1707         else {
1708             //
1709             // PagePriority may need to be a property, and/or parameter to
1710             // this call
1711             //
1712             //
1713             // Upon success, MmGetSystemAddressForMdlSafe stores the mapped
1714             // VA pointer in the pMdl and upon subsequent calls to
1715             // MmGetSystemAddressForMdlSafe, no mapping is done, just
1716             // the stored VA is returned.  FxRequestOutputBuffer relies
1717             // on this behavior and, more importantly, relies on this function
1718             // to do the initial mapping so that FxRequestOutputBuffer::GetBuffer()
1719             // will not return a NULL pointer.
1720             //
1721             pVA = Mx::MxGetSystemAddressForMdlSafe(pMdl, NormalPagePriority);
1722 
1723             if (pVA == NULL) {
1724                 status =  STATUS_INSUFFICIENT_RESOURCES;
1725 
1726                 DoTraceLevelMessage(
1727                     GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1728                     "WDFREQUEST 0x%p could not get a system address for PMDL"
1729                     "0x%p, %!STATUS!", GetHandle(), pMdl, status);
1730             }
1731             else {
1732                 m_OutputBuffer.SetMdl(pMdl);
1733                 m_RequestBaseFlags |= FxRequestBaseOutputMdlMapped;
1734                 status = STATUS_SUCCESS;
1735             }
1736         }
1737     }
1738 
1739 Done:
1740     if ((m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid) == 0x00) {
1741         Unlock(irql);
1742     }
1743 
1744     if (NT_SUCCESS(status)) {
1745         *MemoryObject = &m_OutputBuffer;
1746         if (mapMdl) {
1747             *Buffer = Mx::MxGetSystemAddressForMdlSafe(m_OutputBuffer.m_Mdl,
1748                                                    NormalPagePriority);
1749         }
1750         else {
1751             *Buffer = m_OutputBuffer.m_Buffer;
1752         }
1753         *Length = length;
1754     }
1755 
1756     return status;
1757 }
1758 
1759 FxRequestCompletionState
SetCompletionState(__in FxRequestCompletionState NewState)1760 FxRequest::SetCompletionState(
1761     __in FxRequestCompletionState NewState
1762     )
1763 {
1764     FxRequestCompletionState oldState;
1765 
1766     //
1767     // The flag by itself should never be specified
1768     //
1769     ASSERT(NewState != FxRequestCompletionStateIoPkgFlag);
1770 
1771     //
1772     // No need to lock. Only the "owner" can set the completion
1773     // callback function, and this is when under the general
1774     // FxIoQueue lock.
1775     //
1776 
1777     // Request is already completed, awaiting final dereference
1778     if (m_Completed) {
1779         oldState = FxRequestCompletionStateNone;
1780         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
1781                             "WDFREQUEST 0x%p has already been completed",
1782                             GetHandle());
1783         FxVerifierDbgBreakPoint(GetDriverGlobals());
1784     }
1785     else {
1786         ASSERT(m_Irp.GetIrp() != NULL);
1787 
1788         oldState = (FxRequestCompletionState) m_CompletionState;
1789 
1790         m_CompletionState = (BYTE) NewState;
1791 
1792         if (NewState == FxRequestCompletionStateNone &&
1793             oldState != FxRequestCompletionStateNone) {
1794             //
1795             // Cancelling a callback, so release the callback reference
1796             //
1797             RELEASE(FXREQUEST_STATE_TAG);
1798         }
1799         else if (NewState != FxRequestCompletionStateNone &&
1800                  oldState == FxRequestCompletionStateNone) {
1801             //
1802             // Adding a callback requires a reference
1803             //
1804             ADDREF(FXREQUEST_STATE_TAG);
1805         }
1806         else {
1807             //
1808             // else we leave the current reference alone
1809             //
1810             DO_NOTHING();
1811         }
1812     }
1813 
1814     return oldState;
1815 }
1816 
1817 _Must_inspect_result_
1818 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyInsertIrpQueue)1819 FX_VF_METHOD(FxRequest, VerifyInsertIrpQueue) (
1820     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
1821     _In_ FxIrpQueue* IrpQueue
1822     )
1823 {
1824     NTSTATUS status;
1825 
1826     PAGED_CODE_LOCKED();
1827 
1828     //
1829     // Check to make sure we are not already in an Irp queue
1830     //
1831     if (m_IrpQueue != NULL) {
1832         status = STATUS_INTERNAL_ERROR;
1833 
1834         DoTraceLevelMessage(
1835             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
1836             "Already in FxIrpQueue 0x%p WDFREQUEST 0x%p %!STATUS!",
1837             IrpQueue, GetHandle(), status);
1838 
1839         FxVerifierDbgBreakPoint(FxDriverGlobals);
1840 
1841         goto Done;
1842     }
1843 
1844     //
1845     // If request is completed, fail.
1846     // This is because the driver can complete the request
1847     // right away in another thread while returning STATUS_PENDING
1848     // from EvtIoDefault
1849     //
1850     status = VerifyRequestIsNotCompleted(FxDriverGlobals);
1851 
1852 Done:
1853     return status;
1854 }
1855 
1856 _Must_inspect_result_
1857 NTSTATUS
InsertTailIrpQueue(__in FxIrpQueue * IrpQueue,__out_opt ULONG * pRequestCount)1858 FxRequest::InsertTailIrpQueue(
1859     __in FxIrpQueue* IrpQueue,
1860     __out_opt ULONG*      pRequestCount
1861     )
1862 {
1863     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1864     NTSTATUS status;
1865 
1866     pFxDriverGlobals = GetDriverGlobals();
1867 
1868     // No locking required since only one accessor till inserted on queue
1869 
1870     status = VerifyInsertIrpQueue(pFxDriverGlobals, IrpQueue);
1871     if (!NT_SUCCESS(status)) {
1872         return status;
1873     }
1874 
1875     //
1876     // If a request is on an IrpQueue, it must be referenced
1877     //
1878 
1879 
1880 
1881 
1882 
1883 
1884     ADDREF(FXREQUEST_QUEUE_TAG);
1885 
1886     ASSERT(m_Completed == FALSE);
1887     ASSERT(m_IrpQueue == NULL);
1888 
1889     m_IrpQueue = IrpQueue;
1890 
1891     status = IrpQueue->InsertTailRequest(m_Irp.GetIrp(),
1892                                          &m_CsqContext,
1893                                          pRequestCount);
1894 
1895     //
1896     // If this insert failed, we must release the extra reference we took
1897     //
1898     if (!NT_SUCCESS(status)) {
1899         MarkRemovedFromIrpQueue();
1900         RELEASE(FXREQUEST_QUEUE_TAG);
1901     }
1902 
1903     return status;
1904 }
1905 
1906 _Must_inspect_result_
1907 NTSTATUS
InsertHeadIrpQueue(__in FxIrpQueue * IrpQueue,__out_opt ULONG * pRequestCount)1908 FxRequest::InsertHeadIrpQueue(
1909     __in FxIrpQueue* IrpQueue,
1910     __out_opt ULONG*      pRequestCount
1911     )
1912 {
1913     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1914     NTSTATUS status;
1915 
1916     pFxDriverGlobals = GetDriverGlobals();
1917 
1918     // No locking required since only one accessor till inserted on queue
1919 
1920     status = VerifyInsertIrpQueue(pFxDriverGlobals, IrpQueue);
1921     if (!NT_SUCCESS(status)) {
1922         return status;
1923     }
1924 
1925     //
1926     // If a request is on an IrpQueue, it must be referenced
1927     //
1928 
1929 
1930 
1931 
1932 
1933 
1934     ADDREF(FXREQUEST_QUEUE_TAG);
1935 
1936     ASSERT(m_Completed == FALSE);
1937     ASSERT(m_IrpQueue == NULL);
1938 
1939     m_IrpQueue = IrpQueue;
1940 
1941     status = IrpQueue->InsertHeadRequest(m_Irp.GetIrp(),
1942                                          &m_CsqContext,
1943                                          pRequestCount);
1944 
1945     //
1946     // If this insert failed, we must release the extra reference we took
1947     //
1948     if (!NT_SUCCESS(status)) {
1949         MarkRemovedFromIrpQueue();
1950         RELEASE(FXREQUEST_QUEUE_TAG);
1951     }
1952 
1953     return status;
1954 }
1955 
1956 //
1957 // Remove request from its IRP queue
1958 //
1959 _Must_inspect_result_
1960 NTSTATUS
RemoveFromIrpQueue(__in FxIrpQueue * IrpQueue)1961 FxRequest::RemoveFromIrpQueue(
1962     __in FxIrpQueue* IrpQueue
1963     )
1964 {
1965     PFX_DRIVER_GLOBALS pFxDriverGlobals;
1966     MdIrp pIrp;
1967 
1968     pFxDriverGlobals = GetDriverGlobals();
1969 
1970     //
1971     // Cancel Safe Queues allow this request
1972     // removal to be race free even if the
1973     // request has been cancelled already.
1974     //
1975     // It signals this by returning NULL for
1976     // the Irp.
1977     //
1978     pIrp = IrpQueue->RemoveRequest(&m_CsqContext);
1979 
1980     if (pIrp == NULL) {
1981 
1982         //
1983         // Cancel routine removed it from the cancel
1984         // safe queue.
1985         //
1986         // The cancel handler will remove this reference
1987         // in FxIoQueue::_IrpCancelForDriver /
1988         // FxIrpQueue::_WdmCancelRoutineInternal
1989         //
1990 
1991         return STATUS_CANCELLED;
1992     }
1993     else {
1994 
1995         //
1996         // We retrieved the Irp from the cancel safe queue
1997         // without it having been cancelled first.
1998         //
1999         // It is no longer cancelable
2000         //
2001         if (pFxDriverGlobals->FxVerifierOn) {
2002             if (m_IrpQueue == NULL) {
2003                 DoTraceLevelMessage(
2004                     pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2005                     "WDFREQUEST 0x%p not on IrpQueue",
2006                     GetHandle());
2007 
2008                 FxVerifierDbgBreakPoint(pFxDriverGlobals);
2009             }
2010         }
2011 
2012         MarkRemovedFromIrpQueue();
2013 
2014         RELEASE(FXREQUEST_QUEUE_TAG);
2015 
2016         return STATUS_SUCCESS;
2017     }
2018 }
2019 
2020 //
2021 // Function to return the next FxRequest from an FxIrpQueue
2022 //
2023 _Must_inspect_result_
2024 FxRequest*
GetNextRequest(__in FxIrpQueue * IrpQueue)2025 FxRequest::GetNextRequest(
2026     __in FxIrpQueue*  IrpQueue
2027     )
2028 {
2029     MdIrp pIrp;
2030     FxRequest* pRequest;
2031     PMdIoCsqIrpContext pCsqContext;
2032 
2033     pIrp = IrpQueue->GetNextRequest(&pCsqContext);
2034 
2035     if (pIrp == NULL) {
2036         return NULL;
2037     }
2038 
2039     // Irp is not cancellable now
2040     pRequest = FxRequest::RetrieveFromCsqContext(pCsqContext);
2041 
2042     // Must tell the request it's off the queue
2043     pRequest->MarkRemovedFromIrpQueue();
2044 
2045     // Remove reference placed when on IrpQueue
2046     pRequest->RELEASE(FXREQUEST_QUEUE_TAG);
2047 
2048     return pRequest;
2049 }
2050 
2051 //
2052 // Function to return an FxRequest from an FxIrpQueue based
2053 // on optional context and/or file object.
2054 //
2055 _Must_inspect_result_
2056 NTSTATUS
GetNextRequest(__in FxIrpQueue * IrpQueue,__in_opt MdFileObject FileObject,__in_opt FxRequest * TagRequest,__deref_out FxRequest ** ppOutRequest)2057 FxRequest::GetNextRequest(
2058     __in FxIrpQueue*  IrpQueue,
2059     __in_opt MdFileObject FileObject,
2060     __in_opt FxRequest*   TagRequest,
2061     __deref_out FxRequest** ppOutRequest
2062     )
2063 {
2064     NTSTATUS Status;
2065     FxRequest* pRequest;
2066     PMdIoCsqIrpContext TagCsqContext;
2067 
2068     if( TagRequest != NULL ) {
2069         TagCsqContext = TagRequest->GetCsqContext();
2070     }
2071     else {
2072         TagCsqContext = NULL;
2073     }
2074 
2075     Status = IrpQueue->GetNextRequest( TagCsqContext, FileObject, &pRequest );
2076     if( !NT_SUCCESS(Status) ) {
2077         return Status;
2078     }
2079 
2080     // Irp is not cancellable now
2081 
2082     // Must tell the request its off the queue
2083     pRequest->MarkRemovedFromIrpQueue();
2084 
2085     // Remove reference placed when on IrpQueue
2086     pRequest->RELEASE(FXREQUEST_QUEUE_TAG);
2087 
2088     *ppOutRequest = pRequest;
2089 
2090     return STATUS_SUCCESS;
2091 }
2092 
2093 //
2094 // Allow peeking at requests in the IrpQueue
2095 //
2096 _Must_inspect_result_
2097 NTSTATUS
PeekRequest(__in FxIrpQueue * IrpQueue,__in_opt FxRequest * TagRequest,__in_opt MdFileObject FileObject,__out_opt PWDF_REQUEST_PARAMETERS Parameters,__deref_out FxRequest ** ppOutRequest)2098 FxRequest::PeekRequest(
2099     __in FxIrpQueue*          IrpQueue,
2100     __in_opt FxRequest*           TagRequest,
2101     __in_opt MdFileObject         FileObject,
2102     __out_opt PWDF_REQUEST_PARAMETERS Parameters,
2103     __deref_out FxRequest**         ppOutRequest
2104     )
2105 {
2106     NTSTATUS Status;
2107 
2108     PMdIoCsqIrpContext TagContext = NULL;
2109 
2110     //
2111     // IrpQueue::PeekRequest works with CSQ_CONTEXT
2112     // structures since this is the only value that
2113     // is valid across cancellation.
2114     //
2115     if( TagRequest != NULL ) {
2116         TagContext = TagRequest->GetCsqContext();
2117     }
2118 
2119     Status = IrpQueue->PeekRequest(
2120                            TagContext,
2121                            FileObject,
2122                            ppOutRequest
2123                            );
2124     if(NT_SUCCESS(Status)) {
2125 
2126         if( Parameters != NULL ) {
2127             Status = (*ppOutRequest)->GetParameters(Parameters);
2128         }
2129     }
2130 
2131     return Status;
2132 }
2133 
2134 _Must_inspect_result_
2135 NTSTATUS
Reuse(__in PWDF_REQUEST_REUSE_PARAMS ReuseParams)2136 FxRequest::Reuse(
2137     __in PWDF_REQUEST_REUSE_PARAMS ReuseParams
2138     )
2139 {
2140     FxIrp               currentIrp;
2141     PFX_DRIVER_GLOBALS  pFxDriverGlobals = GetDriverGlobals();
2142 
2143     //
2144     // Make sure request is not pended in IoTarget.
2145     //
2146     if (pFxDriverGlobals->IsVerificationEnabled(1, 9, OkForDownLevel)) {
2147         SHORT flags;
2148         KIRQL irql;
2149 
2150         Lock(&irql);
2151         flags = GetVerifierFlagsLocked();
2152         if (flags & FXREQUEST_FLAG_SENT_TO_TARGET) {
2153             DoTraceLevelMessage(
2154                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2155                 "Driver is trying to reuse WDFREQUEST 0x%p while it is still "
2156                 "active on WDFIOTARGET 0x%p. ",
2157                 GetTraceObjectHandle(), GetTarget()->GetHandle());
2158             FxVerifierDbgBreakPoint(pFxDriverGlobals);
2159         }
2160         Unlock(irql);
2161     }
2162 
2163     //
2164     // For drivers 1.9 and above (for maintaining backwards compatibility)
2165     // deregister previously registered completion routine.
2166     //
2167     if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) {
2168        SetCompletionRoutine(NULL, NULL);
2169     }
2170 
2171     currentIrp.SetIrp(m_Irp.GetIrp());
2172 
2173     if (currentIrp.GetIrp() != NULL) {
2174         //
2175         // Release all outstanding references and restore original fields in
2176         // the PIRP
2177         //
2178         if (m_RequestContext != NULL) {
2179             m_RequestContext->ReleaseAndRestore(this);
2180         }
2181 
2182         if (m_IrpAllocation == REQUEST_ALLOCATED_FROM_IO) {
2183             //
2184             // An irp presented by io queue can only reset a limited state
2185             //
2186             if (ReuseParams->Flags & WDF_REQUEST_REUSE_SET_NEW_IRP) {
2187                 //
2188                 // Not allowed to set a new irp
2189                 //
2190                 return STATUS_WDF_REQUEST_INVALID_STATE;
2191             }
2192 
2193 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
2194             currentIrp.SetStatus(ReuseParams->Status);
2195             currentIrp.SetCancel(FALSE);
2196 #else
2197             //
2198             // For UMDF, host sets cancel flag to false as part of Reuse(), so no
2199             // need to have a separate call for UMDF (that's why host irp doesn't
2200             // expose any interface to set this independently).
2201 
2202 
2203 
2204 
2205             //
2206             currentIrp.Reuse(ReuseParams->Status);
2207 #endif
2208             m_Completed = FALSE;
2209             m_Canceled = FALSE;
2210 
2211             return STATUS_SUCCESS;
2212         }
2213         else if (m_IrpAllocation == REQUEST_ALLOCATED_DRIVER) {
2214             //
2215             // Release outstanding reference on a must complete driver request.
2216             //
2217             if (m_CanComplete && m_Completed == FALSE) {
2218                 ASSERT(GetRefCnt() >= 2);
2219 
2220                 if (pFxDriverGlobals->FxVerifierOn) {
2221                     ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED);
2222                 }
2223 
2224                 RELEASE(FXREQUEST_DCRC_TAG);
2225             }
2226         }
2227     }
2228     else {
2229         //
2230         // We should not have a m_RequestContext with anything to ReleaseAndRestore
2231         // because there is no IRP to have anything formatted off of.
2232         //
2233         DO_NOTHING();
2234     }
2235 
2236     //
2237     // This cannot be a request on a queue
2238     //
2239     ASSERT(m_CompletionState == FxRequestCompletionStateNone &&
2240            m_IoQueue == NULL);
2241 
2242     if (ReuseParams->Flags & WDF_REQUEST_REUSE_SET_NEW_IRP) {
2243         currentIrp.SetIrp((MdIrp)ReuseParams->NewIrp);
2244 
2245         //
2246         // If we are replacing an internal irp, we must free it later.
2247         //
2248         if (m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) {
2249             MdIrp pOldIrp;
2250 
2251             ASSERT(m_CanComplete == FALSE);
2252             pOldIrp = m_Irp.SetIrp(currentIrp.GetIrp());
2253 
2254             if (pOldIrp != NULL) {
2255                 FxIrp oldIrp(pOldIrp);
2256                 oldIrp.FreeIrp();
2257             }
2258         }
2259         else {
2260             (void) m_Irp.SetIrp(currentIrp.GetIrp());
2261         }
2262 
2263         m_IrpAllocation = REQUEST_ALLOCATED_DRIVER;
2264     }
2265 
2266     //
2267     // Only reinitialize an internal irp.  If the irp is external, then its
2268     // still valid.
2269     //
2270     if (m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL && currentIrp.GetIrp() != NULL) {
2271         ASSERT(m_CanComplete == FALSE);
2272         ASSERT(m_Completed == FALSE);
2273         currentIrp.Reuse(ReuseParams->Status);
2274 
2275         //
2276         // For UMDF, host sets cancel flag to false as part of Reuse(), so no
2277         // need to have a separate call for UMDF (that's why host irp doesn't
2278         // expose any interface to set this independently).
2279 
2280 
2281 
2282 
2283         //
2284 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
2285         currentIrp.SetCancel(FALSE);
2286 #endif
2287     }
2288 
2289     //
2290     // If necessary, reinit the request to support WdfRequestComplete.
2291     //
2292     if (ReuseParams->Flags & WDF_REQUEST_REUSE_MUST_COMPLETE) {
2293         NTSTATUS status;
2294 
2295         //
2296         // WDF guarantees a successful return code when the driver calls Reuse() from its
2297         // completion routine with valid input.
2298         //
2299 
2300         //
2301         // This feature can only be used from WDF v1.11 and above.
2302         //
2303         if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) {
2304             status = STATUS_INVALID_DEVICE_REQUEST;
2305             DoTraceLevelMessage(
2306                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2307                 "WDFREQUEST %p doesn't belong to any queue, %!STATUS!",
2308                 GetTraceObjectHandle(), status);
2309             FxVerifierDbgBreakPoint(pFxDriverGlobals);
2310             return status;
2311         }
2312 
2313         //
2314         // 'must_complete' flag requires an IRP.
2315         //
2316         if (currentIrp.GetIrp() == NULL) {
2317             status = STATUS_INVALID_PARAMETER;
2318             DoTraceLevelMessage(
2319                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2320                 "Driver is trying to reuse WDFREQUEST 0x%p without "
2321                 "specifying an IRP with "
2322                 "WDF_REQUEST_REUSE_MUST_COMPLETE flag, %!STATUS!",
2323                 GetTraceObjectHandle(), status);
2324             FxVerifierDbgBreakPoint(pFxDriverGlobals);
2325             return status;
2326         }
2327 
2328         //
2329         // Do not support internal IRPs.
2330         //
2331         if (m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) {
2332             status = STATUS_INVALID_DEVICE_REQUEST;
2333             DoTraceLevelMessage(
2334                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2335                 "Driver is trying to reuse WDFREQUEST 0x%p holding an"
2336                 "internal allocated IRP with "
2337                 "WDF_REQUEST_REUSE_MUST_COMPLETE flag, %!STATUS!",
2338                 GetTraceObjectHandle(), status);
2339             FxVerifierDbgBreakPoint(pFxDriverGlobals);
2340             return status;
2341         }
2342 
2343         //
2344         // Ref count must be 1.
2345         //
2346         if (GetRefCnt() != 1) {
2347             status = STATUS_INVALID_DEVICE_REQUEST;
2348             DoTraceLevelMessage(
2349                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2350                 "Driver is trying to reuse WDFREQUEST 0x%p with "
2351                 "WDF_REQUEST_REUSE_MUST_COMPLETE flag while request is "
2352                 "being referenced, reference count:%d, %!STATUS!",
2353                 GetTraceObjectHandle(), GetRefCnt(), status);
2354             FxVerifierDbgBreakPoint(pFxDriverGlobals);
2355             return status;
2356         }
2357 
2358         //
2359         // Make sure current IRP stack location is valid.
2360         //
2361         if (currentIrp.IsCurrentIrpStackLocationValid() == FALSE) {
2362             status =  STATUS_INVALID_DEVICE_REQUEST;
2363             DoTraceLevelMessage(
2364                 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2365                 "IRP %p of WDFREQUEST %p doesn't have a valid"
2366                 " stack location, %!STATUS!",
2367                 currentIrp.GetIrp(), GetHandle(), status);
2368             FxVerifierDbgBreakPoint(pFxDriverGlobals);
2369             return status;
2370         }
2371 
2372         //
2373         // This ref is removed when:
2374         //   (a) the request is completed or
2375         //   (b) the request is reused and old request/IRP was never sent and completed.
2376         //
2377         ADDREF(FXREQUEST_DCRC_TAG);
2378 
2379         //
2380         // Note: strange why ClearFieldsForReuse() is not used all the time...  just in case,
2381         // keeping old logic for compatibility.
2382         //
2383         ClearFieldsForReuse();
2384         m_CanComplete = TRUE;
2385 
2386         if (pFxDriverGlobals->FxVerifierOn) {
2387             SetVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED);
2388         }
2389     }
2390     else {
2391         m_CanComplete = FALSE;
2392         m_Completed = FALSE;
2393         m_Canceled = FALSE;
2394 
2395         if (pFxDriverGlobals->FxVerifierOn) {
2396             ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED);
2397         }
2398     }
2399 
2400     return STATUS_SUCCESS;
2401 }
2402 
2403 //
2404 // Return the FxFileObject if associated with this request
2405 //
2406 _Must_inspect_result_
2407 NTSTATUS
GetFileObject(__deref_out_opt FxFileObject ** FileObject)2408 FxRequest::GetFileObject(
2409     __deref_out_opt FxFileObject** FileObject
2410     )
2411 {
2412     NTSTATUS status;
2413     FxFileObject* pFileObject;
2414     CfxDevice* pDevice;
2415     PFX_DRIVER_GLOBALS pFxDriverGlobals;
2416 
2417     pFileObject = NULL;
2418     pFxDriverGlobals = GetDriverGlobals();
2419 
2420     pDevice = GetDevice();
2421 
2422     if (pFxDriverGlobals->FxVerifierIO) {
2423         KIRQL irql;
2424         *FileObject = NULL;
2425 
2426         Lock(&irql);
2427         status = VerifyRequestIsNotCompleted(pFxDriverGlobals);
2428 
2429         Unlock(irql);
2430         if (!NT_SUCCESS(status)) {
2431             return status;
2432         }
2433 
2434     }
2435 
2436     if (NULL == m_Irp.GetFileObject() && IsAllocatedDriver()) {
2437         ASSERT(TRUE == m_CanComplete);
2438         //
2439         // This is a 'must_complete' driver created request.
2440         //
2441         *FileObject = NULL;
2442         return STATUS_SUCCESS;
2443     }
2444 
2445     status = FxFileObject::_GetFileObjectFromWdm(
2446         pDevice,
2447         pDevice->GetFileObjectClass(),
2448         m_Irp.GetFileObject(),
2449         &pFileObject
2450         );
2451 
2452     if (NT_SUCCESS(status) && pFileObject != NULL) {
2453         *FileObject = pFileObject;
2454         return STATUS_SUCCESS;
2455     }
2456     else if (NT_SUCCESS(status) &&
2457              FxIsFileObjectOptional(pDevice->GetFileObjectClass())) {
2458         //
2459         // Driver told us that it is ok for the file object to be NULL.
2460         //
2461         *FileObject = NULL;
2462         return STATUS_SUCCESS;
2463     }
2464     else {
2465         return STATUS_INVALID_DEVICE_REQUEST;
2466     }
2467 }
2468 
2469 VOID
AddIrpReference(VOID)2470 FxRequest::AddIrpReference(
2471     VOID
2472     )
2473 /*++
2474 
2475 Routine Description:
2476 
2477     Adds a reference to the IRP contained in the request.
2478 
2479     This is used to check that FxRequest::Complete is not
2480     called with outstanding references to any IRP related
2481     fields such as memory buffers.
2482 
2483 Arguments:
2484 
2485     None
2486 
2487 Return Value:
2488 
2489     None
2490 
2491 --*/
2492 {
2493     PFX_DRIVER_GLOBALS pFxDriverGlobals;
2494     pFxDriverGlobals = GetDriverGlobals();
2495 
2496     if (pFxDriverGlobals->FxVerifierOn) {
2497         KIRQL irql;
2498 
2499         Lock(&irql);
2500 
2501         (VOID)VerifyRequestIsNotCompleted(pFxDriverGlobals);
2502 
2503         Unlock(irql);
2504     }
2505 
2506     InterlockedIncrement(&m_IrpReferenceCount);
2507 
2508     return;
2509 }
2510 
2511 VOID
ReleaseIrpReference(VOID)2512 FxRequest::ReleaseIrpReference(
2513     VOID
2514     )
2515 /*++
2516 
2517 Routine Description:
2518 
2519     Release a reference to the IRP contained in the request.
2520 
2521 Arguments:
2522 
2523     None
2524 
2525 Return Value:
2526 
2527     None
2528 
2529 --*/
2530 {
2531     LONG count;
2532 
2533     count = InterlockedDecrement(&m_IrpReferenceCount);
2534 
2535     if( count < 0 ) {
2536         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST,
2537                             "Attempt to release an IRP reference without adding "
2538                             "one first WDFREQUEST 0x%p",GetHandle());
2539         FxVerifierDbgBreakPoint(GetDriverGlobals());
2540     }
2541 
2542     return;
2543 }
2544 
2545 _Must_inspect_result_
2546 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyProbeAndLock)2547 FX_VF_METHOD(FxRequest, VerifyProbeAndLock) (
2548     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2549     )
2550 {
2551     NTSTATUS status = STATUS_SUCCESS;
2552 
2553     PAGED_CODE_LOCKED();
2554 
2555     MdEThread thread = m_Irp.GetThread();
2556 
2557     //
2558     // Some kernel mode drivers issue I/O without setting this
2559     //
2560     if (thread != NULL) {
2561         //
2562         // Currently DDK level headers don't let us reach into a threads
2563         // parent process, so we can't do the process level check, just
2564         // a thread level check.
2565         //
2566         if (m_Irp.GetRequestorMode() == UserMode && thread != Mx::GetCurrentEThread()) {
2567             status = STATUS_ACCESS_VIOLATION;
2568 
2569             // Error, wrong process context...
2570             DoTraceLevelMessage(
2571                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2572                 "Attempt to access user mode memory from the wrong process "
2573                 "Irp->Tail.Overlay.Thread 0x%p, PsGetCurrentThread 0x%p, "
2574                 "%!STATUS!", thread, Mx::GetCurrentEThread(), status);
2575 
2576             return status;
2577         }
2578     }
2579     else {
2580         // Irp->Thread should be issued for all user mode requests
2581         ASSERT(m_Irp.GetRequestorMode() == KernelMode);
2582     }
2583 
2584     return status;
2585 }
2586 
2587 _Must_inspect_result_
2588 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyStopAcknowledge)2589 FX_VF_METHOD(FxRequest, VerifyStopAcknowledge) (
2590     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals,
2591     _In_ BOOLEAN Requeue
2592     )
2593 {
2594     NTSTATUS status;
2595     KIRQL irql;
2596 
2597     PAGED_CODE_LOCKED();
2598 
2599     Lock(&irql);
2600 
2601     //
2602     // Make sure the driver is calling this function in the context
2603     // of EvtIoStop callback.
2604     //
2605     status = VerifyRequestIsInEvtIoStopContext(FxDriverGlobals);
2606     if (!NT_SUCCESS(status)) {
2607         goto Done;
2608     }
2609 
2610     if (m_Completed == FALSE && Requeue) {
2611 
2612         // Make sure the driver owns the request
2613 
2614         status = VerifyRequestIsDriverOwned(FxDriverGlobals);
2615         if (!NT_SUCCESS(status)) {
2616             goto Done;
2617         }
2618 
2619         //
2620         // Can't re-enqueue a cancelable request
2621         //
2622         status = VerifyRequestIsNotCancelable(FxDriverGlobals);
2623         if (!NT_SUCCESS(status)) {
2624             goto Done;
2625         }
2626     }
2627 
2628 Done:
2629     Unlock(irql);
2630     return status;
2631 }
2632 
2633 VOID
StopAcknowledge(__in BOOLEAN Requeue)2634 FxRequest::StopAcknowledge(
2635     __in BOOLEAN Requeue
2636     )
2637 /*++
2638 
2639 Routine Description:
2640 
2641     This routine saves the acknowledgement in the request object
2642     which will be looked at and processed later by the queue
2643     dispatch event loop
2644 
2645 Arguments:
2646 
2647     Requeue - if TRUE, put the request back into the head
2648               of queue from which it was delivered to the driver.
2649 Return Value:
2650 
2651     None
2652 
2653 --*/
2654 {
2655     NTSTATUS status;
2656 
2657     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
2658 
2659     status = VerifyStopAcknowledge(FxDriverGlobals, Requeue);
2660     if(!NT_SUCCESS(status)) {
2661         return;
2662     }
2663 
2664     if (Requeue) {
2665         m_PowerStopState = FxRequestPowerStopAcknowledgedWithRequeue;
2666     }
2667     else {
2668         m_PowerStopState = FxRequestPowerStopAcknowledged;
2669     }
2670 
2671     return;
2672 }
2673 
2674 ULONG
AddRefOverride(__in WDFOBJECT_OFFSET Offset,__in PVOID Tag,__in LONG Line,__in_opt PSTR File)2675 FxRequest::AddRefOverride(
2676     __in WDFOBJECT_OFFSET Offset,
2677     __in PVOID Tag,
2678     __in LONG Line,
2679     __in_opt PSTR File
2680     )
2681 {
2682     if (Offset != 0x0) {
2683         ASSERT(Offset == FIELD_OFFSET(FxRequest, m_SystemBufferOffset) ||
2684                Offset == FIELD_OFFSET(FxRequest, m_OutputBufferOffset));
2685         AddIrpReference();
2686         return 2;
2687     }
2688     else {
2689         return FxObject::AddRef(Tag, Line, File);
2690     }
2691 }
2692 
2693 ULONG
ReleaseOverride(__in WDFOBJECT_OFFSET Offset,__in PVOID Tag,__in LONG Line,__in_opt PSTR File)2694 FxRequest::ReleaseOverride(
2695     __in WDFOBJECT_OFFSET Offset,
2696     __in PVOID Tag,
2697     __in LONG Line,
2698     __in_opt PSTR File
2699     )
2700 {
2701     if (Offset != 0x0) {
2702         ASSERT(Offset == FIELD_OFFSET(FxRequest, m_SystemBufferOffset) ||
2703                Offset == FIELD_OFFSET(FxRequest, m_OutputBufferOffset));
2704         ReleaseIrpReference();
2705         return 1;
2706     }
2707     else {
2708         return FxObject::Release(Tag, Line, File);
2709     }
2710 }
2711 
2712 _Must_inspect_result_
2713 NTSTATUS
QueryInterface(__in FxQueryInterfaceParams * Params)2714 FxRequest::QueryInterface(
2715     __in FxQueryInterfaceParams* Params
2716     )
2717 {
2718     switch (Params->Type) {
2719     case FX_TYPE_REQUEST:
2720         *Params->Object = (FxRequest*) this;
2721         break;
2722 
2723     case IFX_TYPE_MEMORY:
2724         if (Params->Offset == FIELD_OFFSET(FxRequest, m_SystemBufferOffset)) {
2725             *Params->Object = (IFxMemory*) &m_SystemBuffer;
2726             break;
2727         }
2728         else if (Params->Offset == FIELD_OFFSET(FxRequest, m_OutputBufferOffset)) {
2729             *Params->Object = (IFxMemory*) &m_OutputBuffer;
2730             break;
2731         }
2732 
2733         //  ||   ||   Fall      ||  ||
2734         //  \/   \/   through   \/  \/
2735     default:
2736         return FxRequestBase::QueryInterface(Params); // __super call
2737     }
2738 
2739     return STATUS_SUCCESS;
2740 }
2741 
2742 VOID
FX_VF_METHOD(FxRequest,VerifierBreakpoint_RequestEarlyDisposeDeferred)2743 FX_VF_METHOD(FxRequest, VerifierBreakpoint_RequestEarlyDisposeDeferred) (
2744     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2745     )
2746 {
2747     PAGED_CODE_LOCKED();
2748 
2749     //
2750     // For backwards compatibility break only if WDF is v1.11 or above, or if
2751     // the developer/client enabled these tests on down-level drivers.
2752     //
2753     if (FxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) {
2754         DoTraceLevelMessage(
2755             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2756             "WDFREQUEST %p deferred the dispose operation. This normally "
2757             "indicates that at least one of its children asked for passive "
2758             "level disposal. This is not supported.", GetHandle());
2759 
2760         FxVerifierDbgBreakPoint(FxDriverGlobals);
2761     }
2762 }
2763 
2764 _Must_inspect_result_
2765 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsDriverOwned)2766 FX_VF_METHOD(FxRequest, VerifyRequestIsDriverOwned) (
2767     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2768     )
2769 {
2770     NTSTATUS status;
2771 
2772     PAGED_CODE_LOCKED();
2773 
2774     if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_OWNED) == 0) {
2775         status = STATUS_INVALID_DEVICE_REQUEST;
2776 
2777         DoTraceLevelMessage(
2778             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2779             "WDFREQUEST 0x%p is not owned by the driver, %!STATUS!",
2780             GetHandle(), status);
2781 
2782         //
2783         // See if it's a tag request, since this could be a common mistake
2784         //
2785         if (m_VerifierFlags & FXREQUEST_FLAG_TAG_REQUEST) {
2786             DoTraceLevelMessage(
2787                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2788                 "WDFREQUEST 0x%p has been "
2789                 "used as a TagRequest in WdfIoQueueFindRequest. "
2790                 "A TagRequest cannot be used until it is retrieved "
2791                 "by WdfIoQueueRetrieveFoundRequest",
2792                 GetHandle());
2793         }
2794 
2795         FxVerifierDbgBreakPoint(FxDriverGlobals);
2796     }
2797     else {
2798         status = STATUS_SUCCESS;
2799     }
2800 
2801     return status;
2802 }
2803 
2804 _Must_inspect_result_
2805 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsCancelable)2806 FX_VF_METHOD(FxRequest, VerifyRequestIsCancelable)(
2807      _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2808     )
2809 {
2810     NTSTATUS status;
2811 
2812     PAGED_CODE_LOCKED();
2813 
2814     if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_CANCELABLE) == 0) {
2815         status = STATUS_INVALID_DEVICE_REQUEST;
2816 
2817         DoTraceLevelMessage(
2818             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2819             "WDFREQUEST 0x%p is not cancelable, %!STATUS!",
2820             GetHandle(), status);
2821 
2822         FxVerifierDbgBreakPoint(FxDriverGlobals);
2823     }
2824     else {
2825         status = STATUS_SUCCESS;
2826     }
2827 
2828     return status;
2829 }
2830 
2831 _Must_inspect_result_
2832 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsNotCancelable)2833 FX_VF_METHOD(FxRequest, VerifyRequestIsNotCancelable)(
2834     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2835     )
2836 {
2837     NTSTATUS status;
2838 
2839     PAGED_CODE_LOCKED();
2840 
2841     if (m_VerifierFlags & FXREQUEST_FLAG_DRIVER_CANCELABLE) {
2842         status = STATUS_INVALID_DEVICE_REQUEST;
2843 
2844         DoTraceLevelMessage(
2845             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2846             "WDFREQUEST 0x%p should be unmarked cancelable by calling "
2847             "WdfRequestUnmarkCancelable, %!STATUS!",
2848             GetHandle(), status);
2849 
2850         FxVerifierDbgBreakPoint(FxDriverGlobals);
2851     }
2852     else {
2853         status = STATUS_SUCCESS;
2854     }
2855 
2856     return status;
2857 }
2858 
2859 _Must_inspect_result_
2860 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsInCallerContext)2861 FX_VF_METHOD(FxRequest, VerifyRequestIsInCallerContext)(
2862     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2863     )
2864 {
2865     NTSTATUS status;
2866 
2867     PAGED_CODE_LOCKED();
2868 
2869     if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT) == 0) {
2870         status = STATUS_INVALID_DEVICE_REQUEST;
2871 
2872         DoTraceLevelMessage(
2873             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2874             "This call is valid only in EvtIoInCallerContext callback, "
2875             "WDFREQUEST 0x%p, %!STATUS!", GetHandle(), status);
2876 
2877         FxVerifierDbgBreakPoint(FxDriverGlobals);
2878     }
2879     else {
2880         status = STATUS_SUCCESS;
2881     }
2882 
2883     return status;
2884 }
2885 
2886 _Must_inspect_result_
2887 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsInEvtIoStopContext)2888 FX_VF_METHOD(FxRequest, VerifyRequestIsInEvtIoStopContext)(
2889     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2890     )
2891 {
2892     NTSTATUS status;
2893 
2894     PAGED_CODE_LOCKED();
2895 
2896     if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT) == 0) {
2897         status = STATUS_INVALID_DEVICE_REQUEST;
2898 
2899         DoTraceLevelMessage(
2900             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2901             "This call is valid only in EvtIoStop callback, "
2902             "WDFREQUEST 0x%p, %!STATUS!", GetHandle(), status);
2903 
2904         FxVerifierDbgBreakPoint(FxDriverGlobals);
2905     }
2906     else {
2907         status = STATUS_SUCCESS;
2908     }
2909 
2910     return status;
2911 }
2912 
2913 _Must_inspect_result_
2914 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsNotCompleted)2915 FX_VF_METHOD(FxRequest, VerifyRequestIsNotCompleted)(
2916     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2917     )
2918 {
2919     NTSTATUS status;
2920 
2921     PAGED_CODE_LOCKED();
2922 
2923     if (m_Completed) {
2924         status = STATUS_INTERNAL_ERROR;
2925 
2926         DoTraceLevelMessage(
2927             FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
2928             "WDFREQUEST 0x%p is already completed, %!STATUS!",
2929             GetHandle(), status);
2930 
2931         FxVerifierDbgBreakPoint(FxDriverGlobals);
2932     }
2933     else {
2934         status = STATUS_SUCCESS;
2935     }
2936 
2937     return status;
2938 }
2939 
2940 _Must_inspect_result_
2941 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsTagRequest)2942 FX_VF_METHOD(FxRequest, VerifyRequestIsTagRequest) (
2943     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2944     )
2945 {
2946     NTSTATUS status;
2947 
2948     PAGED_CODE_LOCKED();
2949 
2950     //
2951     // A request that has been marked as a tag request can be retrieved
2952     // by the driver by calling WdfIoQueueRetrieveNextRequest instead of
2953     // WdfIoQueueRetrieveFoundRequest. Some drivers use multiple threads
2954     // to scan the queue, not the best design but allowed. This means that
2955     // it is possible for one thread to remove and complete a request that is
2956     // used as a tag by another thread.
2957     //
2958     if (FALSE == m_Completed && (0x0 == (m_VerifierFlags &
2959             (FXREQUEST_FLAG_TAG_REQUEST | FXREQUEST_FLAG_DRIVER_OWNED)))) {
2960 
2961        status = STATUS_INVALID_PARAMETER;
2962        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2963                            "Request 0x%p is not returned by WdfIoQueueFindRequest, "
2964                            "%!STATUS!", GetHandle(), status);
2965        FxVerifierDbgBreakPoint(FxDriverGlobals);
2966     }
2967     else {
2968         status = STATUS_SUCCESS;
2969     }
2970 
2971     return status;
2972 }
2973 
2974 _Must_inspect_result_
2975 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsAllocatedFromIo)2976 FX_VF_METHOD(FxRequest, VerifyRequestIsAllocatedFromIo)(
2977     _In_ PFX_DRIVER_GLOBALS FxDriverGlobals
2978     )
2979 {
2980     NTSTATUS status;
2981 
2982     PAGED_CODE_LOCKED();
2983 
2984     if (IsAllocatedFromIo() == FALSE) {
2985        status = STATUS_INVALID_PARAMETER;
2986        DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO,
2987                            "Request 0x%p was not allocated for an incoming IRP, "
2988                            "%!STATUS!", GetHandle(), status);
2989        FxVerifierDbgBreakPoint(FxDriverGlobals);
2990 
2991     }  else {
2992         status = STATUS_SUCCESS;
2993     }
2994 
2995     return status;
2996 }
2997 
2998 _Must_inspect_result_
2999 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestIsCurrentStackValid)3000 FX_VF_METHOD(FxRequest, VerifyRequestIsCurrentStackValid)(
3001     _In_ PFX_DRIVER_GLOBALS  FxDriverGlobals
3002     )
3003 {
3004     NTSTATUS status;
3005     MdIrp     irp;
3006 
3007     PAGED_CODE_LOCKED();
3008 
3009     //
3010     //Make sure there is an IRP.
3011     //
3012     irp = GetFxIrp()->GetIrp();
3013     if (NULL == irp) {
3014         status =  STATUS_INVALID_DEVICE_REQUEST;
3015         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
3016                             "WDFREQUEST %p doesn't have an IRP, %!STATUS!",
3017                             GetHandle(), status);
3018         FxVerifierDbgBreakPoint(FxDriverGlobals);
3019         goto Done;
3020     }
3021 
3022     //
3023     // Validate the IRP's stack location values.
3024     //
3025     if (m_Irp.IsCurrentIrpStackLocationValid() == FALSE) {
3026         status =  STATUS_INVALID_DEVICE_REQUEST;
3027         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
3028                             "IRP %p of WDFREQUEST %p doesn't have a valid"
3029                             " stack location, %!STATUS!",
3030                             irp, GetHandle(), status);
3031         FxVerifierDbgBreakPoint(FxDriverGlobals);
3032         goto Done;
3033     }
3034 
3035     status = STATUS_SUCCESS;
3036 
3037 Done:
3038     return status;
3039 }
3040 
3041 _Must_inspect_result_
3042 NTSTATUS
FX_VF_METHOD(FxRequest,VerifyRequestCanBeCompleted)3043 FX_VF_METHOD(FxRequest, VerifyRequestCanBeCompleted)(
3044     _In_ PFX_DRIVER_GLOBALS  FxDriverGlobals
3045     )
3046 {
3047     NTSTATUS            status;
3048 
3049     PAGED_CODE_LOCKED();
3050 
3051     if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) {
3052         status = VerifyRequestIsAllocatedFromIo(FxDriverGlobals);
3053         goto Done;
3054     }
3055 
3056     //
3057     // Validate the IRP's stack location.
3058     //
3059     status = VerifyRequestIsCurrentStackValid(FxDriverGlobals);
3060     if (!NT_SUCCESS(status)) {
3061         goto Done;
3062     }
3063 
3064     //
3065     // Note: There is no guarantees that the request has a completion routine in the current
3066     //          IRP stack location; thus we cannot check for it.
3067     //
3068 
3069     //
3070     // Make sure this request can be completed.
3071     //
3072     if (IsCanComplete() == FALSE) {
3073         status =  STATUS_INVALID_DEVICE_REQUEST;
3074         DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST,
3075                             "IRP %p of WDFREQUEST %p cannot be completed, "
3076                             "%!STATUS!",
3077                             GetFxIrp()->GetIrp(), GetHandle(), status);
3078         FxVerifierDbgBreakPoint(FxDriverGlobals);
3079         goto Done;
3080     }
3081 
3082     status = STATUS_SUCCESS;
3083 
3084 Done:
3085     return status;
3086 }
3087 
3088 ULONG
Release(__in PVOID Tag,__in LONG Line,__in_opt PSTR File)3089 FxRequest::Release(
3090     __in PVOID Tag,
3091     __in LONG Line,
3092     __in_opt PSTR File
3093     )
3094 {
3095     ULONG   retValue;
3096     BOOLEAN reservedRequest;
3097     BOOLEAN allocFromIo;
3098     BOOLEAN canComplete;
3099 
3100     //
3101     // This may be the last ref, copy flags before calling Release().
3102     //
3103     reservedRequest = IsReserved();
3104     allocFromIo     = IsAllocatedFromIo();
3105     canComplete     = IsCanComplete();
3106 
3107     retValue = FxRequestBase::Release(Tag, Line, File); // __super call
3108 
3109     if (reservedRequest && retValue == 1 && m_Completed) {
3110         //
3111         // Reserved requests should have an associated queue all the time.
3112         //
3113         m_ForwardProgressQueue->ReturnReservedRequest(this);
3114     }
3115     else if (allocFromIo == FALSE && canComplete && retValue == 1 && m_Completed) {
3116 
3117         FxRequestCompletionState    state;
3118         FxIoQueue*                  queue;
3119 
3120         //
3121         // Make a local copy before request is gone.
3122         //
3123         state = (FxRequestCompletionState) m_CompletionState;
3124         queue = m_IoQueue;
3125 
3126         m_CompletionState = FxRequestCompletionStateNone;
3127         m_IoQueue = NULL;
3128 
3129         //
3130         // We are now ready to complete this driver created request.
3131         //
3132         FxIrp irp(m_Irp.GetIrp());
3133 
3134         m_Irp.SetIrp(NULL);
3135 
3136         irp.CompleteRequest(GetPriorityBoost());
3137 
3138         PostProcessCompletionForDriverRequest(state, queue);
3139     }
3140 
3141     return retValue;
3142 }
3143 
FxRequestFromLookaside(__in CfxDevice * Device,__in MdIrp Irp)3144 FxRequestFromLookaside::FxRequestFromLookaside(
3145     __in CfxDevice* Device,
3146     __in MdIrp Irp
3147     ) : FxRequest(Device->GetDriverGlobals(),
3148                   Irp,
3149                   FxRequestDoesNotOwnIrp,
3150                   FxRequestConstructorCallerIsFx,
3151                   sizeof(FxRequestFromLookaside))
3152 {
3153     SetDeviceBase(Device->GetDeviceBase());
3154 }
3155 
3156 PVOID
operator new(__in size_t Size,__in CfxDevice * Device,__in_opt PWDF_OBJECT_ATTRIBUTES Attributes)3157 FxRequestFromLookaside::operator new(
3158     __in size_t Size,
3159     __in CfxDevice* Device,
3160     __in_opt PWDF_OBJECT_ATTRIBUTES Attributes
3161     )
3162 {
3163     UNREFERENCED_PARAMETER(Size);
3164 
3165     //
3166     // Allocate out of a device specific lookaside list
3167     //
3168     return Device->AllocateRequestMemory(Attributes);
3169 }
3170 
3171 VOID
SelfDestruct(VOID)3172 FxRequestFromLookaside::SelfDestruct(
3173     VOID
3174     )
3175 {
3176     CfxDevice* pDevice;
3177     PFX_POOL_HEADER pHeader;
3178 
3179     //
3180     // Store off the device in case the destructor chain sets it to NULL.
3181     //
3182     pDevice = GetDevice();
3183     ASSERT(pDevice != NULL);
3184 
3185     //
3186     // Destroy the object
3187     //
3188     // FxRequestFromLookaside::~FxRequestFromLookaside(); __REACTOS__
3189 
3190     if (IsRequestForwardedToParent()) {
3191 
3192  #if FX_VERBOSE_TRACE
3193         DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST,
3194                             "Free FxRequest* %p memory", this);
3195  #endif
3196 
3197         //
3198         // Remove the request from the list of outstanding requests against this
3199         // driver.
3200         //
3201         pHeader = FxObject::_CleanupPointer(GetDriverGlobals(), this);
3202         MxMemory::MxFreePool(pHeader->Base);
3203     }
3204     else {
3205         pDevice->FreeRequestMemory(this);
3206     }
3207 }
3208