오늘은 할당된 Kernelstack 을 초과 사용하여 BSOD(Bugcheck Code: 0x7f(0x8, x, y, n)) 상황에 대해서 알아보겠습니다.
버그 체크 코드가 발생한 상황이 발생하는 경우는 다음과 같습니다.
[커널 스택 오버플로우는 스레드별로 12Kbytes 정도로할당되는 제한된 시스템 리소스인 커널 스택영역을 초과하여 사용할 때 발생됩니다]
즉, KernelStack OverFlow 가 발생한 경우에는 단일 모듈(함수)내에서 가장 많은 스택을 사용한 모듈의 코드 수정이 필요합니다.
그럼 덤프를 간단하게 분석해 보겠습니다.
0: kd> kf 100
Memory ChildEBP RetAddr
ebee3ffc 804de605 hal!KeReleaseQueuedSpinLock+0x10
20 ebee401c f769b89b nt!ExReleaseResourceLite+0x8d
c ebee4028 f769d3a9 Ntfs!NtfsReleaseFcb+0x4e
18 ebee4040 f769b497 Ntfs!NtfsReleaseAllResources+0x62
18 ebee4058 f769b6e6 Ntfs!NtfsCleanupIrpContext+0x23
18 ebee4070 f76c0cd3 Ntfs!NtfsCompleteRequest+0x35
210 ebee4280 f76c0d83 Ntfs!NtfsCommonCleanup+0x2601
178 ebee43f8 804e33d9 Ntfs!NtfsFsdCleanup+0xcf
10 ebee4408 f7743bbf nt!IopfCallDriver+0x31
10 ebee4418 804e33d9 sr!SrCleanup+0xb3
10 ebee4428 ec631f92 nt!IopfCallDriver+0x31
WARNING: Stack unwind information not available. Following frames may be wrong.
1c ebee4444 ec62de51 AhnFlt2K+0x4f92
18 ebee445c 804e33d9 AhnFlt2K+0xe51
10 ebee446c 8057e627 nt!IopfCallDriver+0x31
30 ebee449c 80570943 nt!IopCloseFile+0x26b
30 ebee44cc 80570a96 nt!ObpDecrementHandleCount+0x11b
28 ebee44f4 805709bc nt!ObpCloseHandleTableEntry+0x14d
48 ebee453c 80570a06 nt!ObpCloseHandle+0x87
14 ebee4550 804df99f nt!NtClose+0x1d
0 ebee4550 804e5487 nt!KiFastCallEntry+0xfc
7c ebee45cc f7d86552 nt!ZwClose+0x11
81c ebee4de8 f7d8661d MyDrv!OpenClose+0xc2 [e:\test\mydrv\mydrv.c @ 264]
fb4 ebee5d9c f7d86648 MyDrv!UseStack2+0x1d [e:\test\mydrv\mydrv.c @ 286]
fb0 ebee6d4c f7d86678 MyDrv!UseStack1+0x18 [e:\test\mydrv\mydrv.c @ 293]
fb0 ebee7cfc f7d871c2 MyDrv!BugCheck7F+0x18 [e:\test\mydrv\mydrv.c @ 300]
f44 ebee8c40 804e33d9 MyDrv!MyDrvDeviceControl+0x312 [e:\test\mydrv\mydrv.c @ 460]
10 ebee8c50 8057150b nt!IopfCallDriver+0x31
14 ebee8c64 80582fb1 nt!IopSynchronousServiceTail+0x60
9c ebee8d00 8058909e nt!IopXxxControlFile+0x5ef
34 ebee8d34 804df99f nt!NtDeviceIoControlFile+0x2a
0 ebee8d34 7c93eb94 nt!KiFastCallEntry+0xfc
WinDBG 명령어중 kb 또는 kv 대신에 kf를 사용했습니다. ChildEBP 의 변화량을 모듈별로 보는 것입니다. 일일이 손으로 계산해도 상관없으나 kf 명령어를 사용하면 삽질이 필요없습니다
맨 왼쪽에 보이는 숫자들이 각 함수가 소진한 스택의 량입니다.
한 눈에 보면 MyDrv 가 문제가 있는 녀석이라고 느껴집니다.
사용한 양을 계산해 보면
0: kd> ? 81c + fb4 + fb0 + fb0 + f44
Evaluate expression: 18036 = 00004674
우와~~~ 자그마치 18KB 를 사용하고 있습니다.
도대체 뭘 하느라고 스택을 저렇게 사용할까요? 함수 이름도 범상치 않군여... 한번 봅시다.
void UseStack1(void)
{
char szBuf[4000];
UseStack2();
아... 네... 지역변수를 4000 바이트 사용했네요. 이런일 없어야 겠습니다.
이 녀석이야 예제라지만 이름이 UseStack 도 아니면서 저렇게 사용하는 경우.... 실제 상황에서 종종 봤습니다. -_-;;;
4000 바이트 까지야 없겠지만 100 바이트 이상은 많았습니다. 하나의 함수가 사용하는 지역변수 크기의 합이 100 바이트 넘어가면 문제 있다고 보셔야 합니다.
그런 관점에서 Ntfs 저 녀석도 범인으로 봐야 합니다. 스택 사용량이 가장 큰 함수 두개만 더해봐도
0: kd> ? 210 + 178
Evaluate expression: 904 = 00000388
거의 1KB 가까이 사용하고 있습니다.
MS에서 만든 드라이버 모듈도 커널 스택메모리를 많이 사용하네요 ^^;;;
Kernel stack overflow 는 파일 필터 분야에서 늘 있어왔던 문제이고 필터들이 워낙 많기 때문에 우리 드라이버가 사용할 공간이 늘 협소하다고 가정해야 합니다. 함수 하나당 100 바이트 이하로 하는 것을 권장합니다.
마지막으로 !analyze -v 를 이용해서 커널 스택 오버플로우를 덤프를 분석하면 마지막 드라이버 모듈에서 호출한 스택정보만 보여주는 경우가 있습니다. 그렇기 때문에 커널 스택 오버플로우(Bugcheck Code: 0x7f(0x8, x, y, n))에서는 꼭 kf 명령어를 이용해서 커널 스택의 전체 메모리 사용량을 확인해 봐야 합니다.^^b
출처 : 다년간의 프로그램밍 경험 및 greemate님 자료로 부터(greemate.tistory.com)
댓글 없음:
댓글 쓰기