- May 7, 2013
- 10,400
Rich (BB code):
DRIVER_VERIFIER_DETECTED_VIOLATION (c4)
A device driver attempting to corrupt the system has been caught. This is
because the driver was specified in the registry as being suspect (by the
administrator) and the kernel has enabled substantial checking of this driver.
If the driver attempts to corrupt the system, bugchecks 0xC4, 0xC1 and 0xA will
be among the most commonly seen crashes.
Arguments:
Arg1: 0000000000000062, A driver has forgotten to free its pool allocations prior to unloading.
Arg2: ffffc58bdf474f40, name of the driver having the issue.
Arg3: ffffc58be05fe550, verifier internal structure with driver information.
Arg4: 0000000000000001, total # of (paged+nonpaged) allocations that weren't freed.
Type !verifier 3 drivername.sys for info on the allocations
that were leaked that caused the bugcheck.
I wouldn't usually bother writing about a Stop 0xC4 since they're self-explanatory, however, this appears to a common bug with the Riot Vanguard driver and so I thought I would add some notes about how Driver Verifier detects this bug.
The second parameter contains a string which is the name of the driver which caused the system to bugcheck. The third parameter is actual a pointer to a structure which has no public symbol information, although, you can dump this using PyKd. It isn't particularly interesting though and really just contains the same information which you can obtain by using !verifier 3 <driver>.sys.
Rich (BB code):
15: kd> dc ffffc58bdf474f40 L4
ffffc58b`df474f40 00670076 002e006b 00790073 00000073 v.g.k...s.y.s...
Rich (BB code):
15: kd> !verifier 3 vgk.sys
[...]
Driver Verification List
------------------------
nt!_VF_TARGET_DRIVER 0xffffc58bdf5cc280: vgk.sys (Loaded)
Pool Allocation Statistics: ( NonPagedPool / PagedPool )
Current Pool Allocations: ( 0x00000000 / 0x00000001 )
Current Pool Bytes: ( 0x00000000 / 0x00000068 )
Peak Pool Allocations: ( 0x00000003 / 0x00000001 )
Peak Pool Bytes: ( 0x0000094a / 0x00000068 )
Contiguous Memory Bytes: 0x00000000
Peak Contiguous Memory Bytes: 0x00000000
Pool Allocations:
Address Length Tag Caller Address
------------------ ---------- ---- ------------------
0xffffb10cf7d4af90 0x00000068 VStr 0xfffff80ae1fcce8c vgk+0x7cce8c
Contiguous allocations are not displayed with public symbols.
The !verifier command simply lists the pool allocations which the problematic had made. These are usually always special allocations made through Driver Verifier itself hence the pooltag of VStr. The special pool type is specifically used for debugging purposes and is often used to detect buffer overflows. The Memory Manager will usually allocate a special region between the current pool allocation and the next in order to detect pool corruption without affecting the next "real" allocation.
Rich (BB code):
15: kd> !pooltag VStr
Pooltag VStr
Description: String buffer allocated by the Driver Verifier version of Rtl String APIs
Driver!Module: nt!Vf
Rich (BB code):
15: kd> !pool 0xffffb10cf7d4af90
Pool page ffffb10cf7d4af90 region is Special pool
*ffffb10cf7d4a000 size: 68 data: ffffb10cf7d4af90 (NonPaged) *VStr
Pooltag VStr : String buffer allocated by the Driver Verifier version of Rtl String APIs, Binary : nt!Vf
If we dump the pool allocation, then we can see this special region which is called "slop bytes".
Rich (BB code):
15: kd> dq ffffb10c`f7d4a010
ffffb10c`f7d4a010 ffffc58b`df7f4fe0 01010101`01010101
ffffb10c`f7d4a020 01010101`01010101 01010101`01010101
ffffb10c`f7d4a030 01010101`01010101 01010101`01010101
ffffb10c`f7d4a040 01010101`01010101 01010101`01010101
ffffb10c`f7d4a050 01010101`01010101 01010101`01010101
ffffb10c`f7d4a060 01010101`01010101 01010101`01010101
ffffb10c`f7d4a070 01010101`01010101 01010101`01010101
ffffb10c`f7d4a080 01010101`01010101 01010101`01010101
Notice the repeating pattern? The highlighted address is the pool tag which we saw earlier.
Rich (BB code):
15: kd> dc ffffb10cf7d4af90
ffffb10c`f7d4af90 0052005c 00470045 00530049 00520054 \.R.E.G.I.S.T.R.
ffffb10c`f7d4afa0 005c0059 0041004d 00480043 004e0049 Y.\.M.A.C.H.I.N.
ffffb10c`f7d4afb0 005c0045 00590053 00540053 004d0045 E.\.S.Y.S.T.E.M.
ffffb10c`f7d4afc0 0043005c 006e006f 00720074 006c006f \.C.o.n.t.r.o.l.
ffffb10c`f7d4afd0 00650053 00300074 00310030 0053005c S.e.t.0.0.1.\.S.
ffffb10c`f7d4afe0 00720065 00690076 00650063 005c0073 e.r.v.i.c.e.s.\.
ffffb10c`f7d4aff0 00670076 0000006b 01010101 01010101 v.g.k...........
ffffb10c`f7d4b000 ???????? ???????? ???????? ???????? ????????????????
The data itself is simply the registry key of the service associated to the driver. This is stored at the end of the allocation. If we now examine the call stack, we'll see the following:
Rich (BB code):
15: kd> knL
# Child-SP RetAddr Call Site
00 ffffef89`a52074d8 fffff806`52de2e34 nt!KeBugCheckEx
01 ffffef89`a52074e0 fffff806`52df2169 nt!VerifierBugCheckIfAppropriate+0xe0
02 ffffef89`a5207520 fffff806`5289a64e nt!VfPoolCheckForLeaks+0x49
03 ffffef89`a5207560 fffff806`52dd44f2 nt!VfTargetDriversRemove+0x118f62
04 ffffef89`a52075e0 fffff806`52adadeb nt!VfDriverUnloadImage+0x3e
05 ffffef89`a5207610 fffff806`52b7d331 nt!MiUnloadSystemImage+0x2eb
06 ffffef89`a52077b0 fffff806`52b7d25e nt!MmUnloadSystemImage+0x41
07 ffffef89`a52077e0 fffff806`52a208c0 nt!IopDeleteDriver+0x4e
08 ffffef89`a5207830 fffff806`526302f7 nt!ObpRemoveObjectRoutine+0x80
09 ffffef89`a5207890 fffff806`5263021e nt!ObfDereferenceObjectWithTag+0xc7
0a ffffef89`a52078d0 fffff806`52b476aa nt!HalPutDmaAdapter+0xe
0b ffffef89`a5207900 fffff806`52e6bd2f nt!IopLoadDriver+0x76a
0c ffffef89`a5207ad0 fffff806`52e579ca nt!IopInitializeSystemDrivers+0x157
0d ffffef89`a5207b70 fffff806`52ba323b nt!IoInitSystem+0x2e
0e ffffef89`a5207ba0 fffff806`52735915 nt!Phase1Initialization+0x3b
0f ffffef89`a5207bd0 fffff806`52813cf8 nt!PspSystemThreadStartup+0x55
10 ffffef89`a5207c20 00000000`00000000 nt!KiStartSystemThread+0x28
The IoDeleteDriver function takes a single parameter which is a pointer to the driver object. This invokes the driver unload routine specified by the driver itself, eventually Driver Verifier checks that the driver has freed its pool allocations and then bugchecks the system if it hasn't.