CreateFile ERROR_FILE_NOT_FOUND when opening PCI driver on 32-bit Win10

I am experiencing odd behavior when opening a PCI device through it’s associated kernel driver on 32-bit Windows 10. I do not experience this problem on Windows 7 32-bit, Windows 7 64-bit, or Windows 10 64-bit. The CreateFile user space call returns INVALID_HANDLE_VALUE and a GetLastError call directly following this call returns ERROR_FILE_NOT_FOUND. The confusion is about why the system cannot locate the device. Using DeviceManager, I can see the device in the device tree. Running WinObj, I can see the device object. And looking in the registry location HKLM\SYSTEM\CurrentControlSet\Control\Class, I see the device listed under it’s GUID.

The CreateFile call is as follows:

m_hController = CreateFile ( m_strDevice, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

with m_strDevice set earlier in the class as follows:

sprintf(m_strDevice, “\\.\OmsMAXk%d”, 1)

This device path is found on 64-bit Windows 10 but not on 32-bit Windows 10. Is this an issue related to the string not being Unicode?

Thank you for help anyone can offer to explain this failure.

Where in the driver do you create the symbolic link? Does using a device interface work?

Bent from my phone


From: xxxxx@lists.osr.com on behalf of xxxxx@gmail.com
Sent: Tuesday, March 14, 2017 8:00:31 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] CreateFile ERROR_FILE_NOT_FOUND when opening PCI driver on 32-bit Win10

I am experiencing odd behavior when opening a PCI device through it’s associated kernel driver on 32-bit Windows 10. I do not experience this problem on Windows 7 32-bit, Windows 7 64-bit, or Windows 10 64-bit. The CreateFile user space call returns INVALID_HANDLE_VALUE and a GetLastError call directly following this call returns ERROR_FILE_NOT_FOUND. The confusion is about why the system cannot locate the device. Using DeviceManager, I can see the device in the device tree. Running WinObj, I can see the device object. And looking in the registry location HKLM\SYSTEM\CurrentControlSet\Control\Class, I see the device listed under it’s GUID.

The CreateFile call is as follows:

m_hController = CreateFile ( m_strDevice, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

with m_strDevice set earlier in the class as follows:

sprintf(m_strDevice, “\\.\OmsMAXk%d”, 1)

This device path is found on 64-bit Windows 10 but not on 32-bit Windows 10. Is this an issue related to the string not being Unicode?

Thank you for help anyone can offer to explain this failure.


NTDEV is sponsored by OSR

Visit the list online at: http:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at http:

To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:></http:>

I forgot to mention that my PCI kernel driver does handle the IRP_MJ_CREATE dispatch request by simply returning STATUS_SUCCESS, then calling IoCompleteRequest(Irp, IO_NO_INCREMENT).

The symbolic link is created in my AddDevice routine, not my Driver Entry. Note, this is a WDM driver. The symbolic link is created as follows:

WCHAR dosDeviceName[RESPONSE_BUFF_SIZE] = { ‘\0’ };
UNICODE_STRING ntDeviceName;
UNICODE_STRING Win32DeviceName;
WCHAR deviceInfo[RESPONSE_BUFF_SIZE] = { ‘\0’ };
WCHAR deviceName[RESPONSE_BUFF_SIZE] = { ‘\0’ };

controllerId = deviceInfo[idIndex];
_snwprintf(deviceName, RESPONSE_BUFF_SIZE, L"\Device\OmsMAXk%c", controllerId);
RtlInitUnicodeString(&ntDeviceName, deviceName);

//Link the NT device name with the Win32 name used by applications
RtlInitUnicodeString(&Win32DeviceName, dosDeviceName);
status = IoCreateSymbolicLink(&Win32DeviceName, &ntDeviceName);
if (!NT_SUCCESS(status)) // If we we couldn’t create the link then
{ // abort installation.
OmsKdPrint((“OmsMAXk.sys: Failed to create symbolic link\n”));
return status;
}

I have not tried a device interface yet. But I can modify the code to use one and test my user application again.

xxxxx@gmail.com wrote:

The symbolic link is created in my AddDevice routine, not my Driver Entry. Note, this is a WDM driver. The symbolic link is created as follows:

WCHAR dosDeviceName[RESPONSE_BUFF_SIZE] = { ‘\0’ };
UNICODE_STRING ntDeviceName;
UNICODE_STRING Win32DeviceName;
WCHAR deviceInfo[RESPONSE_BUFF_SIZE] = { ‘\0’ };
WCHAR deviceName[RESPONSE_BUFF_SIZE] = { ‘\0’ };

controllerId = deviceInfo[idIndex];
_snwprintf(deviceName, RESPONSE_BUFF_SIZE, L"\Device\OmsMAXk%c", controllerId);
RtlInitUnicodeString(&ntDeviceName, deviceName);

//Link the NT device name with the Win32 name used by applications
RtlInitUnicodeString(&Win32DeviceName, dosDeviceName);
status = IoCreateSymbolicLink(&Win32DeviceName, &ntDeviceName);

m_hController = CreateFile ( m_strDevice, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

with m_strDevice set earlier in the class as follows:

sprintf(m_strDevice, “\\.\OmsMAXk%d”, 1)

You have deleted all the interesting stuff, as usual. You show the
creation of the ntDeviceName, but not the dosDeviceName, which is the
one you actually need to match.

Also, your driver is using “%c” to add the sequence number, whereas your
app uses “%d”. Are you sure “controllerId” actually contains the ASCII
character “1”? Because you also didn’t show us how you create
deviceInfo, nor how you get idIndex.

In other words, there are about a dozen ways you could have screwed this
up, but the tiny code snippets you showed us don’t allow us to help.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Hello Tim,

My apologies for the lack of information in my previous post. The full AddDevice routine is below. I did see the inconsistency in string formatting, e.g. %d vs. %c and I am verifying that the ASCII string contains the correct integer. Thank you for your advice.

NTSTATUS
OmsAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = NULL;
PDEVICE_EXTENSION DeviceInfo;
UNICODE_STRING ntDeviceName;
UNICODE_STRING Win32DeviceName;
WCHAR deviceInfo[RESPONSE_BUFF_SIZE] = { ‘\0’ };
WCHAR deviceName[RESPONSE_BUFF_SIZE] = { ‘\0’ };
WCHAR dosDeviceName[RESPONSE_BUFF_SIZE] = { ‘\0’ };
char sTag[4] = { ‘\0’ };
ULONG length = 0;
const unsigned int idIndex = 32;
WCHAR controllerId = 0;
ULONG tag = 0;

PAGED_CODE();

OmsKdPrint((“OmsMAXk.sys: OmsAddDevice\n”));

status = IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyHardwareID, RESPONSE_BUFF_SIZE, deviceInfo, &length);
if (!NT_SUCCESS(status) && (length > idIndex)) {
OmsKdPrint((“OmsMAXk.sys: Obtaining device property error\n”));
return status;
}

controllerId = deviceInfo[idIndex];
_snwprintf(deviceName, RESPONSE_BUFF_SIZE, L"\Device\OmsMAXk%c", controllerId);
_snwprintf(dosDeviceName, RESPONSE_BUFF_SIZE, L"\DosDevices\OmsMAXk%c", controllerId);
OmsKdPrint((“Device name is %0LX\n”, deviceName));
OmsKdPrint((“Dos device name is $0LX\n”, dosDeviceName));

sprintf(sTag, “%cSMO”, controllerId);
OmsKdPrint((“sTag is %0LX\n”, sTag));
tag = (sTag[0] << 24) | (sTag[1] << 16) | (sTag[2] << 8) | sTag[3];

//Use the NT device name defined in OmsMAXk1.c, OmsMAXk2.c,
// OmsMAXk3.c or OmsMAXk4.c
RtlInitUnicodeString(&ntDeviceName, deviceName);

// Create the device object for the controller
status = IoCreateDevice(DriverObject,
sizeof(DEVICE_EXTENSION),
&ntDeviceName,
OMS_FILE_DEVICE,
0,
FALSE,
&DeviceObject);
if (!NT_SUCCESS(status))
{
// Either not enough memory to create a DeviceObject or another
// DeviceObject with the same name exists.
OmsKdPrint((“OmsMAXk.sys: Failed to create device object\n”));
return status;
}

OmsKdPrint((“OmsMAXk.sys: Successfully created device object\n”));
//Link the NT device name with the Win32 name used by applications
RtlInitUnicodeString(&Win32DeviceName, dosDeviceName);
status = IoCreateSymbolicLink(&Win32DeviceName, &ntDeviceName);
if (!NT_SUCCESS(status)) // If we we couldn’t create the link then
{ // abort installation.
OmsKdPrint((“OmsMAXk.sys: Failed to create symbolic link\n”));
return status;
}

OmsKdPrint((“OmsMAXk.sys: Successfully created symbolic link\n”));
DeviceInfo = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;

//Attach the driver object to the driver stack.
DeviceInfo->NextLowerDriver = IoAttachDeviceToDeviceStack(
DeviceObject,
PhysicalDeviceObject);
if (NULL == DeviceInfo->NextLowerDriver)
{
//IoDeleteSymbolicLink(&Win32DeviceName);
IoDeleteDevice(DeviceObject);
OmsKdPrint((“OmsMAXk.sys: Failed to attach driver object to driver stack\n”));
return STATUS_NO_SUCH_DEVICE;
}

OmsKdPrint((“OmsMAXk.sys: Successfully attached driver object to driver stack\n”));
//Initialize the device object delete lock structure
IoInitializeRemoveLock(&DeviceInfo->RemoveLock,
tag,
1, // MaxLockedMinutes
5); // HighWatermark, this parameter is
// used only on checked build.

//Windows 7/10 64-bit drivers must be pagable
DeviceObject->Flags |= DO_POWER_PAGABLE;

DeviceInfo->Removed = FALSE;
DeviceInfo->Started = FALSE;

status = IoInitializeTimer(DeviceObject, IoTimer, DeviceInfo);
if (!NT_SUCCESS(status)) // If we couldn’t initialize IO Timer
{ // then abort installation.
OmsKdPrint((“OmsMAXk.sys: Failed to initialize IO Timer\n”));
return status;
}

OmsKdPrint((“OmsMAXk.sys: Successfully initialized IO Timer\n”));
//The device object intialization is complete
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
DeviceInfo->ControllerId = controllerId;

return STATUS_SUCCESS;
}

Also, the user app that calls the driver uses the following:

sprintf(m_strDevice, “\\.\OmsMAXk%d”, id);

// Open the motor controller device
m_hController = CreateFile ( m_strDevice, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL);

where “id” is an int between 1 and 4.

xxxxx@gmail.com wrote:

Hello Tim,

My apologies for the lack of information in my previous post. The full AddDevice routine is below. I did see the inconsistency in string formatting, e.g. %d vs. %c and I am verifying that the ASCII string contains the correct integer. Thank you for your advice.

NTSTATUS
OmsAddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = NULL;
PDEVICE_EXTENSION DeviceInfo;
UNICODE_STRING ntDeviceName;
UNICODE_STRING Win32DeviceName;
WCHAR deviceInfo[RESPONSE_BUFF_SIZE] = { ‘\0’ };
WCHAR deviceName[RESPONSE_BUFF_SIZE] = { ‘\0’ };
WCHAR dosDeviceName[RESPONSE_BUFF_SIZE] = { ‘\0’ };
char sTag[4] = { ‘\0’ };
ULONG length = 0;
const unsigned int idIndex = 32;
WCHAR controllerId = 0;
ULONG tag = 0;

PAGED_CODE();

OmsKdPrint((“OmsMAXk.sys: OmsAddDevice\n”));

status = IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyHardwareID, RESPONSE_BUFF_SIZE, deviceInfo, &length);
if (!NT_SUCCESS(status) && (length > idIndex)) {
OmsKdPrint((“OmsMAXk.sys: Obtaining device property error\n”));
return status;
}

That “if” statement is totally wrong. Read it:
“if the API failed AND the length is longer than we expect, return”

Clearly, you want an “||” there instead of an “&&”, but the length check
is suspicious. If the returned string is SHORTER than you expect, then
it should also fail. Otherwise, you’ll fetch off the end of the string.

controllerId = deviceInfo[idIndex];
_snwprintf(deviceName, RESPONSE_BUFF_SIZE, L"\Device\OmsMAXk%c", controllerId);
_snwprintf(dosDeviceName, RESPONSE_BUFF_SIZE, L"\DosDevices\OmsMAXk%c", controllerId);
OmsKdPrint((“Device name is %0LX\n”, deviceName));
OmsKdPrint((“Dos device name is $0LX\n”, dosDeviceName));

So, it pulls the 32nd character from the hardware ID and uses that as
the device ordinal. Doesn’t that seem extremely delicate? And yet the
app is hardcoding a “1”. What makes you confident the hardware ID will
have a “1” there? Have you printed out the hardware ID to make sure it
looks the same on your 32-bit system as it does on your 64-bit system?
Because the operating system makes no such guarantees.

This is why device interfaces were created.

The first KdPrint will print the address of the UNICODE_STRING, which is
hardly useful. The second one will literally print $0LX, which is even
less useful. In both cases, you should use %wZ, which will print the
CONTENTS of the UNICODE_STRING. That would tell you exactly which
symbolic names you are actually creating.

sprintf(sTag, “%cSMO”, controllerId);
OmsKdPrint((“sTag is %0LX\n”, sTag));

Again, that prints the address of the string. You almost certainly want
a simple %s here.

tag = (sTag[0] << 24) | (sTag[1] << 16) | (sTag[2] << 8) | sTag[3];

I would think replacing all three of those lines with
tag = ‘SMO’ | (controllerId << 24);
would be just as muddy.

Also, the user app that calls the driver uses the following:

sprintf(m_strDevice, “\\.\OmsMAXk%d”, id);

// Open the motor controller device
m_hController = CreateFile ( m_strDevice, GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
NULL);

where “id” is an int between 1 and 4.

There’s an awful lot of assumptions here.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

You should notice that when you declare:

WCHAR deviceInfo[RESPONSE_BUFF_SIZE] = { ‘\0’ };

you allocate sizeof(deviceInfo) bytes on the stack and not RESPONSE_BUFF_SIZE bytes. That’s why you should use sizeof(deviceInfo) for the buffer length with IoGetDeviceProperty.

You should also read this page to find a replacement for _snwprintf. It is deprecated.

https://msdn.microsoft.com/en-us/library/windows/hardware/ff563885(v=vs.85).aspx

I think your naming scheme is wrong because a user could force the installation of your driver for a device whose hardware ID is not listed in your INF file and could not have the ‘format’ you expect.

Thank you for your help. I was on this forum about a year ago when I needed to certify a PCI device for Windows 10 for my company, for which I did not write. Now, I need to certify another PCI device driver for Windows 10 as well. Both drivers were fairly old and I was not involved in the design of the original drivers. However, I am working on fixing the bugs in this driver and porting deprecated code to supported functions, etc, as well handling it’s data more safely. I understand your advise, which is why I am changing some of the code in this driver that was passed off to me.

Yes, I think IoGetDeviceProperty should use sizeof(deviceInfo) rather than RESPONSE_BUFF_SIZE, as the allocated size on the stack.

Thanks again.

You should consider porting the driver to WDF.

https://msdn.microsoft.com/en-us/windows/hardware/drivers/wdf/wdf-porting-guide

Yes, on the PCI driver that I had previously worked on, I ended up certifying the driver based on the WDM model. However, I did work extensively to port the driver to KMDF, and I am planning to complete the port once this one is completed. When porting my previous driver to KMDF, the Framework was much easier to work with than the WDM, so I certainly plan. I plan to finish the port to KMDF.