Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


Before Posting...

Please check out the Community Guidelines in the Announcements and Administration Category.

Possible causes of STATUS_DEVICE_POWER_FAILURE for a virtual display adapter?

scott_smithscott_smith Member Posts: 83

Our IddCx-based display adapter driver installs and works fine for most users (we target Windows 10 exclusively). Once or twice per week, however, a user requests support, and I eventually find in Device Manager that their device instance (a virtual display adapter with no hardware backing) is displaying the yellow caution icon. Checking the device's status, I see STATUS_DEVICE_POWER_FAILURE.

Unfortunately, I've never been able to reproduce this situation in a local test environment, so I'm left to guessing as to what the cause might be...

Of the PnpPowerCallbacks, I only created D0Entry and D0Exit handlers. The thinking was that I didn't need to handle any more than the minimum power callbacks, since ours is a software device.

When I started seeing reports of this error, I thought perhaps these specific users had laptops configured with non-default power plan settings. "Perhaps Windows 10 expects that a driver explicitly confirm its capability to enter some low-power mode, and because mine is missing some behavior, Windows refuses to start it?"

Unfortunately, I've tried reproducing this locally on a laptop by setting various power management plan settings, but everything works fine.

Can anyone help shed light on this?


Scott Smith
Windows Developer since 1989

«1

Comments

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    Not sure if this helps, but it might be worth a try: If Device Manager shows the yellow caution icon, then select "Show Hidden Devices" in Device Manager menu. If there is a second hidden IddCx Device instance of the same kind, then uninstall it. Then disable/enable the original visible IddCx instance and see if it works now. In case this helps, please let us know here.

    Marcel Ruedinger
    datronicsoft

  • scott_smithscott_smith Member Posts: 83

    Hi Marcel. Thanks for the reply. I'll let you know.


    Scott Smith
    Windows Developer since 1989

  • scott_smithscott_smith Member Posts: 83

    Hey Marcel,

    I'm checking with a few users who've reported the problem in our current driver. I'll let you know if it clears out the STATUS_DEVICE_POWER_FAILURE error.

    Meanwhile, I've been testing a refactored "v2.0" video driver, and I ran into this maddening problem where attempts to use CreateFile to open a handle to the display adapter device were failing with an "AccessDenied" error.

    While investigating this, there were a few times where the test containing the CreateFile call suddenly started succeeding. At first, I assumed that last thing I'd changed in the code was responsible. Then at some future point (probably after a reboot), things would mysteriously go back to failing again. It's been driving me crazy.

    After your response, I tried disabling and re-enabling the adapter device, prior to running my test. The problem goes away until I reboot. I've tried this a few times, and it's consistent.

    Whatever this is, disabling/re-enabling seems to fix it temporarily. Sounds like you might be investigating this as well. Any insights as to what's going on?

    --Scott


    Scott Smith
    Windows Developer since 1989

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    First quick thought: These things usually happen when using non-Plug'n'Play function WdfDeviceCreateSymbolicLink instead of Plug'n'Play function WdfDeviceCreateDeviceInterface. Much more when known WDDM mechanisms (e.g. TDR) are at work.

    The second thought is a bit frightening, though: Maybe these problems are resulting from using an upper edge driver interface which does not belong to you? The IddCx driver's upper edge actually belongs to the upper filter driver sitting on top of the IddCx UMDF device: IndirectKmd.sys

    There are two layers above the actual UMDF driver implementation:
    1. First the IndirectKmd.sys filter driver
    2. Second, the IddCx framework itself hides the driver's primary WDFQueue from the developer.

    Marcel Ruedinger
    datronicsoft

  • scott_smithscott_smith Member Posts: 83

    I'm still waiting for feedback from a user who was seeing this STATUS_DEVICE_POWER_FAILURE problem in our v1 driver.

    First quick thought: These things usually happen when using non-Plug'n'Play function WdfDeviceCreateSymbolicLink instead of Plug'n'Play function WdfDeviceCreateDeviceInterface. Much more when known WDDM mechanisms (e.g. TDR) are at work.

    This is a WDF driver based upon the IddCx sample from Microsoft (UMDF 2.x). I do call WdfDeviceCreateDeviceInterface in EvtDriverDeviceAdd after a successful call to WdfDeviceCreate:

    ntStatus = ::WdfDeviceCreateDeviceInterface(hWdfAdapterDevice, &GUID_DEVINTERFACE_IMVD, nullptr);
    

    Maybe these problems are resulting from using an upper edge driver interface which does not belong to you?

    This interface is my own custom set of IOCTL commands that allow configuration of connected displays. There's no actual data transfer (reading/writing), just config functions. But none of that gets called until after CreateFile succeeds:

    // A custom interface GUID ({580FE7DF-137A-45F1-9998-7B1F006CDC43}) so that apps can find and communicate with this device
    DEFINE_GUID(GUID_DEVINTERFACE_IMVD, 0x580fe7df, 0x137a, 0x45f1, 0x99, 0x98, 0x7b, 0x1f, 0x0, 0x6c, 0xdc, 0x43);
    

    One interesting thing to add from my testing of the V2 driver. At one point, I waited too long in the debugger and the watchdog asserted and marked the device as not working (as expected).

    I disabled and then enabled the device to reset its status to "working properly" again. Then I ran my test and the CreateFile called failed with AccessDenied.

    Here's the interesting part: I had to cycle the device (disabled + enable) again, and then the test's CreateFile call succeeded. It's as though the driver has to initialize successfully, and then initialize again.

    Could I be making my WdfDeviceCreateDeviceInterface call at the wrong time (e.g., too early)?


    Scott Smith
    Windows Developer since 1989

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    It is IndirectKmd.sys and IddCx.dll who get asked first if the application's CreateFile(...) call succeeds (and if the file is shareable, etc.). It is not really documented if their design allows application access for the lowest layer UMDF part of the driver (many kernel mode miniport driver models are NOT designed for application access).

    The mere presence of the callback IddConfig.EvtIddCxDeviceIoControl could be interpreted as a positive hint. Unfortunately the purpose of this callback is not documented. It could also be intended only for legacy IOCTL_VIDEO_Xxx from the operating system. The comment in the MS WDK Sample you mentioned might be interpreted as a negative hint: "...is called by the OS when an IO control request needs processing by the driver".

    To cut a long story short: It is already a safe choice, not to convey data over this interface. Possibly you could also convey your control information in a different way?

    Marcel Ruedinger
    datronicsoft

  • scott_smithscott_smith Member Posts: 83

    Since the interface string I get is a symlink, I used SysInternals WinObj to locate the item and see what actual device it refers to:

    Name                                                        Type           Symlink
    --------------------------------------------------------   ------------   ----------------
    [email protected]#0000#{1ca05180-a699-450a-9a0c-de4fbe3ddd89}   SymbolicLink   \device\00000001   (GUID_DISPLAY_DEVICE_ARRIVAL)
    [email protected]#0000#{1ca05181-a699-450a-9a0c-de4fbe3ddd89}   SymbolicLink   \device\00000001   (Undocumented - related to above?)
    [email protected]#0000#{580fe7df-137a-45f1-9998-7b1f006cdc43}   SymbolicLink   \device\00000001   (GUID_DEVINTERFACE_IMVD - my custom interface)
    [email protected]#0000#{5b45201d-f2f2-4f3b-85bb-30ff1f953599}   SymbolicLink   \device\00000001   (GUID_DEVINTERFACE_DISPLAY_ADAPTER)
    

    I then go look up that device under the Device node in the tree, and check the permissions on that. Sure enough, if I do it before I've disabled/enabled the adapter instance in Device Manager (e.g., after an OS restart), I can't view properties on the mapped device ("Error opening \Device\00000001: Access is denied."). But once I've disabled/enabled the adapter, I can view the properties with no problem.


    Scott Smith
    Windows Developer since 1989

  • scott_smithscott_smith Member Posts: 83

    Possibly you could also convey your control information in a different way?

    Any suggestions?


    Scott Smith
    Windows Developer since 1989

  • scott_smithscott_smith Member Posts: 83

    More info:

    I stepped into the CreateFile call with WinDbg, then set a process-specific breakpoint on the kernel side.

    IopParseDevice is where the Access Denied error occurs:

    --- User Mode ---
    mytest.exe
    CreateFile
    ntdll!NtCreateFile
    --- Kernel Mode ---
    nt:IopCreateFile
    nt:ObOpenObjectByNameEx
    nt:ObpLookupObjectName
    nt:IopParseDevice [BANG]
    (nt:IofCallDriver does not get called)

    This is the definition I was able to find for IopParseDevice:

    NTSTATUS
    IopParseDevice(
      IN  PVOID ParseObject,
      IN  PVOID ObjectType,
      IN  PACCESS_STATE AccessState,
      IN  KPROCESSOR_MODE AccessMode,
      IN  ULONG Attributes,
      IN OUT PUNICODE_STRING CompleteName,
      IN OUT PUNICODE_STRING RemainingName,
      IN OUT PVOID Context OPTIONAL,
      IN  PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
      OUT PVOID *Object
      );
    

    I wasn't able to make much sense of the arguments, except for the two in/out strings (" " and "" respectively).

    I'll continue stepping through IopParseDevice in hopes of getting closer to the reason for the Access Denied result...


    Scott Smith
    Windows Developer since 1989

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    Only two more things left for me to say:

    1. I am currently trying to get public info from Microsoft about the purpose of the IddCX Upper-Edge Ioctl-Interface. If successful, it will probably take a few days...

    2. Coming back to the timing question above: In this kind of WDDM IddCx driver, it would defintely be the wrong time (too early) to process EvtIddCxDeviceIoControl before having received the event EvtIddCxAdapterInitFinished. Instead of calling WdfDeviceCreateDeviceInterface later, it might be more helpful using a WDF Queue which is initially stopped and started only in EvtIddCxAdapterInitFinished.

    Marcel Ruedinger
    datronicsoft

  • scott_smithscott_smith Member Posts: 83
    edited April 19

    Instead of calling WdfDeviceCreateDeviceInterface later, it might be more helpful using a WDF Queue which is initially stopped and started only in EvtIddCxAdapterInitFinished.

    Interesting. I based my code on Windows-driver-samples\general\echo\umdf2\driver\AutoSync\queue.c...:

    // Create a device interface for this virtual display adapter device
    ntStatus = ::WdfDeviceCreateDeviceInterface(hWdfAdapterDevice, &Public::GUID_DEVINTERFACE_IMVD, nullptr);
    
    if (NT_SUCCESS(ntStatus))
    {
        // Create and initialize an I/O queue for the adapter device
        . . .
    
        // Configure a default queue so that requests that aren't configure-forwarded (using WdfDeviceConfigureRequestDispatching to
        // go to other queues) get dispatched here.
        WDF_IO_QUEUE_CONFIG config{};
        WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&config, WdfIoQueueDispatchSequential);
        config.PowerManaged       = WdfFalse; //WdfUseDefault TODO
        config.EvtIoDeviceControl = OnWdfIoQueueIoDeviceControl;
    
        // Fill in a callback for destroy, and our CQueue struct size
        WDF_OBJECT_ATTRIBUTES attributes{};
        WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CQueue);
        attributes.EvtCleanupCallback = OnQueueContextCleanup;       // Called when the object is deleted
    
        // Set synchronization scope on queue and have the timer to use queue as the parent object so that queue and timer callbacks
        // are synchronized with the same lock.
        attributes.SynchronizationScope = WdfSynchronizationScopeQueue;
    
        // Create and configure an I/O queue for the adapter device
        WDFQUEUE hWdfQueueOut = nullptr;
        ntStatus = ::WdfIoQueueCreate(hWdfAdapterDevice, &config, &attributes, &hWdfQueueOut);
        . . .
    }
    

    ...but the echo sample was queuing reads and writes. Once I'd boiled everything down, it seemed to me that the queue wasn't necessary in my particular case, so I don't create the timer.

    I'm only sending (synchronous) IOCTL commands to the adapter, and they result in a call to my adapter's EvtIddCxDeviceIoControl callback. I found that the queue's EvtIoDeviceControl callback never got called (which makes sense, because I don't read or write to the device).

    Am I correct in my belief that the queue serves no purpose here?


    Scott Smith
    Windows Developer since 1989

  • scott_smithscott_smith Member Posts: 83
    edited April 19

    Another update

    I've been able to trace the original CreateFile call into the kernel. nt!IopParseDevice calls nt!SeAccessCheck with slightly different parameters, depending upon whether I've disabled/enabled my adapter device.

    Notably, the provided SecurityDescriptor's SECURITY_DESCRIPTOR_CONTROL member changes:

    (after Windows restart)
    0x9814 (SE_SELF_RELATIVE | SE_DACL_PROTECTED | SE_SACL_AUTO_INHERITED | SE_SACL_PRESENT | SE_DACL_PRESENT)
    
    (after disable/enable adapter)
    0x8014 (SE_SELF_RELATIVE |                                              SE_SACL_PRESENT | SE_DACL_PRESENT)
    

    I'm running the test after restarting Windows (Access Denied), then I disable/enable the adapter and immediately run the same test again. I break on nt!SeAcccessCheck and record the parameters passed in.

    I don't know enough about Windows security stuff to understand what these two flags signify in the larger context. I also don't know if this kind of thing is expected behavior, or part of my specific problem...


    Scott Smith
    Windows Developer since 1989

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    Doesn't seem to lead any closer to a solution.
    Ever tried to assign a security descriptor in the INF file (see example below)?

    [MyDevice_HardwareDeviceSettings]
    HKR,, "UpperFilters", %REG_MULTI_SZ%, "IndirectKmd"
    ...
    HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;WD)(A;;GA;;;RC)"

    Marcel Ruedinger
    datronicsoft

  • scott_smithscott_smith Member Posts: 83

    Doesn't seem to lead any closer to a solution.
    Ever tried to assign a security descriptor in the INF file (see example below)?

    No, but I will now. Thanks. Didn't realize it was an option...


    Scott Smith
    Windows Developer since 1989

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    Coming back to my previous pondering about the purpose of EvtIddCxDeviceIoControl.

    There is a clear public statement from Microsoft now. WDK docs were just updated as follows (quote):

    IDD_CX_CLIENT_CONFIG structure
    EvtIddCxDeviceIoControl
    This function can be used for communication between a user session process and the driver; typically this communication channel is used by a companion application to control some aspect of the driver.

    Marcel Ruedinger
    datronicsoft

  • scott_smithscott_smith Member Posts: 83

    So if I'm interpreting that correctly, it says that the approach I'm taking is the intended one? It ought to work?


    Scott Smith
    Windows Developer since 1989

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    Correct - if you do it right, then it will work!

    So what could still be wrong? Maybe your user mode Plug'n'Play implementation? Maybe DIGCF_PRESENT flag forgotten when building the set of device interfaces? Thus trying to access a device interface that is not necessarily active?

    PS: Too extensive use of old (but not osolete) kernel mode debugging techniques might not be concluive here. This is a User Mode Driver. WDK docs explain various UMDF debugging techniques which might be worth a closer look...

  • scott_smithscott_smith Member Posts: 83

    Maybe your user mode Plug'n'Play implementation?

    I did factor Microsoft's everything-in-a-single-source-file sample code into separate files/classes. It's possible that I introduced some subtle change in the order of initialization steps. I'm going to compare mine against the sample (call-by-call) to see whether they're different.

    Maybe DIGCF_PRESENT flag forgotten when building the set of device interfaces?

    I'm actually using CfgMgr32 APIs in my console test program, and I am specifying CM_GET_DEVICE_INTERFACE_LIST_PRESENT:

    _Check_return_ //
    static std::wstring GetDevicePath(REFGUID interfaceClassGuid)
    {
        std::wstring result;
    
        // Request the minimum buffer size to contain the (NUL-delimited) list of devices that support the specified interface
        ULONG listSizeInWords = 0;
        auto  cr = ::CM_Get_Device_Interface_List_SizeW(
            &listSizeInWords,                           // Pointer to a location that receives the required length, in characters
            const_cast<LPGUID>(&interfaceClassGuid),    // GUID that identifies a device interface class
            nullptr,                                    // Device instance ID
            CM_GET_DEVICE_INTERFACE_LIST_PRESENT);      // Flags
        if (cr != CR_SUCCESS)
        {
            std::wcerr << L"\tERROR: Unable to retrieve device interface list size; CONFIGRET: " << Text::CrToString(cr).c_str();
        }
        else if (listSizeInWords <= 1)
        {
            std::wcerr << L"\tWARNING: No active device interfaces found. Is the immersed-display-driver loaded?" << std::endl;
        }
        else
        {
            // Use 'fill' ctor to preallocate (and initialize with NULs) the minimum required buffer to contain the list
            std::wstring deviceItfList(listSizeInWords, L'\0');
    
            // Query the (NUL-delimited, double-NUL-terminated) list of device paths
            cr = ::CM_Get_Device_Interface_ListW(
                const_cast<LPGUID>(&interfaceClassGuid),    // GUID that identifies the device interface class
                nullptr,                               // Device instance ID
                &deviceItfList[0],                     // Buffer to receive list
                listSizeInWords,                       // Length (in wchar_t), of the provided buffer
                CM_GET_DEVICE_INTERFACE_LIST_PRESENT); // Flags
            if (cr != CR_SUCCESS)
            {
                std::wcerr << L"\tERROR: Unable to retrieve device interface list; CONFIGRET: " << Text::CrToString(cr).c_str();
            }
            else
            {
                // Convert the NUL-delimited list to a vector<wstring>
                auto deviceInterfaces = Text::Split(deviceItfList.c_str());
    
                ASSERT(!deviceInterfaces.empty()); // We checked listSizeInWords above, so this shouldn't be empty
    
                // We're looking for our custom driver interface, so there should only be ONE device in the list
                if (1 < deviceInterfaces.size())
                {
                    std::wcerr << L"\tWARNING: More than one device interface instance found. Selecting FIRST matching device."
                               << std::endl;
                }
    
                result = deviceInterfaces[0];
            }
        }
    
        return result;
    }
    

    Also, I'm getting the same Device Path string both before and after the disable-enable:

    c:\display-driver-v3\Windows\bin\Debug>display-driver-ioctl-tester.exe
    
    INFO: Got device path: "\\?\ROOT#DISPLAY#0000#{580fe7df-137a-45f1-9998-7b1f006cdc43}"
    ERROR: Failed to open the device "\\?\ROOT#DISPLAY#0000#{580fe7df-137a-45f1-9998-7b1f006cdc43}"; Access is denied.
    
    (here I manually disable and re-enable the driver)
    
    c:\display-driver-v3\Windows\bin\Debug>display-driver-ioctl-tester.exe
    
    INFO: Got device path: "\\?\ROOT#DISPLAY#0000#{580fe7df-137a-45f1-9998-7b1f006cdc43}"
    
    (...successful output follows...)
    

    Too extensive use of old (but not obsolete) kernel mode debugging techniques might not be conclusive here.

    I was hoping that if I traced the CreateFile API to the point of failure (down in the kernel), I'd have an 'Ah Hah!' moment. Unfortunately, I didn't know how to interpret the results. It was an interesting exercise, though. I ordered Windows Internals 1 & 2, edition 7 yesterday (along with some driver development books) so I can learn more about this.

    This is a User Mode Driver. WDK docs explain various UMDF debugging techniques which might be worth a closer look...

    I'm setting that up again so I can record the actual flow through the driver. Once I had the driver working, I'd switched back to the Visual Studio debugger for the IOCTL stuff, because it's so much more familiar.

    But now I need to break on driver load and view trace output. I will have a look at the UMDF debugging techniques in the WDK docs again to see if I missed anything, but IIRC, I need to go back to WinDbg..., WdfVerifier, TraceView, etc. for that.

    Cheers.


    Scott Smith
    Windows Developer since 1989

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 8,560

    I know less than nothing about display drivers. But...

    was hoping that if I traced the CreateFile API to the point of failure (down in the kernel), I'd have an 'Ah Hah!' moment. Unfortunately, I didn't know how to interpret the results.

    You showed that the failure occurred in IopParseDevice (the “parse” method for DEVICE_OBJECT). This is expected, as this is the function in the I/O Manager where the Create IRP is built and sent to the driver.

    At SOME point, I’d expect IopParseDevice to call SeAccessCheck. Either step through IopParseDevice (a real snoozer) or perhaps start by setting a breakpoint on SeAccessCheck?

    There are two issues here: Why are you getting back access denied, and if this is related to the ACL what is the ACL set to?

    I hate to ask the obvious, but have you looked at the ACL on the Device Object in question?

    Don’t know if any of that is helpful. Like I said, I can barely find the power button to turn on my display device, I know so little about this particular device class.

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    Thanks for jumping in Mr. Viscarola. Your advice emphasizes my suggestion to try the security descriptor in the INF file. Feedback is still pending...

    Probably not much knowledge about the display device class needed any more to hang around in this thread.
    We have an OS supplied function driver (WUDFRd.sys) together with an OS supplied upper filter (IndirectKmd.sys). The chances of finding any problem with these OS supplied drivers is magnitudes smaller than pinpointing the problem either at the application code or the UMDF driver DLL code (e.g. something dangling). Hence my comment about kernel mode debugging (for those who didn't notice: quoting a line from a very popular 2015 movie "Old but not obsolete!").

    Two potential outcomes:

    1. Bug or potential usage problem with OS supplied display drivers:
      Very small probability.

    2. Needle in the haystack of developer's code:
      Very high probability.

    How far can/shall we proceed here?

    Marcel Ruedinger
    datronicsoft

  • scott_smithscott_smith Member Posts: 83
    edited April 23

    Hi Peter,

    Thanks for chiming in!

    ...this is the function in the I/O Manager where the Create IRP is built and sent to the driver.
    At SOME point, I’d expect IopParseDevice to call SeAccessCheck.

    Yes indeed. I was able to determine that SeAccessCheck was returning a different result depending on whether or not I'd cycled the enabled state of the device.

    Either step through IopParseDevice (a real snoozer) or perhaps start by setting a breakpoint on SeAccessCheck?

    I did both. WinDbg is only showing me the assembly, with symbols. I know enough about the calling/return convention that I was able to painstakingly figure out what the arguments/returns were from IopParseDevice and SeAccessCheck. I have some old (outdated) NT source code I can (mostly) follow along by watching for specific calls, but my x86-Fu isn't strong enough for me to grok what's going on at source level most of the time.

    There are two issues here: Why are you getting back access denied, and if this is related to the ACL what is the ACL set to?
    I hate to ask the obvious, but have you looked at the ACL on the Device Object in question?

    I manually examined the arguments going into SeAccessCheck for both (failure/success) cases. In my notes below, values are in hex and differences between cases are called out with "(Fail)" and "(Success)":

    IN PSECURITY_DESCRIPTOR SecurityDescriptor
        {
           UCHAR Revision .. 0x01
           UCHAR Sbz1 ...... 0x00
           SECURITY_DESCRIPTOR_CONTROL Control
                (Fail) ..... 0x9814 (SE_SELF_RELATIVE | SE_DACL_PROTECTED | SE_SACL_AUTO_INHERITED | SE_SACL_PRESENT | SE_DACL_PRESENT)
                (Success) .. 0x8014 (SE_SELF_RELATIVE |                                              SE_SACL_PRESENT | SE_DACL_PRESENT)
           PSID Owner
           {
               BYTE  Revision ................................ 01
               BYTE  SubAuthorityCount ....................... 02
               SID_IDENTIFIER_AUTHORITY IdentifierAuthority .. 00 00 00 00 00 05 [SECURITY_NT_AUTHORITY]
               DWORD SubAuthority[ANYSIZE_ARRAY]
               ................................................[0] 00000020 [NETWORK_SERVICE]
               ................................................[1] 00000220 [BUILTIN_ADMINISTRATORS]
           }
           PSID Group
           {
               BYTE  Revision ................................ 01
               BYTE  SubAuthorityCount ....................... 01
               SID_IDENTIFIER_AUTHORITY IdentifierAuthority .. 00 00 00 00 00 05 [SECURITY_NT_AUTHORITY]
               DWORD SubAuthority[ANYSIZE_ARRAY]
               ................................................[0] 00000012 [RESTRICTED_CODE]
           }
           PACL Sacl
           {
                BYTE AclRevision .. 02
                BYTE Sbz1 ......... 00
                WORD AclSize ...... 001c
                WORD AceCount ..... 0001
                WORD Sbz2 ......... 0000
                .................... 11 00 14 00 01 00 00 00 01 01 00 00 00 00 00 10 00 10 00 00
           }
           PACL Dacl
           {
                BYTE AclRevision .. 02
                BYTE Sbz1 ......... 00
                WORD AclSize
                    (Fail) ........ 001c
                    (Success) ..... 006c
                WORD AceCount
                    (Fail) ........ 0001
                    (Success) ..... 0004
                WORD Sbz2 ......... 0000
                    (Fail) ........ 00 00 14 00 ff 01 1f 00 01 01 00 00 00 00 00 05 12 00 00 00
                    (Success) ..... 00 00 14 00 bf 01 12 00 01 01 00 00 00 00 00 01 00 00 00 00
           }
        } // PSECURITY_DESCRIPTOR SecurityDescriptor
    
    IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
        PACCESS_TOKEN ClientToken ........................ 00000000`00000000
        SECURITY_IMPERSONATION_LEVEL ImpersonationLevel .. 0x00000000 [SecurityAnonymous]
        PACCESS_TOKEN PrimaryToken ....................... (non-null in both cases, but didn't record this)
        PVOID ProcessAuditId
            (Fail) ....................................... 0x00000000000006d4 (???)
            (Success) .................................... 0x0000000000001d2c (???)
    IN BOOLEAN SubjectContextLocked ......... TRUE
    IN ACCESS_MASK DesiredAccess ............ 00 10 0080 (SYNCHRONIZE | FILE_READ_ATTRIBUTES)
    IN ACCESS_MASK PreviouslyGrantedAccess .. 00 00 0000
    OUT PPRIVILEGE_SET * Privileges ......... (non-null in both cases)
    IN PGENERIC_MAPPING GenericMapping
        ACCESS_MASK GenericRead ..... 00 12 0089 (SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA)
        ACCESS_MASK GenericWrite .... 00 12 0116 (SYNCHRONIZE | READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | FILE_WRITE_DATA)
        ACCESS_MASK GenericExecute .. 00 12 00a0 (SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_EXECUTE)
        ACCESS_MASK GenericAll ...... 00 1f 01ff (SYNCHRONIZE | DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | FILE_WRITE_ATTRIBUTES | ...all...)
    IN KPROCESSOR_MODE AccessMode .......... 0x01 [UserMode]
    OUT PACCESS_MASK GrantedAccess ......... (non-null in both cases)
    OUT PNTSTATUS AccessStatus ............. (non-null in both cases)
    

    I'm reading up on ACLs, access tokens, privileges, security descriptors and SIDs right now. I've never really understood Windows security very well.


    Scott Smith
    Windows Developer since 1989

  • scott_smithscott_smith Member Posts: 83

    Hi Marcel,

    1. Needle in the haystack of developer's code:
      Very high probability.

    I was fairly certain that I'd introduced this during refactoring and enhancement of the V1 driver to the V2 driver. I was typing up a response to your last post this morning when I realized that I'd never actually checked to confirm that this doesn't happen with the V1 driver.

    The V1 driver didn't have a custom IOCTL interface, so I think I initially discarded the idea. But it's a simple matter to add a single WdfDeviceCreateDeviceInterface API call (in the same place) to the V1 code, so I did that, built it and ran the console test against it...

    The V1 driver behaves the same; it initially fails the CreateFile call, but succeeds after I disable/re-enable the device in Device Manager.

    So, I'm still betting this is down to something I did wrong, but I don't need to go through the tedious process of looking for some subtle difference between my V1 and V2 drivers. Whatever this is, it was present from the beginning. I only noticed recently because the V1 driver didn't have a custom interface.

    Your advice emphasizes my suggestion to try the security descriptor in the INF file

    Agreed. I'm reading up on Windows security at the moment. I've dealt with it intermittently in the past, but always in a yak shaving context. This time I'm going to try to understand it thoroughly enough that I don't forget it all before I need it again.

    I'll try your suggestion and report back as soon as I figure out what my security descriptor should be...

    Thanks!


    Scott Smith
    Windows Developer since 1989

  • scott_smithscott_smith Member Posts: 83

    Oh, and I'm also going to build the Microsoft example that V1 was based upon, and test that too. I'll let you know.


    Scott Smith
    Windows Developer since 1989

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    You are really coming down on this thing, aren't you?
    I like it!
    And who knows - maybe we will even really find a bug in the WDK IddCx sample or framework?
    Wouldn't be the first one I found (last one was in the 2007 Wave Cyclic audio sample - confirmed and fixed by MS).
    IddCx framework is still very young (introduced in 2016 with Win 10 1607).
    So the chances aren't all that bad ;-)

    Marcel Ruedinger
    datronicsoft

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 8,560

    There's are WinDbg extensions !sd and !acl, in case they'd help. The ACL isn't useful unless you can actuially read it. ;-)

    This is extremely strange. It's GOT to be something very simple that's crossing you up. Hmmmm... wish I could offer-up more useful suggestions. I assume you've got Driver Verifier and WDF Verifier all enabled. And I assume that you've checked the log. Geez... who's changing the ACL on the device, when, and more interestingly WHY?

    Peter

    Peter Viscarola
    OSR
    @OSRDrivers

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    Mr. Viscarola,
    before spending too much time on this, you might probably want to know why I supplied a security descriptor for the INF file. I wanted my INF based security descriptor (which doesn't require admin privileges) to overrule the PDO security. Careful - this PDO is created using SwDeviceCreate(...) which can also specify a security descriptor. I wanted to avoid all these details and eliminate exactly these degrees of freedom which are confusing us now. Unfortunately, my suggestions haven't been followed yet...

    Marcel Ruedinger
    datronicsoft

  • scott_smithscott_smith Member Posts: 83
    edited April 24

    Oh, and I'm also going to build the Microsoft example that V1 was based upon, and test that too. I'll let you know.

    1. Made sure I had the latest copy of the Windows driver samples

    2. Modified driver (Windows-driver-samples\video\IndirectDisplay\IddSampleDriver) in the same way as above:

    ...add a single WdfDeviceCreateDeviceInterface API call (in the same place)

    1. Installed on two different test machines, and ran my console tester.

    Issue exists with the sample driver

    CreateFilecall returns Access Denied on the initial test after install. After I cycle enabled on the device, the CreateFile call succeeds.

    I haven't tried specifying an SDDL in the .inf file yet -- still reading... I'll post here after I do


    Scott Smith
    Windows Developer since 1989

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169
    edited April 24

    Now you made me curious!

    I just tried the same myself...
    ...and surprise, surprise...
    ...yes, indeed, you are right!

    Quick further tests/observations:

    • Even happens without IddCx framework calls and IndirectKmd upper filter.
    • Only seems to disappear when changing the Setup Class in the INF file to something different than Display.

    Hmmmm - need to think about this...

    Marcel Ruedinger
    datronicsoft

  • Peter_Viscarola_(OSR)Peter_Viscarola_(OSR) Administrator Posts: 8,560
    edited April 24

    I’m starting to fell like this may have something to do with the very, very, ugly “propagating of security descriptors” through a dev node.

    That code, which dates back to almost ten years ago, was very subtle and reasonably complex. I wonder if it got broken. If you’re not aware of the issues, there’s an article here.

    Peter

    ETA: I just re-read that article... and, wow! The whole Device Object protection thing is even more complicated than I remembered. And I wrote that article. Maybe there’s something there that’ll help?

    Peter Viscarola
    OSR
    @OSRDrivers

  • Marcel_RuedingerMarcel_Ruedinger Member Posts: 169

    I don't want to be a smartass, but just one hint: If you finally listen to my advice, then you can proceed without even worrying about this.

    One of the reasons why I gave you this advice was the fact that I had discovered some customers of ours successfully using IddCx upper edge with my above mentioned security descriptor. I also found some other customers using a different security descriptor requiring administrative privileges.

    PS: Further research postponed to the next weekend.

    Marcel Ruedinger
    datronicsoft

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Developing Minifilters 24 May 2021 Live, Online
Writing WDF Drivers 14 June 2021 Live, Online
Internals & Software Drivers 27 September 2021 Live, Online
Kernel Debugging 15 November 2021 Live, Online