File Minifilter Part4: Sending huge data from kernel to user mode efficiently using variable-sized structures

Today I will discuss how to send huge chunks of data (usually received in write operations) from kernel mode file system filter to its user-mode counter part. The default implementation of microsft in its sample of file scanner minifilter can send few KB of data per call (fltsendmessage) . The reason is that the structure defined to send different parameters including data to be written can contain only handful of KB due to the small size of stack in the kernel mode.

There are many different structures defined internally in the windows code which can send more data at runtime than these are defined for at compile time. These structures are defined with a fixed header at begining and followed by a variable-sized array.  Then these structures are allocated with sizeof(structure) + number of bytes need(which are accesible by this last array later on). The old new thing is the one cool blog explaining about this variable-sized structure approach.

For kernel mode

typedef struct _SCANNER_INFO {
//other members above here ....
INT iLengthContents;
CHAR  szContents[1];
} SCANNER_INFO;


This is how you will allocate this structure

iNewSize = FIELD_OFFSET(SCANNER_INFO, szContents[iLengthRequired); //this macro FIELD_OFFSET is used to get the offset which in this case will be the total size of the structure

SCANNER_INFO* pScanInfo = ExAllocatePoolWithTag( NonPagedPool,iNewSize,'info' );

Then use this structure to send it to user-mode as follows

FltSendMessage(fitlerHandle, port, pScanInfo , iNewSize,pReplyBuf, &iReplySize,&lTimeout);

In the user mode the default sample contains the following the structure to receive data from kernel mode in overlapped way.

typedef struct _SCANNER_MESSAGE {
OVERLAPPED Ovlp;
//
//  Required structure header.
//
FILTER_MESSAGE_HEADER MessageHeader;
//
//  Private scanner-specific fields begin here.
//
SCANNER_INFO scanInfo;
}SCANNER_MESSAGE,* PSCANNER_MESSAGE;

Allocate and use this message struct as follows.

int iSize = sizeof(OVERLAPPED) + sizeof(FILTER_MESSAGE_HEADER)+ FIELD_OFFSET(SCANNER_INFO, szContents[SCANNER_MAX_PACKET_SIZE+1]);  //SCANNER_MAX_PACKET_SIZE is any required size
pMsg = (PSCANNER_MESSAGE)malloc(iSize);

//the actual buffer needed by getfilter callback, excluding overlapped size
iSize = sizeof(FILTER_MESSAGE_HEADER) + FIELD_OFFSET(SCANNER_INFO, szContents[SCANNER_MAX_PACKET_SIZE]);
memset( & pMsg ->Ovlp, 0, sizeof( OVERLAPPED ) );
hr = FilterGetMessage(iport, & pMsg ->MessageHeader,  iSize,  &msg->Ovlp );

This way we can overcome the limitation of sending more data then a kernel-mode stack can hold thus improving performance of the filter (used in encryption, virus scans etc) by manifolds.

Advertisements
Explore posts in the same categories: Programming

Tags: ,

You can comment below, or link to this permanent URL from your own site.

2 Comments on “File Minifilter Part4: Sending huge data from kernel to user mode efficiently using variable-sized structures”

  1. Yaroslav Says:

    When I use this code in the user mode call GetQueuedCompletionStatus returns ERROR_INSUFFICIENT_BUFFER and in kernel mode FltSendMessage returns STATUS_PORT_DISCONNECTED. Where is a problem?

    • radiantway Says:

      ERROR_INSUFFICIENT_BUFFER is usually associated with not enough memory allocation. Your notification message structure should be allocated with the same size both at kernel mode as well as user mode. At kernel mode in the example above the pointer is ‘pScanInfo’ and in user mode it is ‘pMsg->scanInfo’.
      Also I have used ‘FIELD_OFFSET’ macro to calculate the required size so your ‘szContents[1]’ or ‘szContents[0]’ (array holding contents) should be the last member of the ScannerInfo structure both in kernel as well as in user mode.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: