locked
FwpmEngineOpen returns EPT_NT_CANT_PERFORM_OP when WFP callout driver is started with SERVICE_SYSTEM_START RRS feed

  • Question

  • I am writing a WDM based WFP Callout based on Microsoft Inspect example, Inspect is based onWDF and runs well with SERVICE_DEMAND_START or SERVICE_SYSTEM_START. My example has changed WDF to WDM, and use SERVICE_SYSTEM_START in my INF, but my driver'sFwpmEngineOpen function fails with EPT_NT_CANT_PERFORM_OP when the system got reboot. In my example I just opened and closed the WFP engine, so there is no relationship with persistent callouts or filters.

    I also found that there's relationship with device. If I create a device (using NPF_CreateDevice call), this error will happen, but if I comment NPF_CreateDevice call, this error went away. And considering WDM and WDF are different in device creating code. So I think there must be something wrong with my device code? Thanks!

    lbtest.c

    #include "stdafx.h"
    
    #include <ntddk.h>
    
    #include "Loopback.h"
    #include "lbtest.h"
    #include "debug.h"
    
    extern HANDLE gWFPEngineHandle;
    
    #ifdef ALLOC_PRAGMA
    #pragma NDIS_INIT_FUNCTION(DriverEntry)
    #endif // ALLOC_PRAGMA
    
    #if DBG
    // Declare the global debug flag for this driver.
    ULONG PacketDebugFlag = PACKET_DEBUG_LOUD;
    
    #endif
    
    // 
    // Configurable parameters (addresses and ports are in host order)
    //
    
    WCHAR g_NPF_PrefixBuffer[512] = L"NPCAP" L"_";
    
    WCHAR* bindT = NULL;
    
    NDIS_STRING g_NPF_Prefix;
    NDIS_STRING devicePrefix = NDIS_STRING_CONST("\\Device\\");
    NDIS_STRING symbolicLinkPrefix = NDIS_STRING_CONST("\\DosDevices\\");
    
    
    /*!
    \brief Port device extension.
    
    Structure containing some data relative to every adapter on which NPF is bound.
    */
    typedef struct _DEVICE_EXTENSION
    {
    	NDIS_STRING	AdapterName;			///< Name of the adapter.
    	PWSTR		ExportString;			///< Name of the exported device, i.e. name that the applications will use 
    	///< to open this adapter through WinPcap.
    } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
    
    
    
    BOOLEAN
    NPF_CreateDevice(
    IN OUT PDRIVER_OBJECT adriverObjectP,
    IN PUNICODE_STRING amacNameP
    )
    {
    	NTSTATUS status;
    	PDEVICE_OBJECT devObjP;
    	UNICODE_STRING deviceName;
    	UNICODE_STRING deviceSymLink;
    
    	TRACE_ENTER();
    
    	IF_LOUD(DbgPrint("\n\ncreateDevice for MAC %ws\n", amacNameP->Buffer););
    	if (RtlCompareMemory(amacNameP->Buffer, devicePrefix.Buffer, devicePrefix.Length) < devicePrefix.Length)
    	{
    		TRACE_EXIT();
    		return FALSE;
    	}
    
    	deviceName.Length = 0;
    	deviceName.MaximumLength = (USHORT)(amacNameP->Length + g_NPF_Prefix.Length + sizeof(UNICODE_NULL));
    	deviceName.Buffer = ExAllocatePoolWithTag(PagedPool, deviceName.MaximumLength, '3PWA');
    
    	if (deviceName.Buffer == NULL)
    	{
    		TRACE_EXIT();
    		return FALSE;
    	}
    
    	deviceSymLink.Length = 0;
    	deviceSymLink.MaximumLength = (USHORT)(amacNameP->Length - devicePrefix.Length + symbolicLinkPrefix.Length + g_NPF_Prefix.Length + sizeof(UNICODE_NULL));
    
    	deviceSymLink.Buffer = ExAllocatePoolWithTag(NonPagedPool, deviceSymLink.MaximumLength, '3PWA');
    
    	if (deviceSymLink.Buffer == NULL)
    	{
    		ExFreePool(deviceName.Buffer);
    		TRACE_EXIT();
    		return FALSE;
    	}
    
    	RtlAppendUnicodeStringToString(&deviceName, &devicePrefix);
    	RtlAppendUnicodeStringToString(&deviceName, &g_NPF_Prefix);
    	RtlAppendUnicodeToString(&deviceName, amacNameP->Buffer + devicePrefix.Length / sizeof(WCHAR));
    
    	RtlAppendUnicodeStringToString(&deviceSymLink, &symbolicLinkPrefix);
    	RtlAppendUnicodeStringToString(&deviceSymLink, &g_NPF_Prefix);
    	RtlAppendUnicodeToString(&deviceSymLink, amacNameP->Buffer + devicePrefix.Length / sizeof(WCHAR));
    
    	IF_LOUD(DbgPrint("Creating device name: %ws\n", deviceName.Buffer);)
    
    // 	status = IoCreateDevice(adriverObjectP, sizeof(DEVICE_EXTENSION), &deviceName, FILE_DEVICE_TRANSPORT,
    // 		FILE_DEVICE_SECURE_OPEN, FALSE, &devObjP);
    status = IoCreateDevice(adriverObjectP, sizeof(DEVICE_EXTENSION), &deviceName, FILE_DEVICE_UNKNOWN,
    	FILE_DEVICE_SECURE_OPEN, FALSE, &devObjP);
    // 		UNICODE_STRING sddl = RTL_CONSTANT_STRING(L"D:P(A;;GA;;;SY)(A;;GA;;;BA)");
    // 	const GUID guidClassNPF = { 0x26e0d1e0L, 0x8189, 0x12e0, { 0x99, 0x14, 0x08, 0x00, 0x22, 0x30, 0x19, 0x04 } };
    // 	status = IoCreateDeviceSecure(adriverObjectP, sizeof(DEVICE_EXTENSION), &deviceName, FILE_DEVICE_TRANSPORT,
    // 		FILE_DEVICE_SECURE_OPEN, FALSE, &sddl, (LPCGUID)&guidClassNPF, &devObjP);
    
    	if (NT_SUCCESS(status))
    	{
    		PDEVICE_EXTENSION devExtP = (PDEVICE_EXTENSION)devObjP->DeviceExtension;
    
    		IF_LOUD(DbgPrint("Device created successfully\n"););
    
    		devObjP->Flags |= DO_DIRECT_IO;
    		RtlInitUnicodeString(&devExtP->AdapterName, amacNameP->Buffer);
    
    		IF_LOUD(DbgPrint("Trying to create SymLink %ws\n", deviceSymLink.Buffer););
    
    		if (IoCreateSymbolicLink(&deviceSymLink, &deviceName) != STATUS_SUCCESS)
    		{
    			IF_LOUD(DbgPrint("\n\nError creating SymLink %ws\nn", deviceSymLink.Buffer););
    
    			ExFreePool(deviceName.Buffer);
    			ExFreePool(deviceSymLink.Buffer);
    
    			devExtP->ExportString = NULL;
    
    			TRACE_EXIT();
    			return FALSE;
    		}
    
    		IF_LOUD(DbgPrint("SymLink %ws successfully created.\n\n", deviceSymLink.Buffer););
    
    		devExtP->ExportString = deviceSymLink.Buffer;
    
    		ExFreePool(deviceName.Buffer);
    
    		TRACE_EXIT();
    		return TRUE;
    	}
    	else
    	{
    		IF_LOUD(DbgPrint("\n\nIoCreateDevice status = %x\n", status););
    
    		ExFreePool(deviceName.Buffer);
    		ExFreePool(deviceSymLink.Buffer);
    
    		TRACE_EXIT();
    		return FALSE;
    	}
    }
    
    _Use_decl_annotations_
    VOID
    NPF_Unload(
    	IN PDRIVER_OBJECT      DriverObject
    	)
    {
    	PDEVICE_OBJECT DeviceObject;
    	PDEVICE_OBJECT OldDeviceObject;
    	PDEVICE_EXTENSION DeviceExtension;
    	NDIS_STRING SymLink;
    
    	TRACE_ENTER();
    
    	NPF_UnregisterCallouts();
    
    	DeviceObject = DriverObject->DeviceObject;
    
    	while (DeviceObject != NULL)
    	{
    		OldDeviceObject = DeviceObject;
    
    		DeviceObject = DeviceObject->NextDevice;
    
    		DeviceExtension = OldDeviceObject->DeviceExtension;
    
    		TRACE_MESSAGE3(PACKET_DEBUG_LOUD, "Deleting Adapter %ws, Protocol Handle=xxx, Device Obj=%p (%p)", DeviceExtension->AdapterName.Buffer, DeviceObject, OldDeviceObject);
    
    		if (DeviceExtension->ExportString)
    		{
    			RtlInitUnicodeString(&SymLink, DeviceExtension->ExportString);
    
    			TRACE_MESSAGE1(PACKET_DEBUG_LOUD, "Deleting SymLink at %p", SymLink.Buffer);
    
    			IoDeleteSymbolicLink(&SymLink);
    			ExFreePool(DeviceExtension->ExportString);
    		}
    
    		IF_LOUD(DbgPrint("Device successfully deleted.\n\n"););
    		IoDeleteDevice(OldDeviceObject);
    	}
    
    	// Free the adapters names
    	ExFreePool(bindT);
    
    	TRACE_EXIT();
    }
    
    _Use_decl_annotations_
    NTSTATUS
    DriverEntry(
    	DRIVER_OBJECT* DriverObject,
    	UNICODE_STRING* RegistryPath
    	)
    {
    	NTSTATUS Status = STATUS_SUCCESS;
    	UNICODE_STRING macName;
    
    	UNREFERENCED_PARAMETER(RegistryPath);
    
    	TRACE_ENTER();
    
    	IF_LOUD(DbgPrint("\n\nThis is version [2]!!!.\n");)
    
    	bindT = (PWCHAR)ExAllocatePoolWithTag(PagedPool, 4096, 'NPCA');
    	//RtlCopyUnicodeString(bindT, L"\\Device\\{A22932C9-82CB-4080-993B-D5E82CAD06A7}"); //0006, Microsoft KM-TEST Loopback Adapter;
    	wcscpy(bindT, L"\\Device\\{A22932C9-82CB-4080-993B-D5E82CAD06A7}");
    	RtlInitUnicodeString(&macName, bindT);
    
    	NdisInitUnicodeString(&g_NPF_Prefix, g_NPF_PrefixBuffer);
    
    	DriverObject->DriverUnload = NPF_Unload;
    
    	// 
    	// Standard device driver entry points stuff.
    	//
    // 	DriverObject->MajorFunction[IRP_MJ_CREATE] = NULL;
    // 	DriverObject->MajorFunction[IRP_MJ_CLOSE] = NULL;
    // 	DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NULL;
    // 	DriverObject->MajorFunction[IRP_MJ_READ] = NULL;
    // 	DriverObject->MajorFunction[IRP_MJ_WRITE] = NULL;
    // 	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NULL;
    
    	Status = NPF_CreateDevice(DriverObject, &macName) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
    	if (Status != STATUS_SUCCESS)
    	{
    		IF_LOUD(DbgPrint("Failed to create WFP device.\n");)
    		TRACE_EXIT();
    		return STATUS_SUCCESS;
    	}
    
    // 	if (DriverObject->DeviceObject)
    // 	{
    // 		Status = NPF_RegisterCallouts(DriverObject->DeviceObject);
    // 		if (!NT_SUCCESS(Status))
    // 		{
    // 			if (gWFPEngineHandle != NULL)
    // 			{
    // 				FwpmEngineClose(gWFPEngineHandle);
    // 				gWFPEngineHandle = NULL;
    // 			}
    // 			TRACE_EXIT();
    // 			return Status;
    // 		}
    // 	}
    
    	Status = NPF_RegisterCallouts(NULL);
    	if (!NT_SUCCESS(Status))
    	{
    		if (gWFPEngineHandle != NULL)
    		{
    			FwpmEngineClose(gWFPEngineHandle);
    			gWFPEngineHandle = NULL;
    		}
    		TRACE_EXIT();
    		return Status;
    	}
    
    	TRACE_EXIT();
    	return STATUS_SUCCESS;
    };
    

    loopback.c

    #include "stdafx.h"
    
    #include "Loopback.h"
    #include "debug.h"
    
    
    NTSTATUS
    NPF_RegisterCallouts(
    _Inout_ void* deviceObject
    )
    /* ++
    
    This function registers dynamic callouts and filters that intercept
    transport traffic at ALE AUTH_CONNECT/AUTH_RECV_ACCEPT and
    INBOUND/OUTBOUND transport layers.
    
    Callouts and filters will be removed during DriverUnload.
    
    -- */
    {
    	TRACE_ENTER();
    	NTSTATUS status = STATUS_SUCCESS;
    	FWPM_SUBLAYER NPFSubLayer;
    
    	BOOLEAN engineOpened = FALSE;
    	BOOLEAN inTransaction = FALSE;
    
    	FWPM_SESSION session = { 0 };
    
    	session.flags = 0;// FWPM_SESSION_FLAG_DYNAMIC;
    
    	status = FwpmEngineOpen(
    		NULL,
    		RPC_C_AUTHN_WINNT,
    		NULL,
    		&session,
    		&gWFPEngineHandle
    		);
    	if (!NT_SUCCESS(status))
    	{
    		goto Exit;
    	}
    	engineOpened = TRUE;
    
    Exit:
    
    	if (!NT_SUCCESS(status))
    	{
    		IF_LOUD(DbgPrint("NPF_RegisterCallouts: failed to register callouts\n");)
    			if (inTransaction)
    			{
    				FwpmTransactionAbort(gWFPEngineHandle);
    				_Analysis_assume_lock_not_held_(gWFPEngineHandle); // Potential leak if "FwpmTransactionAbort" fails
    			}
    		if (engineOpened)
    		{
    			FwpmEngineClose(gWFPEngineHandle);
    			gWFPEngineHandle = NULL;
    		}
    	}
    
    	TRACE_EXIT();
    	return status;
    }
    
    void
    NPF_UnregisterCallouts(
    )
    {
    	NTSTATUS status;
    
    	TRACE_ENTER();
    
    	FwpmEngineClose(gWFPEngineHandle);
    
    	TRACE_EXIT();
    }
    

    Monday, July 27, 2015 4:01 AM

Answers

  • Are you sure BFE is up and running when you make the call?  Use FwpmBfeStateSubscribeChanges to get notified when BFE starts, and call only after it is running

    Hope this helps


    Dusty Harper [MSFT]
    Microsoft Corporation
    ------------------------------------------------------------
    This posting is provided "AS IS", with NO warranties and confers NO rights
    ------------------------------------------------------------

    • Marked as answer by Yang Luo Saturday, March 26, 2016 7:10 AM
    Tuesday, September 22, 2015 11:53 PM
    Moderator

All replies

  • Are you sure BFE is up and running when you make the call?  Use FwpmBfeStateSubscribeChanges to get notified when BFE starts, and call only after it is running

    Hope this helps


    Dusty Harper [MSFT]
    Microsoft Corporation
    ------------------------------------------------------------
    This posting is provided "AS IS", with NO warranties and confers NO rights
    ------------------------------------------------------------

    • Marked as answer by Yang Luo Saturday, March 26, 2016 7:10 AM
    Tuesday, September 22, 2015 11:53 PM
    Moderator
  • Yes, this is the reason, thanks!
    Saturday, March 26, 2016 7:10 AM