OSRLogo
OSRLogoOSRLogoOSRLogo x Seminar Ad
OSRLogo
x

Everything Windows Driver Development

x
x
x
GoToHomePage xLoginx
 
 

    Thu, 14 Mar 2019     118020 members

   Login
   Join


 
 
Contents
  Online Dump Analyzer
OSR Dev Blog
The NT Insider
The Basics
File Systems
Downloads
ListServer / Forum
  Express Links
  · The NT Insider Digital Edition - May-June 2016 Now Available!
  · Windows 8.1 Update: VS Express Now Supported
  · HCK Client install on Windows N versions
  · There's a WDFSTRING?
  · When CAN You Call WdfIoQueueP...ously

On the Right Path -- Testing with Device Path Exerciser


The Device Path Exerciser, DC2, is one of the most powerful and important test tools in the DDK. Unfortunately, because of its power, it’s also one of the most complex tools in the DDK. Until recently, there was no good documentation for DC2. But, if you check the Windows Server 2003 (or later) DDK, you’ll see outstanding documentation! Check it out.

In this article, we’ll expand on that documentation a bit. We’ll also try to provide you with a few guidelines for how you can best use DC2 as a test tool for your driver. Pay attention, now! This is good stuff!

How Does DC2 Work?
DC2 is a user mode application that sends a wide variety of valid, unusual but valid, and absolutely perverse and invalid requests to a "Device Under Test". DC2’s tests are highly iterative. That is, tests are performed repeatedly, each time with (perhaps) slightly varied parameters. In a typical test run, DC2 might send a few hundred thousand requests to a driver that it’s testing!

One of the keys to understanding DC2 is realizing that there are two different categories of operational controls. They are:

  • How a Device Is Opened.
  • What Tests Are Performed on the Device (once it has been opened).

The first category above, How a Device Is Opened, is controlled by the "Basic Open Operations" and any additional open operations that you specify.

The second category above, What Tests Are Performed, indicate the tests that are run on the device for each successful open operation. For example, if 4 of 5 open operations succeed, then all the tests you specify will be executed on the Device Under Test 4 times: Once for each time one of the open operations succeeds.

Running Tests
DC2 tests are run from the command line. Its command line syntax is as follows:

DC2 [switches] [[/dr driver] | [devicename]]

The device(s) to be tested may be specified by referencing the driver name with the /dr switch. When this is selected, all devices created by the driver are tested. Alternatively, one device name may be specified on the command line. The syntax for this name must be the native Windows NT device name (that is, the name with the \device\ prefix attached).

While the test runs, the menu bar of the command window will display the active test. The criteria for passing any DC2 test is that the system does not crash, DC2 does not hang, and the Device Under Test behaves as expected by the developer. The fact that DC2 completed successfully (without hanging or crashing) is confirmed by the message "ALL TESTS COMPLETE" appearing as the last text line of DC2.LOG and on the console.

Logging
DC2’s logging otions are both highly flexible, and complex. This is because DC2 creates four different log files, each with a different purpose. The contents of three of these log files can be controlled by the user. In fact, the test logging options that are chosen can have a dramatic effect on the amount of time required to run a set of DC2 tests. So, choose wisely! In this section, we’ll describe the options that control two of the most common logs: The main test log (DC2.LOG) and the diagnostic log (DIAGS.LOG).

The main log that DC2 creates is named, quite reasonably, DC2.LOG. This file logs the tests that are performed. DC2s tests are organized into Categories. Test categories are what are selected via testing options. Within each test category there may be one or more test Groups. Test groups comprise sets of related tests within a single category. Within a test group, there are individual tests.

You can use the /ltX option (where "X" varies) to specify the level of logging performed by DC2 in the DC2.LOG file. /ltc writes one entry to the log indicating the start and end of each test category. /ltg writes one entry to the log indicating the start and end of each test group. /ltt writes an entry to the log for each individual test performed. Each of these logging options causes DC2 to take successively longer to run, as more data is logged. The default logging level for DC2.LOG is /ltc.

The diagnostic log, named DIAGS.LOG, was designed to contain diagnostic information about each individual test that is run. You have to be very careful about how much detail you ask for here. Asking for too much information to be logged can change your test run time from 2 seconds to 2 hours (no joke).

The /ldX switch (where "X" varies) controls diagnostic logging levels. /ldn specifies that no diagnostic log be created. Using this option, obviously, results in the fastest possible DC2 test runs. The other possible options for the value for "X" are: F to log fatal errors only, E to log any errors, and I to log information.

Controlling diagnostic logging levels is most useful when you’re attempting to isolate one or two tests that are causing your driver to fail. Unless you’ve got days to wait, you’ll never want to specify /ldi when you’re running multiple categories of tests!

Open Operations
DC2’s operations begin by opening the Device Under Test in a number of different ways and with several different options. Basic Open Operations comprise the standard ways in which DC2 opens the Device Under Test for testing. Basic Open Operations are performed by default – that is, they take place without specifying any command line switches. There are no command line switches that can disable any of the Basic Open Operations during DC2 testing.

During Basic Open Operations, if any of the following operations fail with STATUS_SHARING_VIOLATION, progressively more liberal ShareAccess is specified and the Open is repeated. If an operation fails with STATUS_ACCESS_DENIED, progressively less RequestedAccess is specified and the Create is repeated. In either of these cases, an appropriate message is logged (with severity Error) to diags.log if this logging has been enabled.

The Basic Open Operations are:

  • Normal (IRP_MJ_CREATE). The device is opened, specifying the native device name only, for asynchronous operation. No CreateOptions are specified, and no ShareAccess is specified. The EaBuffer pointer and EaLength are set to zero. DesiredAccess is MAXIMUM_ALLOWED. CreateDisposition is specified as FILE_OPEN.
  • With Added Backslash (IRP_MJ_CREATE). The device is opened as indicated in item 1 above, except specifying the native device name followed by a backslash. This test specifically probes for how device drivers and file systems deal with a root directory path being supplied along with the device name. Device drivers that do not support a namespace in addition to their device name (that is, almost every driver) should typically fail this request. Note, if you have specified FILE_DEVICE _SECURE_OPEN in your Device Object characteristics, this open request will be (properly) failed.
  • As Named Pipe (IRP_MJ_CREATE_NAMED_ PIPE). The device is opened as a named pipe, using the ZwCreateNamedPipeFile function. In this test, ShareAccess is initially set to share read and share write. Most device drivers will fail this request. What would the driver do with such a strange open?
  • As Mailslot (IRP_MJ_CREATE_MAILSLOT). The device is opened as a mailslot using ZwCreate MailslotFile. As with item 3, above, most device drivers should fail this request.
  • As Tree Connection (IRP_MJ_CREATE). The device is opened by ZwCreateFile specifying CreateOption OPEN_TYPE_TREE_ CONNECTION. In this test, share read and share write are initially specified for ShareAccess. Drivers might either ignore or fail these requests.

If one of the Basic Open Operations succeeds, a few requests are sent to the Device Under Test using the opened handle. This is to verify that the device can in fact be used for an I/O operation. These requests are:

  • ZwQueryObject on the returned file handle for ObjectNameInformation
  • ZwQueryInformationFile for FileNameInformation
  • ZwQueryInformationFile for FileFsDevice Information
  • For the Normal open, an IOCTL_TDI_QUERY_ INFORMATION is sent (presumably to see if the device identifies itself as a TDI device)

The above Basic Open Operations form the basis upon which other DC2 tests build. The contents of the test log (DC2.LOG) created (with /ltc) for these operations appear in Figure 1.

DC2 V3.2 Starting at Mon Jul 26 13:06:40 2004
Command Line: dc2 /ltc /ldn /lrn \device\null

START TESTING: device \device\null
Trying to open \device\null   
Trying to open \device\null   with added backslash
Trying to open \device\null    as NamedPipe
Trying to open \device\null    as Mailslot
Trying to open \device\null    with option FILE_CREATE_TREE_CONNECTION
END TESTING: device \device\null
ALL TESTS COMPLETE at Mon Jul 26 13:06:40 2004

Figure 1 -- DC2.LOG for Basic Opens wiht /ltc Switch

Because the command line defaults to no tests being performed, only the 5 Basic Open Operations (and the associated queries) are performed. If further tests had been requested, either by specifying /hct (which selects a pre-defined group of tests) or by specifying the individual test category to be performed, those tests would be performed while the Device Under Test was open. For most test categories, tests are repeated for each successful open mode.

Note that you can see every operation DC2 performs, and its associated results, by changing the logging options to /lta

/lda /lra. In this case, every operation DC2 performs will be logged to DC2.LOG. The operations performed by DC2, and the results of those operations, will be logged to DIAGS.LOG. For example, when DC2 is run with no tests selected (just the basic opens), the information is logged to DC2.LOG, see Figure 2.

DC2 V3.2 Starting at Mon Jul 26 13:09:22 2004

Command Line: dc2 /lta/lda /lra \device\null

START TESTING: device \device\null
Trying to open \device\null   
\device\null Open   
ZwQueryObject, Buffer=0x2650b8, Length=1032., Type=FileNameInformation
ZwQueryInformationFile, Buffer=0x264c40, Length=1032., Type=FileNameInformation
ZwQueryVolumeInformationFile, Buffer=0x6e958, Length=8., Type=FileFsDeviceInformation
ZwDeviceIoControlFile, ControlCode=0x210012 (IOCTL_TDI_QUERY_INFORMATION), InBuf=0x6f220, 24. OutBuf=0x6f23c, 40.
Trying to open \device\null   with added backslash
\device\null Open   with added backslash
ZwQueryObject, Buffer=0x2659a8, Length=1032., Type=FileNameInformation
ZwQueryInformationFile, Buffer=0x265530, Length=1032., Type=FileNameInformation
ZwQueryVolumeInformationFile, Buffer=0x6e958, Length=8., Type=FileFsDeviceInformation
Trying to open \device\null    as NamedPipe
\device\null Open    as NamedPipe
Trying to open \device\null    as Mailslot
\device\null Open    as Mailslot
Trying to open \device\null    with option FILE_CREATE_TREE_CONNECTION
\device\null Open    with option FILE_CREATE_TREE_CONNECTION
ZwQueryObject, Buffer=0x266298, Length=1032., Type=FileNameInformation
ZwQueryInformationFile, Buffer=0x265e20, Length=1032., Type=FileNameInformation
ZwQueryVolumeInformationFile, Buffer=0x6e958, Length=8., Type=FileFsDeviceInformation
END TESTING: device \device\null

ALL TESTS COMPLETE at Mon Jul 26 13:09:22 2004

Figure 2 -- DC2.LOG with No Tests Selected (Basic Opens Only)

Additional Open Operations
By specifying additional switches, other types of open operations, in addition to the Basic Open Operations, can be performed by DC2. These include the operations seen in Figure 2.

  • /k – This switch causes synchronous Open variants be added to the 5 Basic Open Operations above. All 5 Basic Open Operations are performed, and in addition, the Basic normal, mailslot and named pipe open operations are repeated specifying CreateOptions with FILE_SYNCHRONOUS_IO_ ALERT and AccessMode with SYNCRHONIZE. An additional open, termed a "direct open", is performed if Direct Device Open (/dd) is also specified. In this "direct open", AccessMode is specified as SYNCHRONIZE| FILE_READ_ ATTRIBUTES| READ_CONTROL| WRITE_ OWNER| WRITE_DAC, and CreateOptions is set to zero. As a result of specifying /k, a total of 8 Open operations are performed, as shown in Figure 3 (assuming /dd was not also specified).
  • /dd – As described above, when specified with /k this switch causes an additional synchronous Open variant, the "direct device open," to be performed. If /dd is specified but /k is not specified, this Open is not performed.
  • DC2 V2.4 Starting at Mon Oct 29 18:44:27 2001

    Command Line: dc2 /k /ltc /ldn /lrn \device\null

    START TESTING: device \device\null
    Trying to open \device\null  synchronous 
    Trying to open \device\null   
    Trying to open \device\null   with added backslash
    Trying to open \device\null  synchronous  as NamedPipe
    Trying to open \device\null  synchronous  as Mailslot
    Trying to open \device\null    as NamedPipe
    Trying to open \device\null    as Mailslot
    Trying to open \device\null    with option FILE_CREATE_TREE_CONNECTION
    END TESTING: device \device\null

    ALL TESTS COMPLETE at Mon Oct 29 18:44:28 2001 (elapsed time 00:00:01)

    Figure 3 -- DC2.LOG with /k Swtich (synchronous Open variants)

    Selecting Tests
    Now that you understand how DC2 performs open requests, you’ll need to decide which tests you want DC2 to perform once the device has been opened. DC2 has the capability of performing a large range of tests. We’ll list a few of the most interesting here.

    Miscellaneous Test (Part 1 and Part 2)
    These tests are requested using the /m switch. The tests in this category are performed for:

    • Each successful open in the Basic Open Operations, plus
    • Each successful open in the Additional Open Operations, plus
    • Each successful open in the Sub-Open (Relative Open) tests (if this test category is selected)

    The Miscellaneous Tests are performed in two parts. During Miscellaneous Tests Part 1, a series of ZwReadFile and ZwWriteFile operations are performed, specifying valid data buffers pointers and varying lengths (including zero). The byte offsets specified include both zero byte offset and varying 64-bit bytes offsets. ZwWriteFile operations are also performed explicitly specifying a ByteOffset value of -1.

    ZwCancelIoFile and ZwFlushBuffersFile functions are also issued.

    Miscellaneous Tests Part 1 also issues a series of ZwQueryDirectoryFile operations for a list of common information types, including:

    • FileNameInformation
    • FileDirectoryInformation
    • FileFullDirectoryInformation
    • FileObjectIdInformation
    • FileQuotaInformation
    • FileReparsePointInformation

    Each of the above requests is issued many times, with valid user data buffer pointers and varying buffer lengths (including zero). As part of Miscellaneous Tests Part 1, a series of unusual system services are issued with the indicated device as the target. These include ZwCreateSection, ZwLockFile, and ZwNotifyChangeDirectoryFile. Most device drivers will fail the IRPs that result from these requests.

    Miscellaneous Tests Part 2 test a series of requests, including ZwQueryAttributesFile, ZwQueryFullAttributesFile, and Zw DeleteFile. Each of these requests is issued with valid pointers to an ObjectAttributes structure.

    IOCTL/FSCTL Zero Length Buffer Tests
    This test category is selected with the switch /in (for IOCTL) or /fn (for FSCTL). The tests in this category are performed for:

    • Each successful open in the Basic Open Operations, plus
    • Each successful open in the Additional Open Operations

    These tests issue a sequence of IRP_MJ_DEVICE_ CONTROL (for /in) or IRP_MJ_FILE_SYSTEM_CONTROL (for /fn) IRPs with zero specified for the InBuffer and OutBuffer lengths. The InBuffer and OutBuffer pointers are specified as addresses high in kernel virtual address space (0xfffffc00).

    The IOCTL or FSCTL control code used is dynamically determined according to DC2 parameters. For each function from ioctl_min_function to ioctl_max_function, an IOCTL or FSCTL is issued with that function and a device type ranging from ioctl_min_devtype to ioctl_max_devtype. For each device type and function pair, each buffering method (i.e. transfer type: METHOD_BUFFERED, METHOD_IN_ DIRECT, METHOD_OUT_DIRECT, METHOD_NEITHER) and each type of requested access (FILE_READ_ACCESS, FILE_WRITE_ACCESS, FILE_ANY_ACCESS) is used.

    Ioctl_min_function to ioctl_max_function is determined by the /fl and /fu switches, which default to 0 and 400, respectively. Ioctl_min_devtype to ioctl_max_devtype, determined by the /dl and /du switches, default to 0 and 200, respectively.

    IOCTL/FSCTL Random Tests
    The IOCTL/FSCTL Random Tests are the heart of the testing that DC2 performs.

    This test category is selected with the switch /ir (for IOCTL) or /fr (for FSCTL). The tests in this category are performed for:

    • Each successful open in the Basic Open Operations, plus
    • Each successful open in the Additional Open Operations

    These tests issue a sequence of IRP_MJ_DEVICE_ CONTROL (for /ir) or IRP_MJ_FILE_SYSTEM_CONTROL (for /fr) IRPs with random functions, device types, methods, and access specifications. IRPs are issued with both valid and invalid InBuffer and OutBuffer pointers and lengths. The contents of the InBuffer and OutBuffer, when valid, are random. The number of IOCTLs generated may be controlled by the /t switch. If the /t switch is not specified, DC2 will generate 100,000 random IOCTLs per test sequence.

    The range over which the device type is chosen is specified by ioctl_min_devtype (specified via the /dl switch) to ioctl_max_devtype (specified via the /du switch). When running this test, you’ll want to be sure that the device type for your device falls within the ranges you specify with the /dl and /du switches. The IOCTL function code range that’s tested is specified using /fl for the ioctl_min_function and /fu for the ioctl_max_function. Again, you will want to be sure that your driver’s device type falls within the specified range.

    The control code, in buffer and out buffer information are logged to DC2.LOG when /ltt is specified.

    Tailored IOCTL/FSCTL Tests
    These tests are automatically selected whenever the IOCTL/FSCTL Random Tests are selected. The tailored tests attempt to further probe IOCTL or FSCTL requests using a heuristic based on the results obtained during the basic IOCTL/FSCTL Random Tests. Depending on the results observed during testing, DC2 may issue zero, few, or many additional IOCTL or FSCTL requests in this category.

    In and out buffer pointers and lengths may be valid or invalid, and a variety of transfer types (METHOD_BUFFERED, METHOD_IN_DIRECT, METHOD_OUT_DIRECT, and METHOD_NEITHER) may be used.

    The control code, in buffer and out buffer information are logged to DC2.LOG when /ltt is specified.

    Open/Close Tests
    This test category is selected with the switch /oc. The tests in this category are performed for only two of the Basic Open Operations – Normal open and open With Added Backslash.

    This test spawns several threads, each of which performs several thousand create/close sequences. Each create issued is an IRP_MJ_CREATE, specifying RequestedAccess as MAXIMUM_ALLOWED, and ShareAccess as FILE_ SHARE_READ| FILE_SHARE_WRITE| FILE_SHARE_ DELETE for sharing, and OpenDisposition as FILE_OPEN.

    When selected, the Open/Close Tests are run twice: Just prior to Normal open, and just prior to open With Added Backslash

    Other Tests
    As previously mentioned, there are many more tests that DC2 can perform. Refer to the documentation in the Windows Server 2003 DDK (which is exceptionally well written, by the way) for more information on other tests that DC2 can perform.

    Wrapping It Up
    DC2 is a flexible and powerful tool. No driver should be considered "done" until it has passed a complete set of DC2 tests! If you combine the information in this article, and the info in the Windows Server 2003 or later DDK documentation, you should be able to take maximal advantage of this cool tool.

     

    User Comments
    Rate this article and give us feedback. Do you find anything missing? Share your opinion with the community!
    Post Your Comment

    "Named Pipe"
    I am using the most recent DDK and finc nothing on named pipes. ZwCreateNamedPipeFile does not exist in that DDK ??? I have a project wherein I must create a named pipe in a driver to be accessed by a service on the same machine. Simple problem ? Where is the documentation?

    28-Jul-05, Sanford Hayes


    Post Your Comments.
    Print this article.
    Email this article.
    bottom nav links