data not decrypted correctly in Read completion routine of filter driver

Hi,

I have written a testing-purpose filter driver based on FileMon. It
decrypts/encrypts *.DWG files only when AutoCAD(acad.exe) accesses them.
It doesn’t change file size.

I track the DWG files using FileObj->FsContext. After IRP_MJ_CREATE
succeeds, add it to tracking structure, while after IRP_MJ_CLOSE, decrease
the reference count. Decrypt the data in-place after IRP_MJ_READ and
encrypt the data using my own IRP before IRP_MJ_WRITE is passed down to
lower driver.

But AutoCAD still says “Corrupt file” when it tries to open an DWG
file(This file is already encrypted with a little tool before my driver
starts).

Did I miss sth.? I post the source. Hope gurus can help me out. Thx!

//------------------------------------------------------------------------
//procedure for IRP_MJ_READ
NTSTATUS CheckReadIRP(PDEVICE_OBJECT HookDevice, IN PIRP Irp)
{
PMDL ReadBufferMdl;

currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
nextIrpStack = IoGetNextIrpStackLocation(Irp);

fileObject = currentIrpStack->FileObject;

hookExt = HookDevice->DeviceExtension;

if (! fileObject)
{
goto PassThrough;
}

if(!(hookExt->Hooked) || !ProcessNameOffset)
{
goto PassThrough;
}

if (! IsProcessNameMatched())
{
goto PassThrough;
}

//Check the tracking structure
if (! IsFileObjInTrackList(fileObject) || ! FilterOn)
{
goto PassThrough;
}

ReadBufferMdl = NULL;
if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
&& ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0))
{
if (Irp->MdlAddress)
{
ReadBufferMdl = Irp->MdlAddress;
}
else if (Irp->UserBuffer)
{
ReadBufferMdl = IoAllocateMdl(Irp->UserBuffer,
currentIrpStack->Parameters.Read.Length,
FALSE, FALSE, NULL);
if (ReadBufferMdl)
{
__try
{
MmProbeAndLockPages(ReadBufferMdl, KernelMode, IoModifyAccess);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
IoFreeMdl(ReadBufferMdl);
ReadBufferMdl = NULL;
}
}
}
}

*nextIrpStack = *currentIrpStack;
IoSetCompletionRoutine( Irp, SpecialReadCompletionRoutine,
(PVOID)ReadBufferMdl, TRUE, TRUE, TRUE );
return IoCallDriver( hookExt->FileSystem, Irp );

PassThrough:

*nextIrpStack = *currentIrpStack;
IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, TRUE, TRUE, TRUE
);
return IoCallDriver( hookExt->FileSystem, Irp );

}
//-----------------------------------------------------------------------
//completion procedure for IRP_MJ_READ

NTSTATUS SpecialReadCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN
PIRP Irp,
IN PVOID Context )
{
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION currentIrpStack;
PHOOK_EXTENSION hookExt;
char *Data;
DWORD Len;
PMDL ReadBufferMdl;

if(Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}

if (! NT_SUCCESS(Irp->IoStatus.Status))
{
return Irp->IoStatus.Status;
}

Len = Irp->IoStatus.Information;
if (Len == 0)
{
return Irp->IoStatus.Status;
}

currentIrpStack = IoGetCurrentIrpStackLocation(Irp);

fileObject = currentIrpStack->FileObject;

hookExt = DeviceObject->DeviceExtension;

if ((hookExt->FileSystem->Flags & DO_BUFFERED_IO) &&
(Irp->AssociatedIrp.SystemBuffer))
{
Data = Irp->AssociatedIrp.SystemBuffer;
GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
}
else if ((hookExt->FileSystem->Flags & DO_DIRECT_IO) &&
(Irp->MdlAddress))
{
Data = MmGetSystemAddressForMdl(Irp->MdlAddress);
if (Data)
{
//Data += MmGetMdlByteOffset(Irp->MdlAddress);
GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
}
}
else if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
&& ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0)
//&& (Irp->UserBuffer)
)
{
ReadBufferMdl = (PMDL)Context;
if (ReadBufferMdl)
{
Data = MmGetSystemAddressForMdl(ReadBufferMdl);
if (Data)
{
//Data += MmGetMdlByteOffset(ReadBufferMdl);
GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
}

if (Irp->MdlAddress == NULL)
{
MmUnlockPages(ReadBufferMdl);
IoFreeMdl(ReadBufferMdl);
}
}
}

return Irp->IoStatus.Status;
}

are you encrypting and decrypting for paging io? if you are encrypting and
decrypting normal io, memory mapping will bypass your encryption and
decryption.

Ampsi

----- Original Message -----
From: “zhangbo”
To: “File Systems Developers”
Sent: Wednesday, April 02, 2003 22:22
Subject: [ntfsd] data not decrypted correctly in Read completion routine of
filter driver

Hi,

I have written a testing-purpose filter driver based on FileMon. It
decrypts/encrypts *.DWG files only when AutoCAD(acad.exe) accesses them.
It doesn’t change file size.

I track the DWG files using FileObj->FsContext. After IRP_MJ_CREATE
succeeds, add it to tracking structure, while after IRP_MJ_CLOSE, decrease
the reference count. Decrypt the data in-place after IRP_MJ_READ and
encrypt the data using my own IRP before IRP_MJ_WRITE is passed down to
lower driver.

But AutoCAD still says “Corrupt file” when it tries to open an DWG
file(This file is already encrypted with a little tool before my driver
starts).

Did I miss sth.? I post the source. Hope gurus can help me out. Thx!

//------------------------------------------------------------------------
//procedure for IRP_MJ_READ
NTSTATUS CheckReadIRP(PDEVICE_OBJECT HookDevice, IN PIRP Irp)
{
PMDL ReadBufferMdl;

currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
nextIrpStack = IoGetNextIrpStackLocation(Irp);

fileObject = currentIrpStack->FileObject;

hookExt = HookDevice->DeviceExtension;

if (! fileObject)
{
goto PassThrough;
}

if(!(hookExt->Hooked) || !ProcessNameOffset)
{
goto PassThrough;
}

if (! IsProcessNameMatched())
{
goto PassThrough;
}

//Check the tracking structure
if (! IsFileObjInTrackList(fileObject) || ! FilterOn)
{
goto PassThrough;
}

ReadBufferMdl = NULL;
if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
&& ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0))
{
if (Irp->MdlAddress)
{
ReadBufferMdl = Irp->MdlAddress;
}
else if (Irp->UserBuffer)
{
ReadBufferMdl = IoAllocateMdl(Irp->UserBuffer,
currentIrpStack->Parameters.Read.Length,
FALSE, FALSE, NULL);
if (ReadBufferMdl)
{
__try
{
MmProbeAndLockPages(ReadBufferMdl, KernelMode, IoModifyAccess);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
IoFreeMdl(ReadBufferMdl);
ReadBufferMdl = NULL;
}
}
}
}

*nextIrpStack = *currentIrpStack;
IoSetCompletionRoutine( Irp, SpecialReadCompletionRoutine,
(PVOID)ReadBufferMdl, TRUE, TRUE, TRUE );
return IoCallDriver( hookExt->FileSystem, Irp );

PassThrough:

*nextIrpStack = *currentIrpStack;
IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, TRUE, TRUE, TRUE
);
return IoCallDriver( hookExt->FileSystem, Irp );

}
//-----------------------------------------------------------------------
//completion procedure for IRP_MJ_READ

NTSTATUS SpecialReadCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN
PIRP Irp,
IN PVOID Context )
{
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION currentIrpStack;
PHOOK_EXTENSION hookExt;
char *Data;
DWORD Len;
PMDL ReadBufferMdl;

if(Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}

if (! NT_SUCCESS(Irp->IoStatus.Status))
{
return Irp->IoStatus.Status;
}

Len = Irp->IoStatus.Information;
if (Len == 0)
{
return Irp->IoStatus.Status;
}

currentIrpStack = IoGetCurrentIrpStackLocation(Irp);

fileObject = currentIrpStack->FileObject;

hookExt = DeviceObject->DeviceExtension;

if ((hookExt->FileSystem->Flags & DO_BUFFERED_IO) &&
(Irp->AssociatedIrp.SystemBuffer))
{
Data = Irp->AssociatedIrp.SystemBuffer;
GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
}
else if ((hookExt->FileSystem->Flags & DO_DIRECT_IO) &&
(Irp->MdlAddress))
{
Data = MmGetSystemAddressForMdl(Irp->MdlAddress);
if (Data)
{
//Data += MmGetMdlByteOffset(Irp->MdlAddress);
GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
}
}
else if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
&& ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0)
//&& (Irp->UserBuffer)
)
{
ReadBufferMdl = (PMDL)Context;
if (ReadBufferMdl)
{
Data = MmGetSystemAddressForMdl(ReadBufferMdl);
if (Data)
{
//Data += MmGetMdlByteOffset(ReadBufferMdl);
GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
}

if (Irp->MdlAddress == NULL)
{
MmUnlockPages(ReadBufferMdl);
IoFreeMdl(ReadBufferMdl);
}
}
}

return Irp->IoStatus.Status;
}


You are currently subscribed to ntfsd as: xxxxx@pmail.ntu.edu.sg
To unsubscribe send a blank email to xxxxx@lists.osr.com

There are some details that are not clear in your description:

  • Do you preform encryption/decryption only for NonCached read/write? If you
    perform encryption for both Cached and NonCached IO you may end up
    encrypting/decripting some data twice. You will have also encrypted data in
    cache, so applications that use memory mapped file will see encrypted data.
    You do not filter FastIO that will return data excatly as it is in cache.
    Generally it is good idea to always have plian data in cache and encrypted
    data on disk.
  • What does IsProcessNameMatched() do? PagingIO may come in the context of
    system process, not in the context of application. If you don’t want some
    applications to access data it is better to deny access during create
    instead of failing to perfrom encryption/decryption.

Alexei.

“zhangbo” wrote in message news:xxxxx@ntfsd…
>
> Hi,
>
> I have written a testing-purpose filter driver based on FileMon. It
> decrypts/encrypts *.DWG files only when AutoCAD(acad.exe) accesses them.
> It doesn’t change file size.
>
> I track the DWG files using FileObj->FsContext. After IRP_MJ_CREATE
> succeeds, add it to tracking structure, while after IRP_MJ_CLOSE, decrease
> the reference count. Decrypt the data in-place after IRP_MJ_READ and
> encrypt the data using my own IRP before IRP_MJ_WRITE is passed down to
> lower driver.
>
> But AutoCAD still says “Corrupt file” when it tries to open an DWG
> file(This file is already encrypted with a little tool before my driver
> starts).
>
> Did I miss sth.? I post the source. Hope gurus can help me out. Thx!
>
> //------------------------------------------------------------------------
> //procedure for IRP_MJ_READ
> NTSTATUS CheckReadIRP(PDEVICE_OBJECT HookDevice, IN PIRP Irp)
> {
> PMDL ReadBufferMdl;
>
> currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
> nextIrpStack = IoGetNextIrpStackLocation(Irp);
>
> fileObject = currentIrpStack->FileObject;
>
> hookExt = HookDevice->DeviceExtension;
>
> if (! fileObject)
> {
> goto PassThrough;
> }
>
> if(!(hookExt->Hooked) || !ProcessNameOffset)
> {
> goto PassThrough;
> }
>
> if (! IsProcessNameMatched())
> {
> goto PassThrough;
> }
>
>
> //Check the tracking structure
> if (! IsFileObjInTrackList(fileObject) || ! FilterOn)
> {
> goto PassThrough;
> }
>
> ReadBufferMdl = NULL;
> if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
> && ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0))
> {
> if (Irp->MdlAddress)
> {
> ReadBufferMdl = Irp->MdlAddress;
> }
> else if (Irp->UserBuffer)
> {
> ReadBufferMdl = IoAllocateMdl(Irp->UserBuffer,
> currentIrpStack->Parameters.Read.Length,
> FALSE, FALSE, NULL);
> if (ReadBufferMdl)
> {
> __try
> {
> MmProbeAndLockPages(ReadBufferMdl, KernelMode, IoModifyAccess);
> }
>__except(EXCEPTION_EXECUTE_HANDLER)
> {
> IoFreeMdl(ReadBufferMdl);
> ReadBufferMdl = NULL;
> }
> }
> }
> }
>
> *nextIrpStack = *currentIrpStack;
> IoSetCompletionRoutine( Irp, SpecialReadCompletionRoutine,
> (PVOID)ReadBufferMdl, TRUE, TRUE, TRUE );
> return IoCallDriver( hookExt->FileSystem, Irp );
>
> PassThrough:
>
> *nextIrpStack = *currentIrpStack;
> IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, TRUE, TRUE, TRUE
> );
> return IoCallDriver( hookExt->FileSystem, Irp );
>
> }
> //-----------------------------------------------------------------------
> //completion procedure for IRP_MJ_READ
>
> NTSTATUS SpecialReadCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN
> PIRP Irp,
> IN PVOID Context )
> {
> PFILE_OBJECT fileObject;
> PIO_STACK_LOCATION currentIrpStack;
> PHOOK_EXTENSION hookExt;
> char *Data;
> DWORD Len;
> PMDL ReadBufferMdl;
>
> if(Irp->PendingReturned)
> {
> IoMarkIrpPending(Irp);
> }
>
> if (! NT_SUCCESS(Irp->IoStatus.Status))
> {
> return Irp->IoStatus.Status;
> }
>
> Len = Irp->IoStatus.Information;
> if (Len == 0)
> {
> return Irp->IoStatus.Status;
> }
>
> currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
>
> fileObject = currentIrpStack->FileObject;
>
> hookExt = DeviceObject->DeviceExtension;
>
> if ((hookExt->FileSystem->Flags & DO_BUFFERED_IO) &&
> (Irp->AssociatedIrp.SystemBuffer))
> {
> Data = Irp->AssociatedIrp.SystemBuffer;
> GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
> }
> else if ((hookExt->FileSystem->Flags & DO_DIRECT_IO) &&
> (Irp->MdlAddress))
> {
> Data = MmGetSystemAddressForMdl(Irp->MdlAddress);
> if (Data)
> {
> //Data += MmGetMdlByteOffset(Irp->MdlAddress);
> GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
> }
> }
> else if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
> && ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0)
> //&& (Irp->UserBuffer)
> )
> {
> ReadBufferMdl = (PMDL)Context;
> if (ReadBufferMdl)
> {
> Data = MmGetSystemAddressForMdl(ReadBufferMdl);
> if (Data)
> {
> //Data += MmGetMdlByteOffset(ReadBufferMdl);
> GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
> }
>
> if (Irp->MdlAddress == NULL)
> {
> MmUnlockPages(ReadBufferMdl);
> IoFreeMdl(ReadBufferMdl);
> }
> }
> }
>
> return Irp->IoStatus.Status;
> }
>
>

If I do encrypt/decrypt only at during Noncached/Paging I/O, Is it possible
to return FALSE in fast i/o and deny if it needs to be in regular MJ_READ.
Or Is it going to take it from cache eventhough I deny in regular MJ_READ.

Because in some cases, parent process may have access and child may inherit
those handles and uses that. But child should be prevented.

-Ramaraj

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com]On Behalf Of Alexei Jelvis
Sent: Thursday, April 03, 2003 5:37 PM
To: File Systems Developers
Subject: [ntfsd] Re: data not decrypted correctly in Read completion
routine of filter driver

There are some details that are not clear in your description:

  • Do you preform encryption/decryption only for NonCached read/write? If you
    perform encryption for both Cached and NonCached IO you may end up
    encrypting/decripting some data twice. You will have also encrypted data in
    cache, so applications that use memory mapped file will see encrypted data.
    You do not filter FastIO that will return data excatly as it is in cache.
    Generally it is good idea to always have plian data in cache and encrypted
    data on disk.
  • What does IsProcessNameMatched() do? PagingIO may come in the context of
    system process, not in the context of application. If you don’t want some
    applications to access data it is better to deny access during create
    instead of failing to perfrom encryption/decryption.

Alexei.

“zhangbo” wrote in message news:xxxxx@ntfsd…
>
> Hi,
>
> I have written a testing-purpose filter driver based on FileMon. It
> decrypts/encrypts *.DWG files only when AutoCAD(acad.exe) accesses them.
> It doesn’t change file size.
>
> I track the DWG files using FileObj->FsContext. After IRP_MJ_CREATE
> succeeds, add it to tracking structure, while after IRP_MJ_CLOSE, decrease
> the reference count. Decrypt the data in-place after IRP_MJ_READ and
> encrypt the data using my own IRP before IRP_MJ_WRITE is passed down to
> lower driver.
>
> But AutoCAD still says “Corrupt file” when it tries to open an DWG
> file(This file is already encrypted with a little tool before my driver
> starts).
>
> Did I miss sth.? I post the source. Hope gurus can help me out. Thx!
>
> //------------------------------------------------------------------------
> //procedure for IRP_MJ_READ
> NTSTATUS CheckReadIRP(PDEVICE_OBJECT HookDevice, IN PIRP Irp)
> {
> PMDL ReadBufferMdl;
>
> currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
> nextIrpStack = IoGetNextIrpStackLocation(Irp);
>
> fileObject = currentIrpStack->FileObject;
>
> hookExt = HookDevice->DeviceExtension;
>
> if (! fileObject)
> {
> goto PassThrough;
> }
>
> if(!(hookExt->Hooked) || !ProcessNameOffset)
> {
> goto PassThrough;
> }
>
> if (! IsProcessNameMatched())
> {
> goto PassThrough;
> }
>
>
> //Check the tracking structure
> if (! IsFileObjInTrackList(fileObject) || ! FilterOn)
> {
> goto PassThrough;
> }
>
> ReadBufferMdl = NULL;
> if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
> && ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0))
> {
> if (Irp->MdlAddress)
> {
> ReadBufferMdl = Irp->MdlAddress;
> }
> else if (Irp->UserBuffer)
> {
> ReadBufferMdl = IoAllocateMdl(Irp->UserBuffer,
> currentIrpStack->Parameters.Read.Length,
> FALSE, FALSE, NULL);
> if (ReadBufferMdl)
> {
> __try
> {
> MmProbeAndLockPages(ReadBufferMdl, KernelMode, IoModifyAccess);
> }
>__except(EXCEPTION_EXECUTE_HANDLER)
> {
> IoFreeMdl(ReadBufferMdl);
> ReadBufferMdl = NULL;
> }
> }
> }
> }
>
> *nextIrpStack = *currentIrpStack;
> IoSetCompletionRoutine( Irp, SpecialReadCompletionRoutine,
> (PVOID)ReadBufferMdl, TRUE, TRUE, TRUE );
> return IoCallDriver( hookExt->FileSystem, Irp );
>
> PassThrough:
>
> *nextIrpStack = *currentIrpStack;
> IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, TRUE, TRUE, TRUE
> );
> return IoCallDriver( hookExt->FileSystem, Irp );
>
> }
> //-----------------------------------------------------------------------
> //completion procedure for IRP_MJ_READ
>
> NTSTATUS SpecialReadCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN
> PIRP Irp,
> IN PVOID Context )
> {
> PFILE_OBJECT fileObject;
> PIO_STACK_LOCATION currentIrpStack;
> PHOOK_EXTENSION hookExt;
> char *Data;
> DWORD Len;
> PMDL ReadBufferMdl;
>
> if(Irp->PendingReturned)
> {
> IoMarkIrpPending(Irp);
> }
>
> if (! NT_SUCCESS(Irp->IoStatus.Status))
> {
> return Irp->IoStatus.Status;
> }
>
> Len = Irp->IoStatus.Information;
> if (Len == 0)
> {
> return Irp->IoStatus.Status;
> }
>
> currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
>
> fileObject = currentIrpStack->FileObject;
>
> hookExt = DeviceObject->DeviceExtension;
>
> if ((hookExt->FileSystem->Flags & DO_BUFFERED_IO) &&
> (Irp->AssociatedIrp.SystemBuffer))
> {
> Data = Irp->AssociatedIrp.SystemBuffer;
> GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
> }
> else if ((hookExt->FileSystem->Flags & DO_DIRECT_IO) &&
> (Irp->MdlAddress))
> {
> Data = MmGetSystemAddressForMdl(Irp->MdlAddress);
> if (Data)
> {
> //Data += MmGetMdlByteOffset(Irp->MdlAddress);
> GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
> }
> }
> else if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
> && ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0)
> //&& (Irp->UserBuffer)
> )
> {
> ReadBufferMdl = (PMDL)Context;
> if (ReadBufferMdl)
> {
> Data = MmGetSystemAddressForMdl(ReadBufferMdl);
> if (Data)
> {
> //Data += MmGetMdlByteOffset(ReadBufferMdl);
> GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
> }
>
> if (Irp->MdlAddress == NULL)
> {
> MmUnlockPages(ReadBufferMdl);
> IoFreeMdl(ReadBufferMdl);
> }
> }
> }
>
> return Irp->IoStatus.Status;
> }
>
>


You are currently subscribed to ntfsd as: xxxxx@vormetric.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

> If I do encrypt/decrypt only at during Noncached/Paging I/O, Is it
possible

to return FALSE in fast i/o and deny if it needs to be in regular MJ_READ.
Or Is it going to take it from cache eventhough I deny in regular MJ_READ.

It depends. If application uses ReadFile to get data you will prevent it
from getting the data. But if it uses memory mapped file than it may get the
data without any interaction with the file system (if data already in
cache).

Because in some cases, parent process may have access and child may
inherit
those handles and uses that. But child should be prevented.

Alexei.

Thanks Alexei.
If memory mapped files can be denied only at CREATE path?. Then there is no
way to restrict request based on process. Means there is a security hole -
child process may have that handle and use that.

Ramaraj

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com]On Behalf Of Alexei Jelvis
Sent: Thursday, April 03, 2003 6:23 PM
To: File Systems Developers
Subject: [ntfsd] Re: data not decrypted correctly in Read completion
routine of filter driver

If I do encrypt/decrypt only at during Noncached/Paging I/O, Is it
possible
to return FALSE in fast i/o and deny if it needs to be in regular MJ_READ.
Or Is it going to take it from cache eventhough I deny in regular MJ_READ.

It depends. If application uses ReadFile to get data you will prevent it
from getting the data. But if it uses memory mapped file than it may get the
data without any interaction with the file system (if data already in
cache).

Because in some cases, parent process may have access and child may
inherit
those handles and uses that. But child should be prevented.

Alexei.


You are currently subscribed to ntfsd as: xxxxx@vormetric.com
To unsubscribe send a blank email to xxxxx@lists.osr.com

How can it be a security hole? If you start a child process you are
responsible for ensuring that inherited handles are not a security problem.

----- Original Message -----
From: “Ramaraj Pandian”
To: “File Systems Developers”
Sent: Thursday, April 03, 2003 9:44 PM
Subject: [ntfsd] Re: data not decrypted correctly in Read completion routine
of filter driver

> Thanks Alexei.
> If memory mapped files can be denied only at CREATE path?. Then there is
no
> way to restrict request based on process. Means there is a security hole -
> child process may have that handle and use that.
>
> Ramaraj
>
> -----Original Message-----
> From: xxxxx@lists.osr.com
> [mailto:xxxxx@lists.osr.com]On Behalf Of Alexei Jelvis
> Sent: Thursday, April 03, 2003 6:23 PM
> To: File Systems Developers
> Subject: [ntfsd] Re: data not decrypted correctly in Read completion
> routine of filter driver
>
>
>
> > If I do encrypt/decrypt only at during Noncached/Paging I/O, Is it
> possible
> > to return FALSE in fast i/o and deny if it needs to be in regular
MJ_READ.
> > Or Is it going to take it from cache eventhough I deny in regular
MJ_READ.
>
> It depends. If application uses ReadFile to get data you will prevent it
> from getting the data. But if it uses memory mapped file than it may get
the
> data without any interaction with the file system (if data already in
> cache).
>
> >
> > Because in some cases, parent process may have access and child may
> inherit
> > those handles and uses that. But child should be prevented.
> >
>
> Alexei.
>
>
>
> —
> You are currently subscribed to ntfsd as: xxxxx@vormetric.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>
>
>
> —
> You are currently subscribed to ntfsd as: xxxxx@yoshimuni.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>

> Because in some cases, parent process may have access and child may
inherit

those handles and uses that. But child should be prevented.

The only way how you can prevent the process from accessing the cached
data is - checks in MJ_CREATE path, possibly ACL-based using Sexxx,
but maybe more complex. Just fail CREATE with STATUS_ACCESS_DENIED if
DesiredAccess wants write and the process has no permission from doing
this. IO manager will do the rest.

Remember once more - encryption is not to restrict the particular
processes, you cannot do this. Encryption is only for a case of stolen
media or stolen computer. So, if you have once checked that the user
is genuine - then you are safe to decrypt the data to the cache. Other
users will be blocked by other mechanisms.

You cannot (and, in fact, need not) use encryption to discriminate the
access across running processes. There are simpler ways of doing this.

One more note. Since you always need the cache - at least as a
temporary storage for decrypted data - you must ignore
FILE_NO_INTERMEDIATE_BUFFERING, and handle the FILE_WRITE_THROUGH as a
combination of CcCopyWrite and then CcFlushCache. The cache must
always be activated for a file on any non-attribute-only open.

Max

> If memory mapped files can be denied only at CREATE path?. Then
there is no

way to restrict request based on process.

Correct, no such ways.

Also note that in any major OS - UNIX or NT - security checks are done
at CREATE time. Not at WRITE time as you want. And this is correct,
since the checks must be done at the point where the decision is
taken of granting access or not
, and CREATE is this point.

If the user has no write right - then create fails if it wants write,
and only read-only creates are allowed.
As about trying to write (or to mmap with write access) from the
read-only handle - this is checked and failed, failed very early long
before your FSD.

As about encryption - then you must first check whether this user has
the possibility of decrypting the file properly. If it has not - due
to invalid password or secret key or such - then fail CREATE from this
user. Otherwise, proceed with CREATE and establish the caching, and
then check CREATEs from other users on whether they are authorized to
deal with the file. In the latter case, you can even run in-memory
compare of the second user’s secret key to the first user’s secret
key, which is already checked to be valid.

Means there is a security hole - child process may have that handle
and use that.

No, not a hole :slight_smile: child is running under the same user then the
parent, so, it also has access as the parent had.

Max

At a higher level,

‘NT’ has a security model. Like every general purpose operating system
security model, it assumes that the hardware is safe from tampering. It
assumes that Administrator access is not compromised – that there are
no hostile items running in ring 0. It has a traditional Subject/Object
security model, where the subjects are people identifier by SID (and
authenticated by name/password or smartcard of X.509 or whatever), and
the objects are processes, files, and all the rest of the objects with
ACLs.

Much traffic on this list discusses attempts to graft other security
models onto this one. Many are, in essence, ‘capability’ security
models: this program has privileges, but that program does not. Some
attempt to secure the system in the teeth of compromised hardware or
administrator access.

Clearly, some people have built successful commercial products that
embody some of these efforts, so I can’t dismiss them all as a crock. I
will say that it is clearly extremely difficult to get 100% assurance
for these mechanisms. Not everybody needs 100% assurance. However, there
sure appear to be cases where people are spending vast amounts of time
and effort to go from 80% to 81%.

I at least think it is reasonable to make this appeal: make sure you
understand the basic security model of the system before you set out to
change, improve, or degrade it.

Thx for your kind reply.

sorry I didn’t consider the cached I/O, non-cached I/O and paging I/O in
the previous source code. I have re-read the OSR FAQ. My main goal is to
do encryption/decryption when *.DWG files are read_from/written_to local
disk or network shares.

Now my questions are:

  1. Shall I only deal with non-cached I/O AND paging I/O?
  2. Shall I also do encryption/decryption in FastIO?

The function IsProcessNameMatched() is to match AutoCAD process
name(acad.exe). It should be removed according to your comments.

There are some details that are not clear in your description:

  • Do you preform encryption/decryption only for NonCached read/write? If you
    perform encryption for both Cached and NonCached IO you may end up
    encrypting/decripting some data twice. You will have also encrypted data in
    cache, so applications that use memory mapped file will see encrypted data.
    You do not filter FastIO that will return data excatly as it is in cache.
    Generally it is good idea to always have plian data in cache and encrypted
    data on disk.
  • What does IsProcessNameMatched() do? PagingIO may come in the context of
    system process, not in the context of application. If you don’t want some
    applications to access data it is better to deny access during create
    instead of failing to perfrom encryption/decryption.

Alexei.

“zhangbo” wrote in message news:xxxxx@ntfsd…
> >
> > Hi,
> >
> > I have written a testing-purpose filter driver based on FileMon. It
> > decrypts/encrypts *.DWG files only when AutoCAD(acad.exe) accesses them.
> > It doesn’t change file size.
> >
> > I track the DWG files using FileObj->FsContext. After IRP_MJ_CREATE
> > succeeds, add it to tracking structure, while after IRP_MJ_CLOSE, decrease
> > the reference count. Decrypt the data in-place after IRP_MJ_READ and
> > encrypt the data using my own IRP before IRP_MJ_WRITE is passed down to
> > lower driver.
> >
> > But AutoCAD still says “Corrupt file” when it tries to open an DWG
> > file(This file is already encrypted with a little tool before my driver
> > starts).
> >
> > Did I miss sth.? I post the source. Hope gurus can help me out. Thx!
> >
> > //------------------------------------------------------------------------
> > //procedure for IRP_MJ_READ
> > NTSTATUS CheckReadIRP(PDEVICE_OBJECT HookDevice, IN PIRP Irp)
> > {
> > PMDL ReadBufferMdl;
> >
> > currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
> > nextIrpStack = IoGetNextIrpStackLocation(Irp);
> >
> > fileObject = currentIrpStack->FileObject;
> >
> > hookExt = HookDevice->DeviceExtension;
> >
> > if (! fileObject)
> > {
> > goto PassThrough;
> > }
> >
> > if(!(hookExt->Hooked) || !ProcessNameOffset)
> > {
> > goto PassThrough;
> > }
> >
> > if (! IsProcessNameMatched())
> > {
> > goto PassThrough;
> > }
> >
> >
> > //Check the tracking structure
> > if (! IsFileObjInTrackList(fileObject) || ! FilterOn)
> > {
> > goto PassThrough;
> > }
> >
> > ReadBufferMdl = NULL;
> > if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
> > && ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0))
> > {
> > if (Irp->MdlAddress)
> > {
> > ReadBufferMdl = Irp->MdlAddress;
> > }
> > else if (Irp->UserBuffer)
> > {
> > ReadBufferMdl = IoAllocateMdl(Irp->UserBuffer,
> > currentIrpStack->Parameters.Read.Length,
> > FALSE, FALSE, NULL);
> > if (ReadBufferMdl)
> > {
> > __try
> > {
> > MmProbeAndLockPages(ReadBufferMdl, KernelMode, IoModifyAccess);
> > }
> >__except(EXCEPTION_EXECUTE_HANDLER)
> > {
> > IoFreeMdl(ReadBufferMdl);
> > ReadBufferMdl = NULL;
> > }
> > }
> > }
> > }
> >
> > *nextIrpStack = *currentIrpStack;
> > IoSetCompletionRoutine( Irp, SpecialReadCompletionRoutine,
> > (PVOID)ReadBufferMdl, TRUE, TRUE, TRUE );
> > return IoCallDriver( hookExt->FileSystem, Irp );
> >
> > PassThrough:
> >
> > *nextIrpStack = *currentIrpStack;
> > IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, TRUE, TRUE, TRUE
> > );
> > return IoCallDriver( hookExt->FileSystem, Irp );
> >
> > }
> > //-----------------------------------------------------------------------
> > //completion procedure for IRP_MJ_READ
> >
> > NTSTATUS SpecialReadCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN
> > PIRP Irp,
> > IN PVOID Context )
> > {
> > PFILE_OBJECT fileObject;
> > PIO_STACK_LOCATION currentIrpStack;
> > PHOOK_EXTENSION hookExt;
> > char *Data;
> > DWORD Len;
> > PMDL ReadBufferMdl;
> >
> > if(Irp->PendingReturned)
> > {
> > IoMarkIrpPending(Irp);
> > }
> >
> > if (! NT_SUCCESS(Irp->IoStatus.Status))
> > {
> > return Irp->IoStatus.Status;
> > }
> >
> > Len = Irp->IoStatus.Information;
> > if (Len == 0)
> > {
> > return Irp->IoStatus.Status;
> > }
> >
> > currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
> >
> > fileObject = currentIrpStack->FileObject;
> >
> > hookExt = DeviceObject->DeviceExtension;
> >
> > if ((hookExt->FileSystem->Flags & DO_BUFFERED_IO) &&
> > (Irp->AssociatedIrp.SystemBuffer))
> > {
> > Data = Irp->AssociatedIrp.SystemBuffer;
> > GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
> > }
> > else if ((hookExt->FileSystem->Flags & DO_DIRECT_IO) &&
> > (Irp->MdlAddress))
> > {
> > Data = MmGetSystemAddressForMdl(Irp->MdlAddress);
> > if (Data)
> > {
> > //Data += MmGetMdlByteOffset(Irp->MdlAddress);
> > GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
> > }
> > }
> > else if (((hookExt->FileSystem->Flags & DO_BUFFERED_IO) == 0)
> > && ((hookExt->FileSystem->Flags & DO_DIRECT_IO) == 0)
> > //&& (Irp->UserBuffer)
> > )
> > {
> > ReadBufferMdl = (PMDL)Context;
> > if (ReadBufferMdl)
> > {
> > Data = MmGetSystemAddressForMdl(ReadBufferMdl);
> > if (Data)
> > {
> > //Data += MmGetMdlByteOffset(ReadBufferMdl);
> > GuardDecrypt(currentIrpStack->Parameters.Read.ByteOffset, Data, Len);
> > }
> >
> > if (Irp->MdlAddress == NULL)
> > {
> > MmUnlockPages(ReadBufferMdl);
> > IoFreeMdl(ReadBufferMdl);
> > }
> > }
> > }
> >
> > return Irp->IoStatus.Status;
> > }
> >
> >