Unexpected black screen when using a custom Credential Provider
Hi all,
Some time ago I had a customer how had developed a custom credential provider to use with a third-party smartcard provider. This credential provider was a wrapper of MS Smartcard Credential Provider. They also put a credential provider filter in place to hide MS Smartcard Credential Provider.
Now, from time to time, user tried to do logon, selected her smartcard, and suddently the screen asking for credentials disappeared and they could only see a black screen. User had to press Ctrl+Alt+Sup to recover and get back to the initial logon screen, and try to enter credentials once more. It was very easy to reproduce the issue for her if she removed the smartcard and re-inserted it when she was being asked for her PIN, for example.
First of all, the black screen has an explanation. During logon, logonui.exe shows a maximized window to ask the user for credentials. If logonui.exe crashes for some reason, you will see a black screen which is actually the background of the winlogon desktop where logonui shows that maximized window.
So why did logonui.exe crashed in this case?
Logonui loads all credential providers at the beginning of its execution, and it doesn't unload them until it ends. When we filter the providers we are not unloading them. We are just removing them from a list of references to all those loaded providers, leaving the list with just the providers we want to use. But I repeat, the providers won't get unloaded.
When MS Smartcard Credential Provider gets loaded, it creates a thread to monitor card readers. This monitor thread will be running until we unload the provider. So taking into account how filters work, in customer's scenario we end up with 2 identical threads monitoring card readers at the same time, one created when logonui loads the MS Smartcard Credential Provider by itself, and one created when customer's provider loads its own instance of the MS Smartcard Credential Provider.
In this particular scenario, when the issue happened, logonui was crashing with an Access Violation exception caused by a memory corruption on the third-party smartcard provider, which was not thread-safe and was being used in both card reader monitor threads at the same time. The action of removing and inserting the card back made both threads to resume their work and try to get the credentials from the card, thus using the third-party smartcard provider at the same time.
So there could be two ways to solve this:
1) Use a thread-safe smartcard provider.
2) Get rid of one of those card reader monitor threads. The only way to achieve this would be to tell logonui not to load the MS Smartcard Credential Provider at all, as we don't need it and our custom provider is already loading it when needed.
Because a credential provider filter won't help here, we have to disable the MS Smartcard Credential Provider by adding REG_DWORD "Disabled"=1 under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\{8bf9a910-a8ff-457f-999f-a5ca10b4a885}.
Note: Customer also realized that user got a blank screen when she entered Ctrl+Alt+Sup, saw the credential providers, waited for a while without inserting the smartcard until Ctrl+Alt+Sup appeared again (because of winlogon timer), then she entered Ctrl+Alt+Sup, saw the providers once more, selected theirs, entered the card and Bang! Black screen once more!
In this scenario where winlogon timer causes the Ctrl+Alt+Sup window to appear again, the existing instance of logonui gets reused when trying to enter credentials once more. Under these circumstances, every time the user entered Ctrl+Alt+Sup, customer's credential provider ended up loading a new instance of MS Smartcard Credential Provider, thus creating a new reader monitoring thread every time. So when this issue happened, we had at least 2 reader monitor threads accessing their card at the same time. So same crash as before for the same reasons.
Customer had to modify their credential provider to avoid loading MS Smartcard Credential Provider more than once.
I hope this helps.
Regards,
Alex (Alejandro Campos Magencio)