Accessing usermode file handle from kernel

Hi,

I want to access a user mode file handle from kernel, for reading an
existing file. For that I have created the user mode handle by calling
NtCreateFile. Then the handle is passed to the kernel through an
DeviceIoControl call. Then the handle is verified in Kernel using
“ObReferenceObjectByHandle”. But when I try to read from file using
zwReadFile I get an error - “Invalid handle”. Isn’ t this the right
approach?

I am adding my code here for your reference-

Usermode

UNICODE_STRING myFilePath;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS status;
HANDLE handle;
RtlInitUnicodeString(&myFilePath, L"\??\C:\myfile.txt");
InitializeObjectAttributes(&ObjectAttributes, &myFilePath,
OBJ_KERNEL_HANDLE | OBJ_FORCE_ACCESS_CHECK, NULL, NULL);
status = NtCreateFile(&handle, FILE_READ_DATA | SYNCHRONIZE,
&ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ, FILE_OPEN, FILE_RANDOM_ACCESS, NULL, 0);

Kernel

FILE_OBJECT fo;
OBJECT_HANDLE_INFORMATION ohi;
NTSTATUS stat=ObReferenceObjectByHandle(FileHandle /*handle received
through DeviceIoControl*/, 0L, *IoFileObjectType, UserMode, (PVOID)&fo,
&ohi);
//The above call succeeds

/*The following call is made from a WORKER THREAD*/

NTSTATUS stat = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock,
sysAddr, readLength, &offset, NULL);

The above call fails with Invalid handle (Error code “0xc0000008”). Can you
please shed some light on this issue?

Thanks a lot,
Lloyd

You need to open a kernel handle to the FILE_OBJECT.

FileHandle is only valid in the context of the caller, it’s not valid in the context of a worker thread which belongs to the system process.

Why are you using NtCreateFile in user mode?

I was thinking that File handle can be shared.

Initially i tried with handle returned by “CreateFile” call and that did
not work (I understand that this is a blunder mistake, forgive me). From
further reading I understood that the handle has to be created with
“OBJ_KERNEL_HANDLE”.
zwCreateFile and NtCreateFile are supporting this. In zwCreateFile’s doc it
is mentioned that it should not be called from usermode, so I went with
NtCreateFile.

I would be happy if you can elaborate on opening handle to FILE_OBJECT and
accessing it from kernel.

Thanks a lot,
Lloyd

On Mon, Oct 20, 2014 at 8:18 PM, wrote:

> You need to open a kernel handle to the FILE_OBJECT.
>
> FileHandle is only valid in the context of the caller, it’s not valid in
> the context of a worker thread which belongs to the system process.
>
> Why are you using NtCreateFile in user mode?
>
> —
> 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
>

Calling NtCreateFile in user mode with OBJ_KERNEL_HANDLE will NOT give you a kernel handle. That would be a giant security hole.

Why do you need to open the file in user mode? The driver could open the file.

If you have a handle from user mode, use ObReferenceObjectByHandle to get a pointer to the object, and then ObOpenObjectByPointer to create a kernel mode handle for it.

On Mon, Oct 20, 2014 at 10:42 PM, wrote:

> Why do you need to open the file in user mode? The driver could open the
> file.
>

If you check my previous thread about constructing file names in kernel (
http://www.osronline.com/showthread.cfm?link=260371) , Peter suggested me
to – “You construct the name in user-mode, open the file in user-mode, and
pass the handle the driver.”.-- I am trying this approach.

>
> If you have a handle from user mode, use ObReferenceObjectByHandle to get
> a pointer to the object, and then ObOpenObjectByPointer to create a kernel
> mode handle for it.
>

Thank you very much. I will try this…

Thanks a lot,
Lloyd

>
> —
> 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
>

Good choice.

You can just open the file in the “ordinary way” using the Win32 CreateFile function. No need to do anything fancy, like use ZwCreateFile or NtCreateFile (which are, by the way, EXACTLY the same when used from user-mode… don’t believe me? Disassemble ZwCreateFile and NtCreateFile from the user-mode debugger… you’ll see they’re not only the same code, they decode to exactly the same address).

Peter
OSR
@OSRDriver

Returning to the previous thread, it’s unclear why do you need to process the file in kernel mode at all.

>I want to access a user mode file handle from kernel, for reading an existing file. For that I have

created the user mode handle by calling NtCreateFile.

This, if done in a dumb way, is considered to be a security violation and is prohibited by modern Windows kernels and modern Driver Verifier.

Then the handle is passed to the kernel through an DeviceIoControl call. Then the handle is verified
in Kernel using “ObReferenceObjectByHandle”. But when I try to read from file using zwReadFile I
get an error - “Invalid handle”. Isn’ t this the right approach?

Yes, this is exactly the dumb case, which is now a failure.

To be not dumb, use ObOpenObjectByPointer with OBJ_KERNEL_HANDLE on the file object from ObReferenceObjectByHandle. This creates the new handle, use it for your calls.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

>This, if done in a dumb way, is considered to be a security violation and is prohibited by modern Windows kernels and modern Driver Verifier.

Good point Maxim. I used to think that kernel mode components should not trust user mode handles and the following page confirms this.

http://msdn.microsoft.com/en-us/library/windows/hardware/ff557758(v=vs.85).aspx

Why an application can pass 4 or 8 bytes as a handle to a driver but cannot pass the exact same string that was passed to NtCreateFile in user mode ?

There are plenty of system services that do the advert, i.e filling user mode memory with unicode strings. The ZwQueryInformationFile API called with the FileNameInformation info class is a good example.

The FILE_NAME_INFORMATION structure is interesting for the purpose of passing a WCHAR string to the kernel.

Every time you someone calls ReadFile or WriteFile they pass a handle to kernel mode, and the kernel mode component validates that handle.

It’s not some magic process… It’s pretty simple, actually.

Peter
OSR
@OSRDrivers

>Every time you someone calls ReadFile or WriteFile they pass a handle to kernel mode, and the kernel mode component validates that handle.

It’s not some magic process… It’s pretty simple, actually.

Yes, a system call is guaranted to execute in the context of the caller. That is the “privilege” of system calls.

But drivers must “detour” the I/O system to implement their kind of “system calls” or “system services”, but only highest level drivers execute in the context of the caller I think.

EvtIoInCallerContext documentation

If a driver registers an EvtIoInCallerContext callback function for a device, the framework calls the callback function each time it receives an I/O request for the device. The callback function is called in the thread context of the process that sent the I/O request to the driver. This process is either the next-higher level driver or, if the driver is at the top of the driver stack, a user-mode application.

So there is the case where a device is attached (always on the top) of your device’s stack. The IoAttachDevice documentation explains that the file object for your device is opened upon attachement and therefore, I assume, your driver should recieve an IRP_MJ_CREATE IRP. If that is the case, I don’t know if failing the IRP_MJ_CREATE IRP results in the attachement being failed.

This is a virtual storport miniport driver to “mount” a custom disk image
file. This image is split into multiple files with extensions line
000,001,002 etc…

On Mon, Oct 20, 2014 at 11:49 PM, wrote:

> Returning to the previous thread, it’s unclear why do you need to process
> the file in kernel mode at all.
>
> —
> 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
>

I have tried “ObOpenObjectByPointer with OBJ_KERNEL_HANDLE”, but it fails
with “STATUS_OBJECT_TYPE_MISMATCH”.

This is my code

FILE_OBJECT fo;
OBJECT_HANDLE_INFORMATION ohi;
stat = ObReferenceObjectByHandle(FileHandle, 0L, *IoFileObjectType,
UserMode, (PVOID)&fo, &ohi);
/*Above call succeeds*/

HANDLE h;
stat = ObOpenObjectByPointer((PVOID)&fo, OBJ_FORCE_ACCESS_CHECK |
OBJ_KERNEL_HANDLE , NULL, GENERIC_READ, *IoFileObjectType, KernelMode, &h);

This call fails with STATUS_OBJECT_TYPE_MISMATCH. In the documentation of
ObOpenObjectByPointer, it is mentioned that :-

“If the *Object* parameter points to a file object (that is, a FILE_OBJECT
structure), *ObOpenObjectByPointer* can only be called after at least one
handle has been created for the file object. Callers can check the
*Flags* member
of the FILE_OBJECT structure that the *Object* parameter points to. If the
FO_HANDLE_CREATED flag is set, this means that one or more handles have
been created for the file object, so it is safe to call
*ObOpenObjectByPointer*.”

In my case, the FO_HANDLE_CREATED is not set.

How can I resolve this issue?

Thanks a lot,
Lloyd

On Tue, Oct 21, 2014 at 4:25 AM, Maxim S. Shatskih
wrote:

> >I want to access a user mode file handle from kernel, for reading an
> existing file. For that I have
> >created the user mode handle by calling NtCreateFile.
>
> This, if done in a dumb way, is considered to be a security violation and
> is prohibited by modern Windows kernels and modern Driver Verifier.
>
> >Then the handle is passed to the kernel through an DeviceIoControl call.
> Then the handle is verified
> >in Kernel using “ObReferenceObjectByHandle”. But when I try to read from
> file using zwReadFile I
> >get an error - “Invalid handle”. Isn’ t this the right approach?
>
> Yes, this is exactly the dumb case, which is now a failure.
>
> To be not dumb, use ObOpenObjectByPointer with OBJ_KERNEL_HANDLE on the
> file object from ObReferenceObjectByHandle. This creates the new handle,
> use it for your calls.
>
> –
> Maxim S. Shatskih
> Microsoft MVP on File System And Storage
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
>
> —
> 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
>

> It’s not some magic process… It’s pretty simple, actually.

Yes, but validation is process-context-dependent, and the app’s handle can be validated in the context of System process providing bad results.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

> FILE_OBJECT fo;
> stat = ObReferenceObjectByHandle(FileHandle, 0L, *IoFileObjectType,
> UserMode, (PVOID)&fo, &ohi);

This should be:

PFILE_OBJECT fo;

stat = ObOpenObjectByPointer((PVOID)fo, OBJ_FORCE_ACCESS_CHECK |

– pa

On 21-Oct-2014 12:33, Lloyd wrote:

I have tried “ObOpenObjectByPointer with OBJ_KERNEL_HANDLE”, but it
fails with “STATUS_OBJECT_TYPE_MISMATCH”.

This is my code

FILE_OBJECT fo;
OBJECT_HANDLE_INFORMATION ohi;
stat = ObReferenceObjectByHandle(FileHandle, 0L, *IoFileObjectType,
UserMode, (PVOID)&fo, &ohi);
/*Above call succeeds*/

HANDLE h;
stat = ObOpenObjectByPointer((PVOID)&fo, OBJ_FORCE_ACCESS_CHECK |
OBJ_KERNEL_HANDLE , NULL, GENERIC_READ, *IoFileObjectType, KernelMode, &h);

This call fails with STATUS_OBJECT_TYPE_MISMATCH. In the documentation
of ObOpenObjectByPointer, it is mentioned that :-

“If the /Object/ parameter points to a file object (that is, a
FILE_OBJECT structure), *ObOpenObjectByPointer* can only be called after
at least one handle has been created for the file object. Callers can
check the *Flags* member of the FILE_OBJECT structure that the
/Object/ parameter points to. If the FO_HANDLE_CREATED flag is set, this
means that one or more handles have been created for the file object, so
it is safe to call *ObOpenObjectByPointer*.”

In my case, the FO_HANDLE_CREATED is not set.

How can I resolve this issue?

Thanks a lot,
Lloyd

Thank you very much Grigora, Peter, Maxim and Pavel, Now it is working :slight_smile:

Thanks a lot,
Lloyd

On Tue, Oct 21, 2014 at 4:31 PM, Pavel A. wrote:

> > FILE_OBJECT fo;
> > stat = ObReferenceObjectByHandle(FileHandle, 0L, *IoFileObjectType,
> > UserMode, (PVOID)&fo, &ohi);
>
> This should be:
>
> PFILE_OBJECT fo;
> …
> stat = ObOpenObjectByPointer((PVOID)fo, OBJ_FORCE_ACCESS_CHECK |
>
>
> – pa
>
> On 21-Oct-2014 12:33, Lloyd wrote:
>
>> I have tried “ObOpenObjectByPointer with OBJ_KERNEL_HANDLE”, but it
>> fails with “STATUS_OBJECT_TYPE_MISMATCH”.
>>
>> This is my code
>>
>> FILE_OBJECT fo;
>> OBJECT_HANDLE_INFORMATION ohi;
>> stat = ObReferenceObjectByHandle(FileHandle, 0L, *IoFileObjectType,
>> UserMode, (PVOID)&fo, &ohi);
>> /Above call succeeds/
>>
>> HANDLE h;
>> stat = ObOpenObjectByPointer((PVOID)&fo, OBJ_FORCE_ACCESS_CHECK |
>> OBJ_KERNEL_HANDLE , NULL, GENERIC_READ, *IoFileObjectType, KernelMode,
>> &h);
>>
>> This call fails with STATUS_OBJECT_TYPE_MISMATCH. In the documentation
>> of ObOpenObjectByPointer, it is mentioned that :-
>>
>> “If the /Object/ parameter points to a file object (that is, a
>> FILE_OBJECT structure), ObOpenObjectByPointer can only be called after
>> at least one handle has been created for the file object. Callers can
>> check the Flags member of the FILE_OBJECT structure that the
>> /Object/ parameter points to. If the FO_HANDLE_CREATED flag is set, this
>> means that one or more handles have been created for the file object, so
>> it is safe to call ObOpenObjectByPointer.”
>>
>> In my case, the FO_HANDLE_CREATED is not set.
>>
>> How can I resolve this issue?
>>
>> Thanks a lot,
>> Lloyd
>>
>
>
> —
> 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
>

That’s still wrong.

You need to supply the access mask to validate the handle:

stat = ObReferenceObjectByHandle(FileHandle,STANDARD_RIGHTS_READ, *IoFileObjectType,

or STANDARD_RIGHTS_WRITE if you plan to write to the file.

Thank you Grigora. Initially I had written that, in the process of trying
to identify the issue i changed it to “0L” then forgot to change it back.
Thanks for noticing that.

Thanks,
Lloyd

On Tue, Oct 21, 2014 at 7:29 PM, wrote:

> That’s still wrong.
>
> You need to supply the access mask to validate the handle:
>
> stat = ObReferenceObjectByHandle(FileHandle,STANDARD_RIGHTS_READ,
> *IoFileObjectType,
>
> or STANDARD_RIGHTS_WRITE if you plan to write to the file.
>
> —
> 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
>

On 21-Oct-2014 16:59, xxxxx@broadcom.com wrote:

That’s still wrong.
You need to supply the access mask to validate the handle:
stat = ObReferenceObjectByHandle(FileHandle,STANDARD_RIGHTS_READ, *IoFileObjectType,
or STANDARD_RIGHTS_WRITE if you plan to write to the file.

Good catch!
– pa

You should use GENERIC_READ/GENERIC_WRITE here (or a set of specific rights like FILE_READ_DATA etc.)

Certainly not STANDARD_RIGHTS_READ/STANDARD_RIGHTS_WRITE, which are not what they sound like:

// wdm.h
#define STANDARD_RIGHTS_READ (READ_CONTROL)
#define STANDARD_RIGHTS_WRITE (READ_CONTROL)

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@broadcom.com
Sent: Tuesday, October 21, 2014 6:59 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Accessing usermode file handle from kernel

That’s still wrong.

You need to supply the access mask to validate the handle:

stat = ObReferenceObjectByHandle(FileHandle,STANDARD_RIGHTS_READ, *IoFileObjectType,

or STANDARD_RIGHTS_WRITE if you plan to write to the file.