Stop 0x19 in a Large Pool Allocation
Hello all, Scott Olson here again to share another interesting issue I recently debugged with pool corruption and found that using special pool does not work with large pool allocations (pool allocations greater than a PAGE_SIZE).
Here is an example of a valid large page allocation. Notice the size is 0x1fb0 and a PAGE_SIZE is 0x1000 or 4kb.
0: kd> !pool fffffa80`0dba6fa0
Pool page fffffa800dba6fa0 region is Nonpaged pool
*fffffa800dba5000 : large page allocation, Tag is Io , size is 0x1fb0 bytes
Pooltag Io : general IO allocations, Binary : nt!io
In Windows 7, at the end of the large pool allocation it will have an allocation tag of “Frag” then a “Free” tag with the rest of the page size and is stored on the free pool list for allocation less than a page in size.
0: kd> dc fffffa800dba5000 fffffa800dba5000+0x1fb0-4
fffffa80`0dba5000 00558001 32373242 00000000 00000000 ..U.B272........
fffffa80`0dba5010 55555555 55555555 98764321 01b75f55 UUUUUUUU!Cv.U_..
fffffa80`0dba5020 00000001 00000001 704e6ff0 fffff981 .........oNp....
…<cut>
fffffa80`0dba6f80 55555555 55555555 55555555 55555555 UUUUUUUUUUUUUUUU
fffffa80`0dba6f90 55555555 55555555 55555555 55555555 UUUUUUUUUUUUUUUU
fffffa80`0dba6fa0 55555555 55555555 00001fb0 00000000 UUUUUUUU........
0: kd> dc
fffffa80`0dba6fb0 02010100 67617246 55555555 55555555 ....FragUUUUUUUU
fffffa80`0dba6fc0 00040101 65657246 55555555 55555555 ....FreeUUUUUUUU
fffffa80`0dba6fd0 00802170 fffff880 0e49cf70 fffffa80 p!......p.I.....
fffffa80`0dba6fe0 15cc8fe8 fffff981 3b9c50a7 00000005 .........P.;....
Displayed with the !pool command:
0: kd> !pool fffffa80`0dba6fb0
Pool page fffffa800dba6fb0 region is Nonpaged pool
*fffffa800dba6fb0 size: 10 previous size: 0 (Allocated) *Frag
Owning component : Unknown (update pooltag.txt)
fffffa800dba6fc0 size: 40 previous size: 10 (Free) Free
The example above demonstrates how this normally works. The downside to this architecture is that if a driver were to overrun its pool allocation then special pool would not be useful because the large pool allocation has to be page-aligned. Special pool detects pool overruns by putting the data at the end of the page, which would not be feasible with a large pool allocation.
In Windows 7 there is a check while freeing the pool memory that will determine if this allocation had written past the end of its allocation, and if so will bug check the machine with a Stop 0x19 BAD_POOL_HEADER with the first parameter being a 0x21. Here is the definition along with what each parameter means:
BAD_POOL_HEADER (19)
The pool is already corrupt at the time of the current request.
This may or may not be due to the caller.
The internal pool links must be walked to figure out a possible cause of
the problem, and then special pool applied to the suspect tags or the driver
verifier to a suspect driver.
Arguments:
Arg1: 0000000000000021, the data following the pool block being freed is corrupt. Typically this means the consumer (call stack ) has overrun the block.
Arg2: fffffa800dc57000, The pool pointer being freed.
Arg3: 0000000000002180, The number of bytes allocated for the pool block.
Arg4: 006b0072006f0077, The corrupted value found following the pool block.
Here is an example of what this corruption looks like compared to the above valid large pool allocation:
0: kd> !pool fffffa800dc57000
Pool page fffffa800dc57000 region is Nonpaged pool
fffffa800dc57000 is not a valid large pool allocation, checking large session pool...
fffffa800dc57000 is freed (or corrupt) pool
Bad allocation size @fffffa800dc57000, zero is invalid
***
*** An error (or corruption) in the pool was detected;
*** Attempting to diagnose the problem.
***
*** Use !poolval fffffa800dc57000 for more details.
Pool page [ fffffa800dc57000 ] is __inVALID.
Analyzing linked list...
[ fffffa800dc57000 ]: invalid previous size [ 0x38 ] should be [ 0x0 ]
Scanning for single bit errors...
None found
Next, I dump the allocation from the start to the end. Notice the size of the allocation is stored in the bugcheck code as argument 3.
0: kd> dc fffffa800dc57000 fffffa800dc57000+2180-4
fffffa80`0dc57000 00000038 0000000e 00000000 00000000 8...............
fffffa80`0dc57010 a24da497 01ccc5d6 c827993c 41946d1f ..M.....<.'..m.A
fffffa80`0dc57020 c0d75c9b b7cff1a5 00000000 00000020 .\.......... ...
fffffa80`0dc57030 000021e0 00000006 0000006c 00000110 .!......l.......
fffffa80`0dc57040 00000208 000003b8 00000208 00000660 ............`...
fffffa80`0dc57050 00000208 00000910 00000208 00000bb0 ................
<cut>
fffffa80`0dc59150 002d0033 00300031 0063002e 006d006f 3.-.1.0...c.o.m.
fffffa80`0dc59160 006c002e 00660065 00680074 006e0061 ..l.e.f.t.h.a.n.
fffffa80`0dc59170 006e0064 00740065 006f0077 006b0072 d.n.e.t.w.o.r.k.
This should be the end of the allocation. The next thing we see should be the “Frag” and “Free” tags.
0: kd> dc
fffffa80`0dc59180 003a0073 0061006d 0061006e 00650067 s.:.m.a.n.a.g.e.
fffffa80`0dc59190 0065006d 0074006e 0038003a 00390036 m.e.n.t.:.8.6.9.
fffffa80`0dc591a0 0062003a 00670069 0075006c 00790063 :.b.i.g.l.u.c.y.
fffffa80`0dc591b0 0064002d 00740061 002d0061 006e0069 -.d.a.t.a.-.i.n.
fffffa80`0dc591c0 00650064 00650078 002d0073 00740063 d.e.x.e.s.-.c.t.
fffffa80`0dc591d0 006c0072 0031005f 00000031 00000000 r.l._.1.1.......
We clearly see that the Frag and Free tag have been overwritten with some string value which is causing the corruption. At this point, you would need to look at the current stack to determine which driver had allocated the memory, and review the code to investigate when this corruption could have occurred.
Comments
Anonymous
January 28, 2012
Nice little gem here, good to know about the Frag and Free pooltags. Thanks.Anonymous
February 06, 2012
Very Impressive, keep up the good work.