DeviceIoControl returning ERROR_MORE_DATA

This error is only happening only 64 bit windows. On 32 bit windows this is working fine.

KERNEL_DATA outputBuffer;
memset(&outputBuffer, 0, sizeof(KERNEL_DATA));

if(!DeviceIoControl(sharingDevice_, COMM_CONTROL_GET_REQUEST, NULL, 0, &outputBuffer, sizeof(KERNEL_DATA), &bytesReturned, &outputOverlapped_))

sizeof(KERNEL_DATA) is 64 and byesReturned is giving me 88. I dont know where these extra 24 bytes are coming from and why this is only happening on 64 bit. If anyone can help please let me know. Thanks

Give us the struct definition . Also, a 32 or 64 bit app on the 64 bit os? Did you write the driver as well?

d

debt from my phone

-----Original Message-----
From: xxxxx@yahoo.com
Sent: Thursday, August 04, 2011 8:18 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] DeviceIoControl returning ERROR_MORE_DATA

This error is only happening only 64 bit windows. On 32 bit windows this is working fine.

KERNEL_DATA outputBuffer;
memset(&outputBuffer, 0, sizeof(KERNEL_DATA));

if(!DeviceIoControl(sharingDevice_, COMM_CONTROL_GET_REQUEST, NULL, 0, &outputBuffer, sizeof(KERNEL_DATA), &bytesReturned, &outputOverlapped_))

sizeof(KERNEL_DATA) is 64 and byesReturned is giving me 88. I dont know where these extra 24 bytes are coming from and why this is only happening on 64 bit. If anyone can help please let me know. Thanks


NTDEV is sponsored by OSR

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

The structure is below. Its a 32 bit app on a 64 bit os and yes I wrote the driver as well.

typedef struct _KERNEL_DATA
{
UINT64 ;
int ;
wchar_t* ;
int ;
USHORT ;
USHORT ;
ULONG ;
ULONG ;
USHORT ;
USHORT ;
USHORT ;
wchar_t* ;
int ;

char* ;
int ;
UINT64 ;
} KERNEL_DATA, *PKERNEL_DATA;

xxxxx@yahoo.com wrote:

The structure is below. Its a 32 bit app on a 64 bit os and yes I wrote the driver as well.

Then I’m not sure how you can be surprised by this. All of your
pointers are 8 bytes wide in a 64-bit compile, and 4 bytes wide in a
32-bit compile. Further, that changes the padding. In a 64-bit
compile, there will be padding bytes inserted before all of your
pointers, to make then 8-byte aligned.

Here are the byte offsets of each field in a 32-bit compile and a 64-bit
compile:

typedef struct _KERNEL_DATA
{
UINT64 a; // 0 0
int b; // 8 8
wchar_t* c; // 12 16
int d; // 16 24
USHORT e; // 20 28
USHORT f; // 22 30
ULONG g; // 24 32
ULONG h; // 28 36
USHORT i; // 32 40
USHORT j; // 34 42
USHORT k; // 36 44
wchar_t* l; // 40 48
int m; // 44 56
char* n; // 48 64
int o; // 52 72
UINT64 p; // 56 80
} KERNEL_DATA, *PKERNEL_DATA;

Total length 64 and 88.

This is the price you pay for the unwise decision to pass pointers from
user-mode to kernel-mode.


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

Also, are you seriously returning pointers from the kernel mode? That’s not going to work.

Thanks that breakdown was very helpful. So is there a way that I can get them to align with each other on the 64 and 32 bit compilers such as adding extra bytes for the 32 bit compilers or something or is that not possible?

Yes (for example, you could use __ptr64 and then carefully maintain C_ASSERTs in the 32-bit and 64-bit compilations enforcing that the structure size is as expected).

This is not what I would, however, recommend. It’s best to avoid embedding pointers into IOCTL structures (instead reference them via the appropriate in/out arguments to DeviceIoControl), both for this reason and the complicated and easy-to-get-subtlely-wrong semantics on how to safely validate and capture pointers supplied from user mode. Even the slightest mistake in the latter may create serious security vulnerabilities in your software that conventional testing would likely miss.

  • S (Msft)

-----Original Message-----
From: xxxxx@yahoo.com
Sent: Thursday, August 04, 2011 10:57
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] DeviceIoControl returning ERROR_MORE_DATA

Thanks that breakdown was very helpful. So is there a way that I can get them to align with each other on the 64 and 32 bit compilers such as adding extra bytes for the 32 bit compilers or something or is that not possible?


NTDEV is sponsored by OSR

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

Thanks the __ptr64 declaration worked however could you give me more incite into your recommended method. I allocate the structure in kernel mode then allocate each of the pointers when needed in the kernel. I send a DeviceIoControl control in the user mode with the structure to the kernel. The first call to the kernel I get the size of the buffer I need and send this back to user mode in the structure. In the user mode I allocate the pointer to be the size needed then send the structure again with the allocated pointer using DeviceIoControl and then I copy the pointer to the user allocated buffer and send this back to user mode. Is this open to security vulnerabilities and if so can you please explain the better recommend method of achieving this?

> Thanks that breakdown was very helpful. So is there a way that I can get them to align with each other on the 64

and 32 bit compilers such as adding extra bytes for the 32 bit compilers or something or is that not possible?

No.

In your driver code, define 2 structures for 32bit version - KERNEL_DATA_32 and KERNEL_DATA.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

xxxxx@yahoo.com wrote:

Thanks that breakdown was very helpful. So is there a way that I can get them to align with each other on the 64 and 32 bit compilers such as adding extra bytes for the 32 bit compilers or something or is that not possible?

Certainly, it’s possible. If you replace your pointers with ULONG64
variables, the structure will be the same size in both environments.
It’s up to you to do the casting back and forth. Now, that means you
won’t be binary compatible with your current release. If you don’t have
to worry about existing 32-bit applications, that’s fine. If you do
need binary compatibility, then the driver has to do a little more work.

However, as several folks have pointed out, it is not normal to pass
pointers in a structure like that. It is error-prone, because your
driver can’t dereference the pointers without locking the pages first.
The I/O manager doesn’t do that automatically. What are you doing with
those pointers?


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

xxxxx@yahoo.com wrote:

Thanks the __ptr64 declaration worked however could you give me more incite into your recommended method. I allocate the structure in kernel mode then allocate each of the pointers when needed in the kernel. I send a DeviceIoControl control in the user mode with the structure to the kernel. The first call to the kernel I get the size of the buffer I need and send this back to user mode in the structure. In the user mode I allocate the pointer to be the size needed then send the structure again with the allocated pointer using DeviceIoControl and then I copy the pointer to the user allocated buffer and send this back to user mode. Is this open to security vulnerabilities and if so can you please explain the better recommend method of achieving this?

I think you’re talking about the structure itself. The problem is not
the structure. The problem is that the structure CONTAINS pointers.
You have two wchar_t* fields in there, which point to Unicode strings.
Where do those strings reside? Are they in user memory or in kernel
memory? If they are in kernel mode, then your user-mode app cannot
access that memory, so it’s silly to return an address. If you are
sending them to user mode just so they can be sent back to the kernel
later, that’s a HUGE security hole. The user mode app could replace
those addresses with any numbers it wants, thereby causing a blue
screen, or (depending on how they are used) gaining access to arbitrary
kernel memory.


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

The pointers store strings of information I get in the kernel that I have to send to the user mode. I have no idea what size the strings could be or else I would have defined them as wchar_t string[500]. This is what I am doing:

In the Kernel:
I allocate the structure from NonPagedPool.
I allocate the strings from NonPagedPool if I need or use them.

In the User Mode:
I create the structure like this: KERNEL_DATA outputBuffer;
I pass the structure using the DeviceIoControl like in my 1st post.
If the IRP gets pended in the kernel I wait until I have data.

In the Kernel:
I copy all the information of the structure except for the strings to the IRP and complete it. This information also contains the size of each of the strings I allocated in the kernel.

In the User Mode:
I allocate the strings to be the size of the strings I need.
I pass the structure again with the user allocated addresses to the kernel using DeviceIoControl.

In the Kernel:
I copy the strings into the user allocated string buffers.
Free the kernel strings and structure.
Complete the IRP.

In the User Mode:
I now have all the information I need including the strings.

If you guys have any advice as to why this method is bad or how to fix it please let me know. Thanks

xxxxx@yahoo.com wrote:

The pointers store strings of information I get in the kernel that I have to send to the user mode. I have no idea what size the strings could be or else I would have defined them as wchar_t string[500]. This is what I am doing:

In the User Mode:
I allocate the strings to be the size of the strings I need.
I pass the structure again with the user allocated addresses to the kernel using DeviceIoControl.

There’s the step I would change. Instead of using your big structure
for this, just add additional ioctls to fetch the strings. It doesn’t
cost anything to create additional ioctls. You could add an
IOCTL_FETCH_MY_STRING ioctl, where the input buffer identified which
string you want, and the output buffer received the string. Or, you
could even add one ioctl per string.

In the User Mode:
I now have all the information I need including the strings.

If you guys have any advice as to why this method is bad or how to fix it please let me know.

It’s only bad because you are forcing the driver to work with raw
user-mode addresses. That’s tricky, because the user-mode addresses can
evaporate, unless you lock the pages down every time (which I’m guessing
you do not.)


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

Even if you get it to align, the underlying driver needs to detect if the pointer is 32 or 64 bits wide, no?

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@yahoo.com
Sent: Thursday, August 04, 2011 10:57 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] DeviceIoControl returning ERROR_MORE_DATA

Thanks that breakdown was very helpful. So is there a way that I can get them to align with each other on the 64 and 32 bit compilers such as adding extra bytes for the 32 bit compilers or something or is that not possible?


NTDEV is sponsored by OSR

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