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

В предыдущих 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*http://msdl.microsoft.com/download/symbols

Symbol search path is: srv*C:Symbols*http://msdl.microsoft.com/download/symbolsExecutable search path is: Windows Server 2008/Windows Vista Kernel Version 6002 (Service Pack 2) UP Free x86 compatibleProduct: WinNt, suite: TerminalServer SingleUserTSBuilt by: 6002.18005.x86fre.lh_sp2rtm.090410-1830Machine Name:Kernel base = 0x81a48000 PsLoadedModuleList = 0x81b5fc70Debug session time: Sun Aug  9 17:03:39.946 2015 (UTC + 3:00)System Uptime: 0 days 0:02:29.986Loading 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 SymbolsLoading 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.sysGetPointerFromAddress: unable to read from 81b7f868Unable 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 81b7f868Unable 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 freedArg2: 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 81b7f868Unable 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+0x1e9d579bd4 99d176ff 837e1008 00000000 00000000 nt!ExFreePoolWithTag+0x17fWARNING: Stack unwind information not available. Following frames may be wrong.9d579bf4 99d17b26 837aa960 00000001 00000000 myfault+0x6ff9d579c2c 81a8c976 971ff040 8588ea40 8588ea40 myfault+0xb269d579c44 81c8e6a1 837aa960 8588ea40 8588eab0 nt!IofCallDriver+0x639d579c64 81c8ee46 971ff040 837aa960 00000000 nt!IopSynchronousServiceTail+0x1d99d579d00 81c8ff10 971ff040 8588ea40 00000000 nt!IopXxxControlFile+0x6b79d579d34 81a92c7a 00000090 00000000 00000000 nt!NtDeviceIoControlFile+0x2a9d579d34 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.

Понравилась статья? Поделиться с друзьями: