How to restrict copying particular file into device(usb)

Hello,
i want to restrict copying the file from my computer to usb based on file size.
Like: file size greater than 2mb should not be copied into the usb.
In driver Code : I’m able to get file name and file size but not having control over different size of files. It will rather allow or block files.

if((Data->Iopb->MajorFunction == IRP_MJ_READ) || (Data->Iopb->MajorFunction == IRP_MJ_WRITE) || (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION) || (Data->Iopb->MajorFunction == IRP_MJ_CLOSE) || (Data->Iopb->MajorFunction == IRP_MJ_CLEANUP))
{
QueryInfo = FltQueryInformationFile(FltObjects->Instance,
FltObjects->FileObject,
&standardInfo,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation,
NULL );

if (NT_SUCCESS( QueryInfo ))
{
Size2 = standardInfo.EndOfFile.QuadPart;

DbgPrint(“\n%lld standardInfo.EndOfFile.QuadPart “, Size2);
DbgPrint(”\n%d GlobalFileSizeLimit”,GlobalFileSizeLimit);

tempfileStatus = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | MiniSpyData.NameQueryMethod, &tempfileNameInfo);
if (NT_SUCCESS(tempfileStatus))
{
tempfitParseStatus = FltParseFileNameInformation (tempfileNameInfo);
if (NT_SUCCESS(tempfitParseStatus))
{
tempfileExtToUse = &tempfileNameInfo->Extension;
tempfileExtToUse1 = &tempfileNameInfo->Name;
tempfileExtToUse2 = &tempfileNameInfo->ParentDir;
tempfileExtToUse3 = &tempfileNameInfo->Volume;
DbgPrint("\n%wZ tempfileNameInfo->Extension “, tempfileExtToUse);
DbgPrint(”\n%wZ tempfileNameInfo->Name “, tempfileExtToUse1);
DbgPrint(”\n%wZ tempfileNameInfo->ParentDir ", tempfileExtToUse2);

RtlInitAnsiString(&tempSlash, “\”);
RtlAnsiStringToUnicodeString(&CopySlash,&tempSlash,TRUE);
if(RtlCompareUnicodeString( &CopySlash, tempfileExtToUse2, FALSE) != 0)
{
DbgPrint(“\n Directory name not equal”);
if(RtlCompareUnicodeString( tempfileExtToUse3, tempfileExtToUse1, FALSE) != 0)
{
DbgPrint(“\nInside Comparing FileName and volume “);
if(Size2 >= (LONGLONG)GlobalFileSizeLimit)
{
if (tempfileNameInfo != NULL)
{
FltReleaseFileNameInformation(tempfileNameInfo);
}
DbgPrint(”\n File Size is More”);
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
return FLT_PREOP_COMPLETE;
}
else
{
if (tempfileNameInfo != NULL)
{
FltReleaseFileNameInformation(tempfileNameInfo);
}
DbgPrint(“\n File Size is Less”);
Data->IoStatus.Status = STATUS_SUCCESS;
Data->IoStatus.Information = 0;
}
}
}
else
{
DbgPrint(“\n Driectory is SLASH”);
Data->IoStatus.Status = STATUS_SUCCESS;
Data->IoStatus.Information = 0;
}
}
}
else
{
DbgPrint(“\n FltGetFileNameInformation Not present”);
Data->IoStatus.Status = STATUS_SUCCESS;
Data->IoStatus.Information = 0;
}
}
}

Actual Code :

if((Data->Iopb->MajorFunction == IRP_MJ_READ) || (Data->Iopb->MajorFunction == IRP_MJ_WRITE) || (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION) || (Data->Iopb->MajorFunction == IRP_MJ_CLOSE) || (Data->Iopb->MajorFunction == IRP_MJ_CLEANUP))
{
QueryInfo = FltQueryInformationFile(FltObjects->Instance,
FltObjects->FileObject,
&standardInfo,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation,
NULL );

if (NT_SUCCESS( QueryInfo ))
{
Size2 = standardInfo.EndOfFile.QuadPart;

DbgPrint(“\n%lld standardInfo.EndOfFile.QuadPart “, Size2);
DbgPrint(”\n%d GlobalFileSizeLimit”,GlobalFileSizeLimit);

tempfileStatus = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | MiniSpyData.NameQueryMethod, &tempfileNameInfo);
if (NT_SUCCESS(tempfileStatus))
{
tempfitParseStatus = FltParseFileNameInformation (tempfileNameInfo);
if (NT_SUCCESS(tempfitParseStatus))
{
tempfileExtToUse = &tempfileNameInfo->Extension;
tempfileExtToUse1 = &tempfileNameInfo->Name;
tempfileExtToUse2 = &tempfileNameInfo->ParentDir;
DbgPrint(“\n%wZ tempfileNameInfo->Extension “, tempfileExtToUse);
DbgPrint(”\n%wZ tempfileNameInfo->Name “, tempfileExtToUse1);
DbgPrint(”\n%wZ tempfileNameInfo->ParentDir “, tempfileExtToUse2);
if (tempfileExtToUse->Length != 0)
{
DbgPrint(”\n%wZ Inside FileExt is “, tempfileExtToUse);
if(Size2 >= (LONGLONG)GlobalFileSizeLimit)
{
if (tempfileNameInfo != NULL)
{
FltReleaseFileNameInformation(tempfileNameInfo);
}
DbgPrint(”\n File Size is More”);
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;
return FLT_PREOP_COMPLETE;
}
else
{
if (tempfileNameInfo != NULL)
{
FltReleaseFileNameInformation(tempfileNameInfo);
}
DbgPrint(“\n File Size is Less”);
Data->IoStatus.Status = STATUS_SUCCESS;
Data->IoStatus.Information = 0;
}
}
}
}
else
{
DbgPrint(“\n FltGetFileNameInformation Not present”);
Data->IoStatus.Status = STATUS_SUCCESS;
Data->IoStatus.Information = 0;
}
}
}

Depending on how the file is created on the USB drive, your solution
could have issues. What if the file is copied using extending writes?
The file size is never set up front so you won’t know it has exceeded
your global max limit until that write which surpasses that value is
processed.

You could try to filter the set_file_info request and if the EOF/alloc
size is set beyond your limit, deny it. Or you could monitor the writes
going through and check for writes beyond your limit, etc. Using these,
or a combination of these as well as others (create file with a size
specified, etc), you may be able to prevent data being written beyond
your limit. But you would also need cleanup code in your driver that
could delete the file after it exceeds the size? Or maybe you don’t care
about that?

In the end, this type of solution is going to be filled with little edge
cases and scenarios where either the recognition or cleanup is going to
be ugly.

Pete


Kernel Drivers
Windows File System and Device Driver Consulting
www.KernelDrivers.com http:</http:>
866.263.9295

------ Original Message ------
From: xxxxx@gmail.com
To: “Windows File Systems Devs Interest List”
Sent: 8/3/2015 3:14:08 AM
Subject: [ntfsd] How to restrict copying particular file into
device(usb)

>Hello,
> i want to restrict copying the file from my computer to usb based
>on file size.
>Like: file size greater than 2mb should not be copied into the usb.
>In driver Code : I’m able to get file name and file size but not having
>control over different size of files. It will rather allow or block
>files.
>
>if((Data->Iopb->MajorFunction == IRP_MJ_READ) ||
>(Data->Iopb->MajorFunction == IRP_MJ_WRITE) ||
>(Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION) ||
>(Data->Iopb->MajorFunction == IRP_MJ_CLOSE) ||
>(Data->Iopb->MajorFunction == IRP_MJ_CLEANUP))
> {
> QueryInfo = FltQueryInformationFile(FltObjects->Instance,
> FltObjects->FileObject,
> &standardInfo,
> sizeof(FILE_STANDARD_INFORMATION),
> FileStandardInformation,
> NULL );
>
> if (NT_SUCCESS( QueryInfo ))
> {
> Size2 = standardInfo.EndOfFile.QuadPart;
>
> DbgPrint(“\n%lld standardInfo.EndOfFile.QuadPart “, Size2);
> DbgPrint(”\n%d GlobalFileSizeLimit”,GlobalFileSizeLimit);
>
> tempfileStatus = FltGetFileNameInformation(Data,
>FLT_FILE_NAME_NORMALIZED | MiniSpyData.NameQueryMethod,
>&tempfileNameInfo);
> if (NT_SUCCESS(tempfileStatus))
> {
> tempfitParseStatus = FltParseFileNameInformation
>(tempfileNameInfo);
> if (NT_SUCCESS(tempfitParseStatus))
> {
> tempfileExtToUse = &tempfileNameInfo->Extension;
> tempfileExtToUse1 = &tempfileNameInfo->Name;
> tempfileExtToUse2 = &tempfileNameInfo->ParentDir;
> tempfileExtToUse3 = &tempfileNameInfo->Volume;
> DbgPrint(“\n%wZ tempfileNameInfo->Extension “, tempfileExtToUse);
> DbgPrint(”\n%wZ tempfileNameInfo->Name “, tempfileExtToUse1);
> DbgPrint(”\n%wZ tempfileNameInfo->ParentDir “,
>tempfileExtToUse2);
>
> RtlInitAnsiString(&tempSlash, “\”);
> RtlAnsiStringToUnicodeString(&CopySlash,&tempSlash,TRUE);
> if(RtlCompareUnicodeString( &CopySlash, tempfileExtToUse2, FALSE)
>!= 0)
> {
> DbgPrint(”\n Directory name not equal”);
> if(RtlCompareUnicodeString( tempfileExtToUse3,
>tempfileExtToUse1, FALSE) != 0)
> {
> DbgPrint(“\nInside Comparing FileName and volume “);
> if(Size2 >= (LONGLONG)GlobalFileSizeLimit)
> {
> if (tempfileNameInfo != NULL)
> {
> FltReleaseFileNameInformation(tempfileNameInfo);
> }
> DbgPrint(”\n File Size is More”);
> Data->IoStatus.Status = STATUS_ACCESS_DENIED;
> Data->IoStatus.Information = 0;
> return FLT_PREOP_COMPLETE;
> }
> else
> {
> if (tempfileNameInfo != NULL)
> {
> FltReleaseFileNameInformation(tempfileNameInfo);
> }
> DbgPrint(“\n File Size is Less”);
> Data->IoStatus.Status = STATUS_SUCCESS;
> Data->IoStatus.Information = 0;
> }
> }
> }
> else
> {
> DbgPrint(“\n Driectory is SLASH”);
> Data->IoStatus.Status = STATUS_SUCCESS;
> Data->IoStatus.Information = 0;
> }
> }
> }
> else
> {
> DbgPrint(“\n FltGetFileNameInformation Not present”);
> Data->IoStatus.Status = STATUS_SUCCESS;
> Data->IoStatus.Information = 0;
> }
> }
> }
>
>—
>NTFSD is sponsored by OSR
>
>OSR is hiring!! Info at http://www.osr.com/careers
>
>For our schedule of debugging and file system 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

You cannot distinguish copies from just writes, period.

What you can do is fail all writes starting above ( 2MB - write size ) with STATUS_DISK_FULL


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

wrote in message news:xxxxx@ntfsd…
> Hello,
> i want to restrict copying the file from my computer to usb based on file size.
> Like: file size greater than 2mb should not be copied into the usb.
> In driver Code : I’m able to get file name and file size but not having control over different size of files. It will rather allow or block files.
>
> if((Data->Iopb->MajorFunction == IRP_MJ_READ) || (Data->Iopb->MajorFunction == IRP_MJ_WRITE) || (Data->Iopb->MajorFunction == IRP_MJ_SET_INFORMATION) || (Data->Iopb->MajorFunction == IRP_MJ_CLOSE) || (Data->Iopb->MajorFunction == IRP_MJ_CLEANUP))
> {
> QueryInfo = FltQueryInformationFile(FltObjects->Instance,
> FltObjects->FileObject,
> &standardInfo,
> sizeof(FILE_STANDARD_INFORMATION),
> FileStandardInformation,
> NULL );
>
> if (NT_SUCCESS( QueryInfo ))
> {
> Size2 = standardInfo.EndOfFile.QuadPart;
>
> DbgPrint(“\n%lld standardInfo.EndOfFile.QuadPart “, Size2);
> DbgPrint(”\n%d GlobalFileSizeLimit”,GlobalFileSizeLimit);
>
> tempfileStatus = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | MiniSpyData.NameQueryMethod, &tempfileNameInfo);
> if (NT_SUCCESS(tempfileStatus))
> {
> tempfitParseStatus = FltParseFileNameInformation (tempfileNameInfo);
> if (NT_SUCCESS(tempfitParseStatus))
> {
> tempfileExtToUse = &tempfileNameInfo->Extension;
> tempfileExtToUse1 = &tempfileNameInfo->Name;
> tempfileExtToUse2 = &tempfileNameInfo->ParentDir;
> tempfileExtToUse3 = &tempfileNameInfo->Volume;
> DbgPrint(“\n%wZ tempfileNameInfo->Extension “, tempfileExtToUse);
> DbgPrint(”\n%wZ tempfileNameInfo->Name “, tempfileExtToUse1);
> DbgPrint(”\n%wZ tempfileNameInfo->ParentDir “, tempfileExtToUse2);
>
> RtlInitAnsiString(&tempSlash, “\”);
> RtlAnsiStringToUnicodeString(&CopySlash,&tempSlash,TRUE);
> if(RtlCompareUnicodeString( &CopySlash, tempfileExtToUse2, FALSE) != 0)
> {
> DbgPrint(”\n Directory name not equal”);
> if(RtlCompareUnicodeString( tempfileExtToUse3, tempfileExtToUse1, FALSE) != 0)
> {
> DbgPrint(“\nInside Comparing FileName and volume “);
> if(Size2 >= (LONGLONG)GlobalFileSizeLimit)
> {
> if (tempfileNameInfo != NULL)
> {
> FltReleaseFileNameInformation(tempfileNameInfo);
> }
> DbgPrint(”\n File Size is More”);
> Data->IoStatus.Status = STATUS_ACCESS_DENIED;
> Data->IoStatus.Information = 0;
> return FLT_PREOP_COMPLETE;
> }
> else
> {
> if (tempfileNameInfo != NULL)
> {
> FltReleaseFileNameInformation(tempfileNameInfo);
> }
> DbgPrint(“\n File Size is Less”);
> Data->IoStatus.Status = STATUS_SUCCESS;
> Data->IoStatus.Information = 0;
> }
> }
> }
> else
> {
> DbgPrint(“\n Driectory is SLASH”);
> Data->IoStatus.Status = STATUS_SUCCESS;
> Data->IoStatus.Information = 0;
> }
> }
> }
> else
> {
> DbgPrint(“\n FltGetFileNameInformation Not present”);
> Data->IoStatus.Status = STATUS_SUCCESS;
> Data->IoStatus.Information = 0;
> }
> }
> }
>

You can do some heuristics to determine if a write is based on a copy.
Obviously it involves a lot of book keeping and will not be 100% (would
fail is data is modified in memory for example) but it can be reliable in
general cases.

On Wed, Aug 5, 2015 at 12:25 AM, Maxim S. Shatskih
wrote:

> You cannot distinguish copies from just writes, period.
>
> What you can do is fail all writes starting above ( 2MB - write size )
> with STATUS_DISK_FULL
>
> –
> Maxim S. Shatskih
> Microsoft MVP on File System And Storage
> xxxxx@storagecraft.com
> http://www.storagecraft.com
>
> wrote in message news:xxxxx@ntfsd…
> > Hello,
> > i want to restrict copying the file from my computer to usb based on
> file size.
> > Like: file size greater than 2mb should not be copied into the usb.
> > In driver Code : I’m able to get file name and file size but not having
> control over different size of files. It will rather allow or block files.
> >
> > if((Data->Iopb->MajorFunction == IRP_MJ_READ) ||
> (Data->Iopb->MajorFunction == IRP_MJ_WRITE) || (Data->Iopb->MajorFunction
> == IRP_MJ_SET_INFORMATION) || (Data->Iopb->MajorFunction == IRP_MJ_CLOSE)
> || (Data->Iopb->MajorFunction == IRP_MJ_CLEANUP))
> > {
> > QueryInfo = FltQueryInformationFile(FltObjects->Instance,
> > FltObjects->FileObject,
> > &standardInfo,
> > sizeof(FILE_STANDARD_INFORMATION),
> > FileStandardInformation,
> > NULL );
> >
> > if (NT_SUCCESS( QueryInfo ))
> > {
> > Size2 = standardInfo.EndOfFile.QuadPart;
> >
> > DbgPrint(“\n%lld standardInfo.EndOfFile.QuadPart “, Size2);
> > DbgPrint(”\n%d GlobalFileSizeLimit”,GlobalFileSizeLimit);
> >
> > tempfileStatus = FltGetFileNameInformation(Data,
> FLT_FILE_NAME_NORMALIZED | MiniSpyData.NameQueryMethod, &tempfileNameInfo);
> > if (NT_SUCCESS(tempfileStatus))
> > {
> > tempfitParseStatus = FltParseFileNameInformation (tempfileNameInfo);
> > if (NT_SUCCESS(tempfitParseStatus))
> > {
> > tempfileExtToUse = &tempfileNameInfo->Extension;
> > tempfileExtToUse1 = &tempfileNameInfo->Name;
> > tempfileExtToUse2 = &tempfileNameInfo->ParentDir;
> > tempfileExtToUse3 = &tempfileNameInfo->Volume;
> > DbgPrint(“\n%wZ tempfileNameInfo->Extension “, tempfileExtToUse);
> > DbgPrint(”\n%wZ tempfileNameInfo->Name “, tempfileExtToUse1);
> > DbgPrint(”\n%wZ tempfileNameInfo->ParentDir “, tempfileExtToUse2);
> >
> > RtlInitAnsiString(&tempSlash, “\”);
> > RtlAnsiStringToUnicodeString(&CopySlash,&tempSlash,TRUE);
> > if(RtlCompareUnicodeString( &CopySlash, tempfileExtToUse2, FALSE) != 0)
> > {
> > DbgPrint(”\n Directory name not equal”);
> > if(RtlCompareUnicodeString( tempfileExtToUse3, tempfileExtToUse1, FALSE)
> != 0)
> > {
> > DbgPrint(“\nInside Comparing FileName and volume “);
> > if(Size2 >= (LONGLONG)GlobalFileSizeLimit)
> > {
> > if (tempfileNameInfo != NULL)
> > {
> > FltReleaseFileNameInformation(tempfileNameInfo);
> > }
> > DbgPrint(”\n File Size is More”);
> > Data->IoStatus.Status = STATUS_ACCESS_DENIED;
> > Data->IoStatus.Information = 0;
> > return FLT_PREOP_COMPLETE;
> > }
> > else
> > {
> > if (tempfileNameInfo != NULL)
> > {
> > FltReleaseFileNameInformation(tempfileNameInfo);
> > }
> > DbgPrint(“\n File Size is Less”);
> > Data->IoStatus.Status = STATUS_SUCCESS;
> > Data->IoStatus.Information = 0;
> > }
> > }
> > }
> > else
> > {
> > DbgPrint(“\n Driectory is SLASH”);
> > Data->IoStatus.Status = STATUS_SUCCESS;
> > Data->IoStatus.Information = 0;
> > }
> > }
> > }
> > else
> > {
> > DbgPrint(“\n FltGetFileNameInformation Not present”);
> > Data->IoStatus.Status = STATUS_SUCCESS;
> > Data->IoStatus.Information = 0;
> > }
> > }
> > }
> >
>
> —
> NTFSD is sponsored by OSR
>
> OSR is hiring!! Info at http://www.osr.com/careers
>
> For our schedule of debugging and file system 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
>