Freigeben über


I/O Stack Locations

일반적으로 함수가 호출될 때마다 ESP, EBP 레지스터 정보와 함께 thread stack를 이용해서 함수에 전달되어야 하는 파라미터 정보와 함수 실행이 끝난 뒤에 리턴되어야 하는 함수의 주소 정보 등을 담아두게 된다. stack에 쌓인 이러한 정보를 역으로 추적하게 되면 현재 실행중인 함수에 이르기까지 호출된 함수들과 전달된 파라미터 정보들을 확인할 수 있는데 이를 'Call Stack'이라고 한다.

Driver에서는 이와 유사한 개념으로 특정 IRP(I/O Request Packet)를 처리하는데 관여할 수 있는 여러 driver들이 마치 chain과 같은 형태를 구성하고 있는데 이를 'Driver Stack'이라고 한다. IRP를 처리할 때 필요한 처리 루틴이나 파라미터 등의 정보를 각각의 driver 들은 I/O stack location이라는 구조체에 저장하여 해당 IRP에 append 시켜야 하며, 상위 레벨의 driver는 하위 레벨의 driver에게 IoCallDriver 를 호출해서 IRP를 전달하기 전에 해당 stack location의 정보를 반드시 채워야 한다.

I/O manager는 이러한 Driver Stack을 구현하기 위해서 각 IRP마다 I/O stack location 정보를 저장할 수 있도록 배열을 만든다. 각 driver들은 특정 IRP를 처리하기 전에 IoGetCurrentIrpStackLocation 함수를 호출함으로써 해당 driver가 I/O operation을 수앵하는데 필요한 고유의 I/O stack location 정보를 얻을 수 있다.

다음 그림은 IRP 내에 저장되는 데이터를 도식화한 것이다.

아래 부분에 흰색 블록으로 표현된 것이 하나의 I/O stack location이며, 만약 2개의 driver가 관여하고 있다면 I/O stack location이 하나 더 append 된 형태가 될 것이다.

 

하나의 I/O Stack Location 정보는 IO_STACK_LOCATION 구조체를 이용해서 정의할 수 있는데, WDK에서 확인할 수 있는 IO_STACK_LOCATION 구조체의 정의는 다음과 같다.

typedef struct  _IO_STACK_LOCATION {
  UCHAR  MajorFunction;  // 수행되어야 할 I/O operation 타입
  UCHAR  MinorFunction;  // MajorFunction에 대한 Sub funtion code
  UCHAR  Flags;   // 요청에 대한 플래그 (파일 시스템 드라이버에서 주로 사용됨)
  UCHAR  Control;  //
  union {
        //
        // Parameters for IRP_MJ_CREATE 
        //
        struct {
            PIO_SECURITY_CONTEXT SecurityContext;
            ULONG Options;
            USHORT POINTER_ALIGNMENT FileAttributes;
            USHORT ShareAccess;
            ULONG POINTER_ALIGNMENT EaLength;
        } Create;
        //
        // Parameters for IRP_MJ_READ 
        //
        struct {
            ULONG Length;
            ULONG POINTER_ALIGNMENT Key;
            LARGE_INTEGER ByteOffset;
        } Read;
        /* 이하 생략 */
        /* full list는 https://msdn.microsoft.com/en-us/library/aa491675.aspx 참고 */
  } Parameters;  // MajorFunction과 MinorFunction 수행에 필요한 파라미터

  PDEVICE_OBJECT  DeviceObject;  // IRP를 처리해야하는 target device (DEVICE_OBJECT 구조체 포인터)
  PFILE_OBJECT  FileObject;  // DeviceObject와 관련된 file object (FILE_OBJECT 구조체 포인터 ) 
 .
IO_STACK_LOCATION, *PIO_STACK_LOCATION;

WinDbg에서 !irp 명령을 이용하면 다음과 같이 특정 IRP에 관련된 I/O Stack Location 정보를 확인할 수 있다.

0: kd>  !irp 0x831f4a00
Irp is active with 8 stacks 5 is current (= 0x831f4b00)
 Mdl = 82b020d8 Thread 8c622118:  Irp stack trace.
     cmd flg cl Device File Completion-Context
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

                        Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

                        Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

                        Args: 00000000 00000000 00000000 00000000
 [  0, 0]   0  0 00000000 00000000 00000000-00000000

                        Args: 00000000 00000000 00000000 00000000
>[  3,34]  40 e1 828517a8 00000000 842511e0-00000000 Success Error Cancel pending
               \Driver\disk     partmgr!PmReadWriteCompletion
                        Args: 00007000 00000000 fe084e00 00000004
 [  3, 0]  40 e0 82851450 00000000 842414d4-82956350 Success Error Cancel
               \Driver\PartMgr  volmgr!VmpReadWriteCompletionRoutine
                        Args: 129131bb 000000de fe084e00 00000004
 [  3, 0]   0 e0 82956298 00000000 847eeed0-829e2ba8 Success Error Cancel
               \Driver\volmgr   Ntfs!NtfsMasterIrpSyncCompletionRoutine
                        Args: 00007000 00000000 1bdae400 00000000
 [  3, 0]   0  0 82ac2020 8e879410 00000000-00000000
                \FileSystem\Ntfs
                        Args: 00007000 00000000 00018400 00000000

References 

WDK I/O Stack Locations
https://msdn.microsoft.com/en-us/library/ms795764.aspx

Comments