관리 메뉴

kisoo

Kernel Stack Overflow ( Bug Check 0x7f) 본문

01.About Programming /2.Kernel Lab

Kernel Stack Overflow ( Bug Check 0x7f)

JamesK78 2008. 10. 20. 23:56

오늘은 할당된 Kernelstack 을 초과 사용하여 BSOD(Bugcheck Code: 0x7f(0x8, x, y, n)) 상황에 대해서 알아보겠습니다.

 Bug Check 0x7f 가 발생 하는 경우 는 다음과 같습니다.

 원인 :Kernel Stack Overflow 는 Thread 별로 12Kbytes 정도로할당되는 제한된 시스템 리소스인
         커널 스택영역을 초과하여 사용할 때 발생됩니다.

* 여기서 잠깐 -  왜 스택 사이즈가 12kb 뿐 일까??
**********
윈도우 운영체제에서 스레드를 생성하면 User : Kernel 영역에 1:1로 매치되서 생성됩니다.
즉, 유저영역에서 스레드를 많이 생성할수록  커널영역에서도 스레드가 많이 생성됩니다.

만약, 많은 수의 스레드를 User 영역에서 생성했다면 커널영역에서도 생성이 되어야 하고 생성된 여러스레드를  운영체제에서는 context switch를 통해서 thread scheduling을 해주어야 합니다. 즉, 커널 스택 사이즈가 크다면  context switch에 많은 부하가 발생합니다. 이것을 방지하기 위해서 커널스택 사이즈가 12kb인 것입니다
**********

즉, 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


Comments