Windows System Software -- Consulting, Training, Development -- Engineering Excellent, Every Time.

LFH Kernel Pool Allocator Challenges the Incumbent

Windows 10 RS5 introduced a new pool allocator in the kernel for the first time in, well, forever. Interestingly, the newly introduced kernel pool allocator is actually the existing user mode Low Fragmentation Heap (LFH) allocator. While there’s something to be said for the, “if it ain’t broke” mentality, having a single allocator in the O/S certainly makes a certain amount of sense from a maintainability perspective. Also, the user mode heap allocator has undergone significant revisions over the years to better reflect modern security practices, so it makes sense to share those benefits with kernel mode as well.

Most of us wouldn’t even notice or care that there’s a new pool allocator (except for the fact that it broke !pool, that is). However, over the years I have debugged so many BAD_POOL_HEADER bugchecks that I was curious about how the new pool allocator responded to some obvious driver bugs. Specifically, I wondered about the following cases:

1) Buffer Overruns

2) Double Frees

3) Use After Frees

So, I seized the unique opportunity to intentionally write buggy code (and, yes, I did at one point end up with a bug in my buggy code that caused it to not be buggy). The buggy code provides IOCTLs to generate each buggy scenario and the code to handle the IOCTLs is shown in Figure 1.

I then ran each test to pit the Windows 7 allocator against the Windows 10 19H1 allocator to see which one performed better in detecting the bugs. Note that this was not a rigorous, scientific study involving thousands of iterations. Each one was run about three times max to validate that the behavior was at least somewhat repeatable.

Now, without further ado, the results…

Overrun Challenge

Windows 7

On Windows 7 the system immediately crashed with a BAD_POOL_HEADER:

Running !pool on second argument to the bugcheck walks the pool page and shows us where we went off a cliff:

Windows 10 19H1

Running the same test on Windows 10 produced no crash. Running !pool on the freed buffer shows a corruption of the page just like on Windows 7:

But no BAD_POOL_HEADER crash.

Interestingly, I ran the test again and this time I did hit a crash. However, it was an IRQL_NOT_LESS_THAN_OR_EQUAL bugcheck in the bowels of the heap allocator on the next allocation:

Overrun Challenge Winner: Windows 7. Corruption was detected immediately when the buffer was freed and we were provided a clear bugcheck description.

Double Free Challenge

Windows 7

On Windows 7 the system immediately crashed with a BAD_POOL_CALLER:

Windows 10 19H1

Running the same test on Windows 10 produced no crash. Much like last time, running the test a second time did indeed result in a system crash, though this time it was properly at the point of the second free:

Curious about what Arg1 == 0x11 meant, I took a SWAG and grep’d the type information for something related to “heap” and “type”:

That was lucky! Dumping HEAP_FAILURE_TYPE we see that 0x11 (0n17) maps to heap_failure_segment_lfh_double_free:

So there is double free detection, but for some reason it didn’t trigger on the first pass.

Double Free Challenge Winner: Very close, but Windows 7 because it was caught the first time every time we tested. Windows 10 also lost points because the debugger didn’t provide additional reason information and we only came to it through a lucky guess.

Use After Free Challenge

Windows 7

Running this test on Windows 7 produced no crash.

Windows 10 19H1

Running this test on Windows 10 produced no crash.

Use After Free Challenge Winner: Tie. To be fair, it would take a lot of extra processing in the allocator to find this bug, so not surprising that the bug was not caught by either allocator.

Overall Results

Though there are surely benefits to the new allocator, in our opinion the old allocator wins in its ability to detection corruptions of the pool in cases tested.

What About With Driver Verifier?

Of course, the best way to find pool corruptions is with Driver Verifier and Special Pool. I’m happy to report that both allocators caught all three bugs equally, so no loss in functionality there.