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.