Понимание ошибки Pool Coruption часть 3 (двойное освобождение памяти)

Автор: admin | 09.08.2015

В предыдущих 2-ух частях:

 

понимание ошибки Pool Coruption часть 1 (переполнение буфера);

понимание ошибки Pool Coruption часть 2 (переполнение буфера).

мы рассмотрели различные ошибки, связанные с работой с пулом, которые могут приводить к  краху системы. Также мы рассмотрели, что их анализ и нахождение проблемного драйвера не простая задача, поэтому специалистами Microsoft была реализована утилита Driver Verifier.

В этой части мы рассмотрим проблемы в драйверах, которые приводят к синему экрану смерти и которые связаны с освобождением одного и того же участка памяти более одного раза. Если память освобождается дважды то обычно это заканчивается крахом со стоп кодом BSOD 0x000000C2 — BAD_POOL_CALLER а первый аргумент будет равен 7, что означает, что была выполнена попытка освобождения уже освобожденного пула.

Более сложным для анализа будет вариант если пул будет перемещен. Пул структурирован таким образом, что многие драйверы используют одни и те же страницы. То есть возможно ситуация когда драйвер А выполняет вызов ExFreePool и освобождает  блок пула, далее этот блок пула предоставляет драйверу Б, после чего происходит повторный вызов ExFreePool в драйвере А. Как следствие, проблем возникает в драйвере Б, который ожидает работать с корректными данными в своем пуле.

Без специального пула решение такого рода проблем затруднительно. Как уже обсуждалось во второй части, каждый пул драйвера находится в отдельной странице. И когда драйвер А пытается повторно освободить память генерируется крах.

Давайте рассмотрим пример подобной ошибки. Для этого воспользуемся уже известной нам утилитой NotMyFault. Не включаем отслеживание за драйверами и выбираем опцию “Double Free”. Вот исходный код драйвера, который будет вызывать крах

VOID
DoubleFree(
VOID
)
{
PCHAR buffer = ExAllocatePool( NonPagedPool, ALLOCATION_SIZE );
ExFreePool( buffer );
ExFreePool( buffer );
}

Крэшим систему на виртуалке

Теперь давайте попытаемся выполнить анализ такого дампа.

Microsoft (R) Windows Debugger Version 6.3.9600.17298 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.

Loading Dump File [C:Downloads!Mini080915-06.dmp]
Mini Kernel Dump File: Only registers and stack trace are available

************* Symbol Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       srv*C:Symbols*https://msdl.microsoft.com/download/symbols
Symbol search path is: srv*C:Symbols*https://msdl.microsoft.com/download/symbols
Executable search path is:
Windows Server 2008/Windows Vista Kernel Version 6002 (Service Pack 2) UP Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 6002.18005.x86fre.lh_sp2rtm.090410-1830
Machine Name:
Kernel base = 0x81a48000 PsLoadedModuleList = 0x81b5fc70
Debug session time: Sun Aug  9 17:03:39.946 2015 (UTC + 3:00)
System Uptime: 0 days 0:02:29.986
Loading Kernel Symbols
.

Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long.
Run !sym noisy before .reload to track down problems loading symbols.

……………………………………………………..
……………………………………………………….
…………………….
Loading User Symbols
Loading unloaded module list
….
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck C2, {7, 110b, 9010000, 837e1008}

*** WARNING: Unable to verify timestamp for myfault.sys
*** ERROR: Module load completed but symbols could not be loaded for myfault.sys
GetPointerFromAddress: unable to read from 81b7f868
Unable to read MiSystemVaType memory at 81b5f420
Probably caused by : myfault.sys ( myfault+6ff )

Followup: MachineOwner
———

kd> !analyze 0v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck C2, {7, 110b, 9010000, 837e1008}

GetPointerFromAddress: unable to read from 81b7f868
Unable to read MiSystemVaType memory at 81b5f420
Probably caused by : myfault.sys ( myfault+6ff )

Followup: MachineOwner
———

kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

BAD_POOL_CALLER (c2)
The current thread is making a bad pool request.  Typically this is at a bad IRQL level or double freeing the same allocation, etc.
Arguments:
Arg1: 00000007, Attempt to free pool which was already freed
Arg2: 0000110b, (reserved)
Arg3: 09010000, Memory contents of the pool block
Arg4: 837e1008, Address of the block of pool being deallocated

Debugging Details:
——————

GetPointerFromAddress: unable to read from 81b7f868
Unable to read MiSystemVaType memory at 81b5f420

POOL_ADDRESS: GetPointerFromAddress: unable to read from 81b7f868
Unable to read MiSystemVaType memory at 81b5f420
837e1008

BUGCHECK_STR:  0xc2_7

CUSTOMER_CRASH_COUNT:  6

DEFAULT_BUCKET_ID:  COMMON_SYSTEM_FAULT

PROCESS_NAME:  NotMyfault.exe

CURRENT_IRQL:  0

ANALYSIS_VERSION: 6.3.9600.17298 (debuggers(dbg).141024-1500) amd64fre

LAST_CONTROL_TRANSFER:  from 81b35184 to 81b15b0d

STACK_TEXT: 
9d579b5c 81b35184 000000c2 00000007 0000110b nt!KeBugCheckEx+0x1e
9d579bd4 99d176ff 837e1008 00000000 00000000 nt!ExFreePoolWithTag+0x17f
WARNING: Stack unwind information not available. Following frames may be wrong.
9d579bf4 99d17b26 837aa960 00000001 00000000 myfault+0x6ff
9d579c2c 81a8c976 971ff040 8588ea40 8588ea40 myfault+0xb26
9d579c44 81c8e6a1 837aa960 8588ea40 8588eab0 nt!IofCallDriver+0x63
9d579c64 81c8ee46 971ff040 837aa960 00000000 nt!IopSynchronousServiceTail+0x1d9
9d579d00 81c8ff10 971ff040 8588ea40 00000000 nt!IopXxxControlFile+0x6b7
9d579d34 81a92c7a 00000090 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
9d579d34 77085e74 00000090 00000000 00000000 nt!KiFastCallEntry+0x12a
000bf758 00000000 00000000 00000000 00000000 0x77085e74

STACK_COMMAND:  kb

FOLLOWUP_IP:
myfault+6ff
99d176ff ??              ???

SYMBOL_STACK_INDEX:  2

SYMBOL_NAME:  myfault+6ff

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: myfault

IMAGE_NAME:  myfault.sys

DEBUG_FLR_IMAGE_TIMESTAMP:  4f806ca0

FAILURE_BUCKET_ID:  0xc2_7_myfault+6ff

BUCKET_ID:  0xc2_7_myfault+6ff

ANALYSIS_SOURCE:  KM

FAILURE_ID_HASH_STRING:  km:0xc2_7_myfault+6ff

FAILURE_ID_HASH:  {c8b4976b-dbc5-81a2-e89d-90cb17280354}

Followup: MachineOwner
———

Как видим механизм анализа указывает на myfault.sys, но  probably

Теперь включаем “особый пул” с помощью verifier

verifier /flags 1 /driver myfault.sys

Перегружаем компьютер и вновь крешим систему.

Теперь мы получаем стоп код 0x00000CC. Выполняем анализ с помощью Windbg.

Microsoft (R) Windows Debugger Version 6.3.9600.17298 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.


Loading Dump File [C:Downloads!Mini080915-07.dmp]
Mini Kernel Dump File: Only registers and stack trace are available


************* Symbol Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       srv*C:Symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: srv*C:Symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows Server 2008/Windows Vista Kernel Version 6002 (Service Pack 2) UP Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 6002.18005.x86fre.lh_sp2rtm.090410-1830
Machine Name:
Kernel base = 0x81a1a000 PsLoadedModuleList = 0x81b31c70
Debug session time: Sun Aug  9 17:17:38.639 2015 (UTC + 3:00)
System Uptime: 0 days 0:01:39.296
Loading Kernel Symbols
.

Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long.
Run !sym noisy before .reload to track down problems loading symbols.

..............................................................
................................................................
.........................
Loading User Symbols
Loading unloaded module list
....
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck 100000CC, {9f616000, 0, 81aa51bc, 0}

*** WARNING: Unable to verify timestamp for myfault.sys
*** ERROR: Module load completed but symbols could not be loaded for myfault.sys

Could not read faulting driver name
Probably caused by : myfault.sys ( myfault+6ff )

Followup: MachineOwner
---------

kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

PAGE_FAULT_IN_FREED_SPECIAL_POOL (cc)
Memory was referenced after it was freed.
This cannot be protected by try-except.
When possible, the guilty driver's name (Unicode string) is printed on
the bugcheck screen and saved in KiBugCheckDriver.
Arguments:
Arg1: 9f616000, memory referenced
Arg2: 00000000, value 0 = read operation, 1 = write operation
Arg3: 81aa51bc, if non-zero, the address which referenced memory.
Arg4: 00000000, Mm internal code.

Debugging Details:
------------------


Could not read faulting driver name

READ_ADDRESS: GetPointerFromAddress: unable to read from 81b51868
Unable to read MiSystemVaType memory at 81b31420
9f616000

FAULTING_IP:
nt!MmQuerySpecialPoolBlockSize+1a
81aa51bc 8b00            mov     eax,dword ptr [eax]

MM_INTERNAL_CODE:  0

CUSTOMER_CRASH_COUNT:  7

DEFAULT_BUCKET_ID:  COMMON_SYSTEM_FAULT

BUGCHECK_STR:  0xCC

PROCESS_NAME:  NotMyfault.exe

CURRENT_IRQL:  0

ANALYSIS_VERSION: 6.3.9600.17298 (debuggers(dbg).141024-1500) amd64fre

LAST_CONTROL_TRANSFER:  from 81b070e1 to 81aa51bc

STACK_TEXT:
9ada9b4c 81b070e1 00000000 9f616800 81cfe195 nt!MmQuerySpecialPoolBlockSize+0x1a
9ada9bb4 9c70a6ff 9f616800 00000000 00000000 nt!ExFreePoolWithTag+0xdc
WARNING: Stack unwind information not available. Following frames may be wrong.
9ada9bd4 9c70ab26 8a28e970 00000001 00000000 myfault+0x6ff
9ada9c0c 81cfc6be 8a134040 9f6aaf68 8a28e970 myfault+0xb26
9ada9c30 81a5e92d 9f6aafd8 9f6aaf68 8a134040 nt!IovCallDriver+0x23f
9ada9c44 81c606a1 8a28e970 9f6aaf68 9f6aafd8 nt!IofCallDriver+0x1b
9ada9c64 81c60e46 8a134040 8a28e970 00000000 nt!IopSynchronousServiceTail+0x1d9
9ada9d00 81c61f10 8a134040 9f6aaf68 00000000 nt!IopXxxControlFile+0x6b7
9ada9d34 81a64c7a 00000090 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
9ada9d34 77275e74 00000090 00000000 00000000 nt!KiFastCallEntry+0x12a
0008f5ec 00000000 00000000 00000000 00000000 0x77275e74


STACK_COMMAND:  kb

FOLLOWUP_IP:
myfault+6ff
9c70a6ff ??              ???

SYMBOL_STACK_INDEX:  2

SYMBOL_NAME:  myfault+6ff

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: myfault

IMAGE_NAME:  myfault.sys

DEBUG_FLR_IMAGE_TIMESTAMP:  4f806ca0

FAILURE_BUCKET_ID:  0xCC_myfault+6ff

BUCKET_ID:  0xCC_myfault+6ff

ANALYSIS_SOURCE:  KM

FAILURE_ID_HASH_STRING:  km:0xcc_myfault+6ff

FAILURE_ID_HASH:  {65a27173-7222-f0ba-5ad6-d0552d88cd8d}

Followup: MachineOwner
---------

Теперь благодаря использованию механизма “Особый пул”  мы получаем точное описание стоп кода:

PAGE_FAULT_IN_FREED_SPECIAL_POOL (cc)
Memory was referenced after it was freed.

Добавить комментарий

Ваш адрес email не будет опубликован.