pbatard / libwdi

Windows Driver Installer library for USB devices
GNU General Public License v3.0
1.84k stars 459 forks source link

Default WinUSB INF claims other devices #251

Closed mliberty1 closed 2 years ago

mliberty1 commented 2 years ago

Version: unknown Platform: Windows 11 x64

Description

I had a Joulescope customer attempt to use their new device on a Windows 11 machine. They reported that their new instrument showed up in Device Manager, but our application software could not find it. After investigation, the device was claimed by libwdi.

Joulescopes use Microsoft OS Descriptors to automatically instantiate the WinUSB driver and set some registry keys, including DeviceInterfaceGUID. It appears that the default libwdi winusb INF template overwrites DeviceInterafaceGUID and does not restrict itself to any USB VID/PID. Since our application software searches for Joulescopes using DeviceInterfaceGUID (see here and here), it failed to find the connected device on this machine. Joulescopes also use a PID issued by MCS with VID 0x16D0 rather than a dedicated VID issued to our company, which may exacerbate the problem.

Whoever uses libwdi should restrict their drivers to the specified VID/PID pairs. For some reason, this seems to not have happened with this computer and whatever software deployed libwdi. Unfortunately, I do not know what software used libwdi that caused this issue.

You can find more details on the Joulescope forum.

Expected Behavior

libwdi should play nicely with other software & devices. Drivers created with libwdi should only affect the target VID/PID pairs. In my opinion, the default libwdi setup should help users create drivers that only claim the specified VID/PID pairs, if it doesn't already. libwdi should not cause erratic or unexpected behavior with other devices.

pbatard commented 2 years ago

It appears that the default libwdi winusb INF template overwrites DeviceInterafaceGUID and does not restrict itself to any USB VID/PID

The second part is not correct.

If you install a standard driver with libwdi, it will explicitly restrict the driver installation to the VID/PID of the target device that was selected during installation.

Please be mindful that the template you see is filled at runtime by libwdi to insert the VID/PID before it is provided to Windows for driver installation.

For instance, the following is what will be generated in the inf if you select a device with a VID:PID of 045E:0289 in libwdi:

[Strings]
DeviceName = "XBox Controller"
VendorName = "Microsoft Corp."
SourceName = "XBox Controller Install Disk"
DeviceID   = "VID_045E&PID_0289"
DeviceGUID = "{28E17191-8803-4532-89A6-222A4581A803}"

(...)

[Manufacturer]
%VendorName% = libusbDevice_WinUSB,NTx86,NTamd64,NTarm

[libusbDevice_WinUSB.NTx86]
%DeviceName% = USB_Install, USB\%DeviceID%

[libusbDevice_WinUSB.NTamd64]
%DeviceName% = USB_Install, USB\%DeviceID%

[libusbDevice_WinUSB.NTarm]
%DeviceName% = USB_Install, USB\%DeviceID%

[USB_Install]
Include = winusb.inf
Needs   = WINUSB.NT

[USB_Install.HW]
AddReg = AddDeviceInterfaceGUID

(...)

[NoDeviceInterfaceGUID]
; Avoids adding a DeviceInterfaceGUID for generic driver

[AddDeviceInterfaceGUID]
HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%

(...)

This means that, since the .inf processing logic is libusbDevice_WinUSBlibusbDevice_WinUSBUSB_Install IF USB\%DeviceID% matchesUSB_Install.HWAddDeviceInterfaceGUID, if %DeviceID% doesn't match, which equates to a mismatch for "VID_045E&PID_0289", then the DeviceInterfaceGUID registry changes are not carried out.

In other words, what you request is already what libwdi is doing, which is to restrict the drivers to the specified VID/PID pairs.

Now, the one part that is correct is that we do insert a new DeviceInterfaceGUID when a user installs or overwrites the driver for a specific VID/PID. That's because we consider that, if a user is using libwdi then, it's because they aren't happy with the existing (or non existing) driver, which, if Microsoft OS descriptors are being used, should have already been installed to the user's satisfaction and not required the use of libwdi.

Therefore, I believe that your analysis of the issue is not accurate, because it most likely boils down to your customer, who should already have had a perfectly working WinUSB driver installed through the Microsoft OS descriptors, along with the DeviceInterfaceGUID you needed, deciding that they somehow weren't happy with that driver and choosing to override/overwrite it using libwdi (which, if they are just going to use to re-install WinUSB makes absolutely no logical sense... and, if they are going with another driver such a libusbK, will prevent your WinUSB based application from accessing it anyway, regardless of whether the DeviceInterfaceGUID is the one you want or not).

Well, if someone says: "I want to overwrite the driver settings for this specific device and start with a clean slate", that's is precisely what libwdi gives them, including a brand new DeviceInterfaceGUID, because we see very little reason why a customer would not want a new one then (since, if we preserved it, it'd mean that the end result would be virtually the same as what they already had, whereas getting a new DeviceInterfaceGUID is pretty much the only reason why you'd want to use libdwi to reinstall a WinUSB driver, if you already had WinUSB installed through the OS descriptors).

All in all then, I think your issue boils down to a user error.

Your customer probably thought they needed to manually install the WinUSB driver and didn't realise it had been done automatically for them. So they selected their device in Zadig/libwdi, ignored the field that told them that WinUSB was already installed for that device as well as the fact that the button explicitly says Replace driver (instead of the usual Install driver when no driver is installed), and replaced the generic WinUSB driver with the one generated by libwdi whereas they had absolutely no need of doing so.

Thus, unless I am misunderstanding your issue, I don't think there's much I want to do about users using my application when they had no reason to use it in the first place. Considering that installation of drivers is not a trivial operation, and that libwdi/Zadig were never designed for entry level users, we expect anyone using libwdi/Zadig to have some idea what they are doing and why. Therefore, if a customer starts to use it when they shouldn't, and it happens to overwrite the DeviceInterfaceGUID of their device (which again, is what I very much expect the majority of libwdi users who willingly choose to overwrite a driver do want), then I would say that it probably your job to let your customers know that they don't need oto bother about manually install WinUSB, because it gets installed automatically for them.

In other words, I think the issue simply boils down to an overzealous customer. And, considering that the cost/benefit ratio of trying to cater for such users (especially if it comes at the detriment of other users) is simply way too high for a free application, I really don't see anything that libwdi should to do any differently.

As such, I will close this issue.

mliberty1 commented 2 years ago

Thanks for the quick and detailed response, @pbatard !

To add more detail, my customer was using a lab computer where a lot of other software was installed. As far as I know, my customer did not do anything intentionally to install libwdi. It was likely installed by the software for some other instrument that he was using. Joulescopes also include the MS OS Descriptor versions 1 & 2, so the user should never be prompted to select a driver.

I did ask my customer to send the INF associated with libwdi, which was named oem92.inf. Here it is:

; WinUSB_Generic_Device.inf
; Copyright (c) 2010-2016 Pete Batard <pete@akeo.ie> (GNU LGPL)
[Strings]
DeviceName = "WinUSB Generic Device"
VendorName = "(Undefined Vendor)"
SourceName = "WinUSB Generic Device Install Disk"
DeviceID   = "MS_COMP_WINUSB"
DeviceGUID = "UNUSED"

[Version]
Signature   = "$Windows NT$"
Class       = "USBDevice"
ClassGuid   = {88bae032-5a81-49f0-bc3d-a4ff138216d6}
Provider    = "libwdi"
CatalogFile = WinUSB_Generic_Device.cat
DriverVer   = 02/10/2017, 6.1.7600.16385

[ClassInstall32]
Addreg = WinUSBDeviceClassReg

[WinUSBDeviceClassReg]
HKR,,,0,"Universal Serial Bus devices"
HKR,,Icon,,-20

[Manufacturer]
%VendorName% = libusbDevice_WinUSB,NTx86,NTamd64,NTarm

[libusbDevice_WinUSB.NTx86]
%DeviceName% = USB_Install, USB\%DeviceID%

[libusbDevice_WinUSB.NTamd64]
%DeviceName% = USB_Install, USB\%DeviceID%

[libusbDevice_WinUSB.NTarm]
%DeviceName% = USB_Install, USB\%DeviceID%

[USB_Install]
Include = winusb.inf
Needs   = WINUSB.NT

[USB_Install.Services]
Include    = winusb.inf
AddService = WinUSB,0x00000002,WinUSB_ServiceInstall

[WinUSB_ServiceInstall]
DisplayName   = "WinUSB - Kernel Driver 02/10/2017 6.1.7600.16385"
ServiceType   = 1
StartType     = 3
ErrorControl  = 1
ServiceBinary = %12%\WinUSB.sys

[USB_Install.Wdf]
KmdfService = WINUSB, WinUsb_Install

[WinUSB_Install]
KmdfLibraryVersion = 1.11

[USB_Install.HW]
AddReg = NoDeviceInterfaceGUID

[NoDeviceInterfaceGUID]
; Avoids adding a DeviceInterfaceGUID for generic driver

[AddDeviceInterfaceGUID]
HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%

[USB_Install.CoInstallers]
AddReg    = CoInstallers_AddReg
CopyFiles = CoInstallers_CopyFiles

[CoInstallers_AddReg]
HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01011.dll,WdfCoInstaller","WinUSBCoInstaller2.dll"

[CoInstallers_CopyFiles]
WinUSBCoInstaller2.dll
WdfCoInstaller01011.dll

[DestinationDirs]
CoInstallers_CopyFiles = 11

[SourceDisksNames]
1 = %SourceName%

[SourceDisksFiles.x86]
WinUSBCoInstaller2.dll = 1,x86
WdfCoInstaller01011.dll = 1,x86

[SourceDisksFiles.amd64]
WinUSBCoInstaller2.dll = 1,amd64
WdfCoInstaller01011.dll = 1,amd64

[SourceDisksFiles.arm]
WinUSBCoInstaller2.dll = 1,arm
WdfCoInstaller01011.dll = 1,arm

It's great to hear that libwdi already respects VID/PID. I suspect that some user of libwdi released software that does not respect VID/PID or possibly just used all of the MCS VID. Another possible option is that my customer or a colleague tried using libwdi for some other purpose long ago, and forgot about it.

Regardless, I now understand that libwdi already has the "expected behavior" I listed above. I agree that closing the issue without action is the right call. Thanks for quickly considering this issue and for your explanation!

pbatard commented 2 years ago

That .inf indicates that they manually installed the libwdi WCID generic driver, which again, they should not have had to do.

WCID is pretty much the same as WinUSB installation through OS descriptors (see here), and we do provide the ability to install such a driver in Zadig for older versions of Windows (notably Windows 7) where, unlike later versions of Windows, the OS does not already have a generic .inf for WinUSB.

And we also use this if a user wants to install a generic WCID driver for something else than WinUSB, which is why we don't only limit the installation of WCID for Windows 7 or earlier.

However, installing the generic WCID driver using Zadig should not have altered the DeviceInterfaceGUID (hence the NoDeviceInterfaceGUID and DeviceGUID = "UNUSED" you see in the inf) so I suspect that if the DeviceInterfaceGUID changed its probably because the user first installed the non-generic driver, found that it didn't do what they expected it to do, then went back to Zadig to install the generic WCID driver out of frustration, leading to the current situation.

Of course, it's difficult to "guess" what really happened, but what's clear is that, if the WinUSB driver installation through OS descriptor worked as expected, that customer should never had have to use Zadig/libwdi to overwrite the driver. And the presence of the .inf files, along with the alteration of the DeviceInterfaceGUID that should have been set through the OS descriptors seems to corroborate the idea that they went and ran Zadig/libwdi to replace the original WinUSB driver, even as there most likely was no reason to do so.

Or somebody on the computer needed to install a driver for some other USB device (that didn't have the WinUSB OS descriptors) and selected your USB device by mistake, which would also explain why they installed both the non-generic and then the generic driver out of desperation.

Hopefully, this should be a very limited occurrence...

mliberty1 commented 2 years ago

As far as I know, this installation issue has not happened before, so let's hope it's a one-time occurrence!

I also don't know the history of this particular computer. It could originally have been Windows from the WinUSB "before times", and they could have needed WCID at one point.

If it does happen again, I now understand, and I will be equipped to better troubleshoot. I have my forum post and this thread to solve it quickly. Thank you for your time and open source contributions!