DeviceIoControl Maximum Buffer Size

I’m trying to use DeviceIoControl in my win32 application to send some big message for my kernel-driver, but I can’t use buffer, that larger than about 17kb (it’s variable).

First, I used METHOD_BUFFERED in CTL_CODE, and then METHOD_IN_DIRECT, but it doesn’t work.

My question is:
What is the maximum size of the buffer which I can send with DeviceIoControl?

Thanks in advance,
Daniel M.

“it doesn’t work” has to be the most ambiguous explanation of the problem
ever.
What error you get ?
How do you call the DeviceIoControl ?
Does it reach your dispatch function in the driver ?
etc…
etc…
etc…

Gabriel

On Tue, Oct 13, 2015 at 9:31 AM, wrote:

> I’m trying to use DeviceIoControl in my win32 application to send some big
> message for my kernel-driver, but I can’t use buffer, that larger than
> about 17kb (it’s variable).
>
> First, I used METHOD_BUFFERED in CTL_CODE, and then METHOD_IN_DIRECT, but
> it doesn’t work.
>
> My question is:
> What is the maximum size of the buffer which I can send with
> DeviceIoControl?
>
>
> Thanks in advance,
> Daniel M.
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


Bercea. G.

Sorry for my ambiguous problem.

The error code is 998 (ERROR_NOACCESS).
It doesn’t reach the driver dispatch function.

The DeviceIoControl call is:
DeviceIoControl(interfaceHandle, command.getIOControlCode(), &request, command.getRequestSize(), NULL, 0, &bytesReturned, NULL)

where IOControlCode (command.getIOControlCode() response) is:
#define IOCTL_RESTORE CTL_CODE(FILE_DEVICE_NETWORK, 0x810, METHOD_IN_DIRECT, FILE_ANY_ACCESS)

request is a struct which is:
struct RESTORE {
WCHAR name[256];
UINT32* content;
UINT32 contentSize;
}

command.getRequestSize() return with struct size, which calculated by
sizeof(WCHAR) * 256 + sizeof(UINT32) * (contentSize + 1)
formula.

Thanks in advance,
Daniel

Well there you go.

The content size is not correct. It is always a static: sizeof(RESTORE).
The fact that you think the DeviceIoControl will “know” that the “UINT32*
content” is as big as the UINT32 contentSize is a wrong assumption. Those
are just 2 members in a struct.
What you send down to the driver is only that structure ( which btw I would
not send that way ).

You should make the "command.getRequestSize() " to return sizeof ( REQUEST
) which is pretty much equal to: sizeof (WCHAR) * 256 + sizeof(UINT32*) +
sizeof(UINT32) and of course when
it reaches your dispatch routine, that one will know how to use those
pointers there ( and make sense of the sizes and stuff )

So again make sure you handle those user-mode pointers right when you are
in kernel, or just send data there differently not like this, redesign the
structure I would say, but nevertheless the size you are telling
deviceIoControl is wrong, it will try to probe beyond the actual size,
beyond by sizeof(UINT32) * ( contentSize + 1 ) what you really have there,
hence your issue.

I hope it is more clear now why.

Gabriel

On Tue, Oct 13, 2015 at 10:47 AM, wrote:

> Sorry for my ambiguous problem.
>
> The error code is 998 (ERROR_NOACCESS).
> It doesn’t reach the driver dispatch function.
>
> The DeviceIoControl call is:
> DeviceIoControl(interfaceHandle, command.getIOControlCode(), &request,
> command.getRequestSize(), NULL, 0, &bytesReturned, NULL)
>
> where IOControlCode (command.getIOControlCode() response) is:
> #define IOCTL_RESTORE CTL_CODE(FILE_DEVICE_NETWORK, 0x810,
> METHOD_IN_DIRECT, FILE_ANY_ACCESS)
>
> request is a struct which is:
> struct RESTORE {
> WCHAR name[256];
> UINT32* content;
> UINT32 contentSize;
> }
>
> command.getRequestSize() return with struct size, which calculated by
> sizeof(WCHAR) * 256 + sizeof(UINT32) * (contentSize + 1)
> formula.
>
>
> Thanks in advance,
> Daniel
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


Bercea. G.

xxxxx@web-szerver.hu wrote:

request is a struct which is:
struct RESTORE {
WCHAR name[256];
UINT32* content;
UINT32 contentSize;
}

command.getRequestSize() return with struct size, which calculated by
sizeof(WCHAR) * 256 + sizeof(UINT32) * (contentSize + 1)
formula.

Your formula assumes that sizeof(UINT32*) == sizeof(UINT32). If you are
on a 64-bit system, that assumption is incorrect.

Further, if you are running a 32-bit application on a 64-bit system, the
driver and the application will not have the same layout for that
structure, and disaster will ensue.

As a general rule, never, never, never include pointers in ioctl
buffers. If you need to pass a descriptor and a buffer, put the
descriptor in the first ioctl buffer and the buffer in the second.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thank you for your replies.

xxxxx@gmail.com wrote:

The fact that you think the DeviceIoControl will “know” that the “UINT32*
content” is as big as the UINT32 contentSize is a wrong assumption. Those
are just 2 members in a struct.
What you send down to the driver is only that structure ( which btw I would
not send that way ).

So again make sure you handle those user-mode pointers right when you are
in kernel, or just send data there differently not like this, redesign the
structure I would say, but nevertheless the size you are telling
deviceIoControl is wrong, it will try to probe beyond the actual size,
beyond by sizeof(UINT32) * ( contentSize + 1 ) what you really have there,
hence your issue.

I got the problem and solved it. I’am a newbie and I don’t know how to redesign the structure to send dynamic content to kernel-driver. Can you give me some instruction about it?

xxxxx@probo.com wrote:

As a general rule, never, never, never include pointers in ioctl
buffers. If you need to pass a descriptor and a buffer, put the
descriptor in the first ioctl buffer and the buffer in the second.

I understand this, and try to redesign my application. But what about the situation, when I have more then one descriptor?

Well it depends what you really want to do, but how I approach these things
is put all the non dynamic part in the beginning and then let the dynamic
part at the end something like this:

typedef my_struct
{
//
// fixed part
//
ULONG size;
ULONG someFlags;
ULONG anotherMember;
BOOLEAN shouldDoWhatever;
ULONG someNameLength;
ULONG otherDataLength;
ULONG dynamicLen; // optional I guess in this case
//
//dynamic part now
//
CHAR Data[1]
}

Assuming you have this and you want to send to your driver a
“someNameLength” worth of a file name + some extra stuff that your driver
knows how to handle ( in this case the otherDataLength tells you how much)
you declare something like
my_struct *DataToSend = allocate(sizeof(my_struct) + fileNameLength +
extraDataLen);

should the allocation succeed you now fill the non dynamic members first:

DataToSend->size = sizeof(my_struct) + fileNameLength + extraDataLen;

DataToSend->someNameLength = filename->Length;
etc…

and now the dynamic part:
first let’s say you copy the name, you already know the length it is
specified in the "someNameLength’ member

RtlCopyMemory(&(DataToSend->Data[0]), myFileName->Buffer, nameLength);

and if you have some other data to send add that as well after the name

PVOID otherDataPointerOffset = (PVOID)((char*)(&DataToSend->Data[0]) +
nameLength);
RtlCopyMemory(otherDataPointerOffset, DataBuffer, DataLength );

And now you call DeviceIoControl and have as the input buffer your
“DataToSend” pointer and as size the one you actually allocated in this
case: “sizeof(my_struct) + fileNameLength + extraDataLen”

In the driver you just “unpack”/ deserialze this struct, knowing that the
first someNameLength bytes starting drom Data[0] is the name you need, and
the next otherDataLength bytes are the extra data you want to send.

There are other ways I don’t know if this is really the best fit for you
but this way there are no pointers involved in the driver.

Good luck,
Gabriel

On Wed, Oct 14, 2015 at 8:20 AM, wrote:

> Thank you for your replies.
>
> xxxxx@gmail.com wrote:
> > The fact that you think the DeviceIoControl will “know” that the “UINT32*
> > content” is as big as the UINT32 contentSize is a wrong assumption. Those
> > are just 2 members in a struct.
> > What you send down to the driver is only that structure ( which btw I
> would
> > not send that way ).
> …
> > So again make sure you handle those user-mode pointers right when you are
> > in kernel, or just send data there differently not like this, redesign
> the
> > structure I would say, but nevertheless the size you are telling
> > deviceIoControl is wrong, it will try to probe beyond the actual size,
> > beyond by sizeof(UINT32) * ( contentSize + 1 ) what you really have
> there,
> > hence your issue.
>
> I got the problem and solved it. I’am a newbie and I don’t know how to
> redesign the structure to send dynamic content to kernel-driver. Can you
> give me some instruction about it?
>
> xxxxx@probo.com wrote:
> > As a general rule, never, never, never include pointers in ioctl
> > buffers. If you need to pass a descriptor and a buffer, put the
> > descriptor in the first ioctl buffer and the buffer in the second.
>
> I understand this, and try to redesign my application. But what about the
> situation, when I have more then one descriptor?
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


Bercea. G.

xxxxx@web-szerver.hu wrote:

> So again make sure you handle those user-mode pointers right when you are
> in kernel, or just send data there differently not like this, redesign the
> structure I would say, but nevertheless the size you are telling
> deviceIoControl is wrong, it will try to probe beyond the actual size,
> beyond by sizeof(UINT32) * ( contentSize + 1 ) what you really have there,
> hence your issue.
I got the problem and solved it. I’am a newbie and I don’t know how to redesign the structure to send dynamic content to kernel-driver. Can you give me some instruction about it?

I’m not sure what you mean by “dynamic content”. Any time you have a
pointer in a structure passed to an ioctl, you have to worry about 32/64
issues. There are two ways to handle that. You can use
IoIs32bitProcess in the driver to detect that your client has passed
32-bit pointers and convert the structure there, or you can use
ULONGLONG in the structure instead of the pointer.

xxxxx@probo.com wrote:
> As a general rule, never, never, never include pointers in ioctl
> buffers. If you need to pass a descriptor and a buffer, put the
> descriptor in the first ioctl buffer and the buffer in the second.
I understand this, and try to redesign my application. But what about the situation, when I have more then one descriptor?

Then you send multiple ioctls.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.