[This is preliminary documentation and subject to change.]
The Devctl program is designed to crash drivers by calling them through various user-mode I/O interfaces. It does not test the functionality but rather the robustness of drivers. Drivers should be resilient to bad data from user mode in exactly the same way that kernel entry points have to be. If they are not resilient then they open up denial of service attacks and in some cases a mechanism to bypass system security. This program identifies drivers that do not handle the following calls properly:
Devctl checks to make sure that the above calls are handled properly, and do not result in any of the following events:
After each operation is performed, the program performs a check on consumed system memory. Devctl queries the pool tag database and look-aside information. If this operation caused either one of these memory sources to be depleted, the operation is repeated. Note that this increase in memory consumption may have had nothing to do with the request that was just performed. Typically, the second call does not see an increase and the program continues. Real memory leaks arise as a vast number of repeated calls and the tag in question raised to the top of the poolmon display sorted by difference (d).
For calls that would typically be buffered I/O operations, the program tracks the number of exceptions the operating system has dispatched. If the number of exceptions increases, the operation is also repeated. Although buffered I/O operations may also reference the user's address space, this is rare. Note that exception dispatching may signal an internal error that is being handled by an exception handler. Such a situation may hide a true parameter or handle validation problem. Devctl can run with the bottom hardware page mapped so that NULL pointer dereferences do not raise exceptions but rather return meaningless information.
Candidates for pool leaks and exceptions are logged to a file, diags.txt, which may be useful in the event that the leak does not crash the system or the many repeated calls are missed by the user. The program's basic execution passes are:
After IOCTL passes, Devctl issues a cancel request to the driver as part of a "miscellaneous function calls pass". IRPs that were lost (never completed by calling IoCompleteRequest or passed to other drivers but finished by the device) will cause the process to hang. Some execution paths may lead to dialog boxes appearing from the I/O manager warning that IRPs did not cancel within an allotted time. These lost IRPs are easily debugged by issuing "!process 0 0" from the debugger. Select the Devctl process via a "!process
The basic syntax for the program is:
devctl [/i] [/l] [/il nn] [/iu mm] [devnam]
E:\devctl>obj\i386\devctl \device\null
Here is a sample leak:
C:\>g:\nt\nttest\security\tiger\devctl\obj\i386\devctl -if
Memory: 65080K Avail: 3424K PageFlts: 0 InRam Krnl: 4632K P: 1916K
Note that the IOCTL and FSCTL passes take a very long time since the space is huge. You can get much quicker coverage if you know the range of IOCTLs that the driver accepts. Here is the procedure with IPNAT:
The first number in this macro is the function number. You can limit Devctl to just cover this range with a command like devctl +fl 0 +fu 13. This limits both the IOCTL and FSCTL zero-length and random buffer calls. This will run very quickly; consider increasing the number of random buffers that the program gives the driver by +t nnnn, for instance.
/and + enable options, - disables options
/a
Examine all devices in system. Don't prompt for yes/no.
/al
Alert the main thread periodically.
/c
Enable or disable skipping operations that aborted or crashed.
/dd
Enable or disable the direct device open paths.
/dl nn
Sets maximum limit for device type portion of IOCTL/FSCTL code, default zero.
/du nn
Sets minimum limit for device type portion of IOCTL/FSCTL code, default 200.
/e
Enable or disable zero length EA's, needed on checked builds.
/f
Enable or disable all FSCTL paths.
/fi
Enable or disable turning on failure injection in the driver verifier.
/fn
Enable or disable FSCTL paths with null buffers.
/fr
Enable or disable FSCTL paths with random buffers.
/fl nn
Sets maximum limit for function portion of IOCTL and FSCTL code, default zero.
/fu nn
Sets minimum limit for function portion of IOCTL and FSCTL code, default 200.
/g c h
Grabs a handle from another process.
/h /?
Prints this message.
/i
Enable or disable all IOCTL paths.
/if
Enable or disable all FSCTL and IOCTL paths.
/in
Enable or disable IOCTL paths with null buffers.
/il nnn
Set lower input buffer size.
/iu nnn
Set upper input buffer size.
/im
Enable or disable the impersonation of a non-admin during the test.
/ir
Enable or disable IOCTL paths with random buffers.
/j
Enable or disable relative stream opens for file systems.
/k
Enable or disable synchronous handles.
/l
Enable or disable logging and skipping failing functions.
/m
Enable or disable miscellaneous functions.
/n
Map zero page so that NULL pointer dereferences do not raise.
/ol nnn
Set lower output buffer size.
/ou nnn
Set upper output buffer size.
/p
Enable or disable the checks on pool usage through tags and look-aside lists.
/pd
Print out device objects and symbolic links and exit.
/pr
Enable or disable protection change tests.
/ps sss
Set prefix string for use with /pd.
/q
Enable or disable the normal handle query functions.
/r
Enable or disable skipping operations that are already logged as done.
/rd
Select a random device object or symbolic link for testing.
/s
Enable or disable the sub or relative opens to obtain handles.
/sd
Enable or disable the query and set security functions.
/sl
Enable or disable the opening of symbolic links.
/se nnn
Set session ID to "nnn."
/t nn
Set maximum limit for IOCTL/FSCTL calls made with random buffers, default 100000.
/tt nn
Set maximum limit for tailored calls made for discovered IOCTLs/FSCTLs, default 10000.
/v
Enable or disable the printing of error status values for calls.
/w
Enable or disable the Winsock TransmitFile test.
/y
Enable or disable touching disk devices.
Defaults: devctl -a -al +c +dd +dl 0 +du 200 +e +fn +fr +fl 0 fu 200 +im +il 0
+in +iu 512 +ir -j -k +l +m -n +ol 0 +ou 512 +p -pr +q +s +sd
+sl +t 100000 +tt 10000 -v -w +y
Devnam is the device to open to issue requests. It must be in native object tree format like ’\device\null’. If this is omitted the program prompts for each device in turn. You can skip to a particular device by typing ‘/
Listen socket on port 1192 address 172.31.236.194
Trying to open device \device\null synchronous
Opened crashn.log for reading
Lookaside: PooL, size 128 up 2
Pool: Mdl , Paged up 0, NonPaged up 128
\device\null Open synchronous
Opened file \device\null with access 1f03ff
Pool: File, Paged up 0, NonPaged up 192
Pool: CcBc, Paged up 0, NonPaged up 160
\device\null NtQueryObject ObjectNameInformation
NtQueryObject failed c0000004
NtQueryObject failed c0000004
Lookaside: Pool, size 128 up 1
NtQueryObject failed c0000004
\device\null NtQueryInformationFile FileBasicInformation
\device\null NtQueryInformationFile FileStandardInformation
\device\null NtQueryInformationFile FileInternalInformation
…
…
E:\devctl>obj\i386\devctl
Listen socket on port 1194 address 172.31.236.194
Open device Cdfs? /null
Matching "null" against "Cdfs"
Matching "null" against "000126"
Matching "null" against "ASYNCMAC"
Matching "null" against "Afd"
Matching "null" against "Beep"
Matching "null" against "CdRom0"
Matching "null" against "DmLoader"
Matching "null" against "Floppy0"
Matching "null" against "FloppyPDO0"
Matching "null" against "FsWrap"
Matching "null" against "FtControl"
Matching "null" against "Gpc"
Matching "null" against "Hal Pci 0"
Matching "null" against "IdeDeviceP0T0L0"
Matching "null" against "IdeDeviceP1T1L0"
Matching "null" against "IdeFdo809a1288Channel0"
Matching "null" against "IdeFdo809a1288Channel1"
Matching "null" against "IdePort0"
Matching "null" against "IdePort1"
Matching "null" against "Ip"
Matching "null" against "KeyboardClass0"
Matching "null" against "KsecDD"
Matching "null" against "LanmanDatagramReceiver"
Matching "null" against "LanmanRedirector"
Matching "null" against "LanmanServer"
Matching "null" against "Mailslot"
Matching "null" against "MountPointManager"
Matching "null" against "Mup"
Matching "null" against "NTPNP_PCI0000"
Matching "null" against "NamedPipe"
Matching "null" against "Ndis"
Matching "null" against "Null"
Open device Null? y
Trying to open device Null synchronous
Opened crashn.log for reading
Lookaside: Pool, size 32 up 4
Pool: AfdC, Paged up 0, NonPaged up 192
\Device\Null Open synchronous
Opened file Null with access 1f03ff
Pool: File, Paged up 0, NonPaged up 192
\Device\Null NtQueryObject ObjectNameInformation
NtQueryObject failed c0000004
NtQueryObject failed c0000004
Lookaside: Pool, size 128 up 1
Lookaside: Pool, size 192 up 1
NtQueryObject failed c0000004
\Device\Null NtQueryInformationFile FileBasicInformation
\Device\Null NtQueryInformationFile FileStandardInformation
\Device\Null NtQueryInformationFile FileInternalInformation
\Device\Null NtQueryInformationFile FileEaInformation
\Device\Null NtQueryInformationFile FileAccessInformation
\Device\Null NtQueryInformationFile FileNameInformation
\Device\Null NtQueryInformationFile FileModeInformation
\Device\Null NtQueryInformationFile FileAlignmentInformation
Lookaside: PooL, size 128 up 1
Pool: Sect, Paged up 128, NonPaged up 0
Pool: CcSc, Paged up 0, NonPaged up 320
\Device\Null NtQueryInformationFile FileAllInformation
\Device\Null NtQueryInformationFile FileStreamInformation
Pool: VadS, Paged up 0, NonPaged up 32
\Device\Null NtQueryInformationFile FilePipeInformation
\Device\Null NtQueryInformationFile FilePipeLocalInformation
\Device\Null NtQueryInformationFile FilePipeRemoteInformation
E:\devctl>
…
Open device \Device\000167? /dfs
…
Open device \Dfs? y
…
\Dfs Open synchronous
Opened file Dfs with access 1f03ff
…
\Dfs NtQueryVolumeInformationFile FileFsVolumeInformation
Pool: Mup , Paged up 0, NonPaged up 131136
Lookaside: Scs$, size 64 up 2
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Hal , Paged up 0, NonPaged up 288
Pool: Irp , Paged up 0, NonPaged up 384
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Lookaside: Ntfi, size 264 up 1
Pool: Mup , Paged up 0, NonPaged up 130944
Lookaside: Ntfi, size 264 up 2
Lookaside: Scs$, size 64 up 1
Pool: Mup , Paged up 0, NonPaged up 131008
Pool: Mup , Paged up 0, NonPaged up 129536
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131008
Lookaside: Ntfi, size 264 up 1
Lookaside: Scs$, size 64 up 1
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 130752
Pool: Mup , Paged up 0, NonPaged up 130944
Pool: Mup , Paged up 0, NonPaged up 131008
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Lookaside: PooL, size 256 up 1
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Mup , Paged up 0, NonPaged up 131136
Lookaside: Scs$, size 64 up 2
Pool: Mup , Paged up 0, NonPaged up 131136
Pool: Hal , Paged up 0, NonPaged up 288
Pool: Irp , Paged up 0, NonPaged up 768
^C
Commit: 52972K Limit: 666632K Peak: 108844K Pool N: 6312K P:10324K
Tag Type Allocs Frees Diff Bytes Per Alloc
Mup Nonp 84551 ( 0) 9870 ( 0) 74681 4779584 ( 0) 64
SYSA Paged 2227 ( 0) 750 ( 0) 1477 67136 ( 0) 45
CM Paged 6542 ( 0) 5854 ( 0) 688 8877504 ( 0) 12903
Vad Nonp 1460 ( 0) 1000 ( 0) 460 29440 ( 0) 64
File Nonp 3434 ( 0) 3137 ( 0) 297 57024 ( 0) 192
C:\>type diags.txt
\Dfs NtQueryVolumeInformationFile FileFsAttributeInformation Pool: Mup , Paged
up 0, NonPaged up 65600
//
// NAT-supported IOCTL constant declarations
//
#define IOCTL_IP_NAT_SET_GLOBAL_INFO \
_IP_NAT_CTL_CODE(0, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_IP_NAT_CREATE_INTERFACE \
_IP_NAT_CTL_CODE(2, METHOD_BUFFERED, FILE_WRITE_ACCESS)
…
…
#define IOCTL_IP_NAT_DELETE_REDIRECT \
_IP_NAT_CTL_CODE(13, METHOD_BUFFERED, FILE_WRITE_ACCESS)
© 1999 Microsoft Corporation