ShareAccess and STATUS_SHARING_VIOLATION

Hello,

This question is related to the thread http://www.osronline.com/showthread.cfm?link=151481 .

My minifilter, much like a scanner, passes the filename of files that it catches in the post-create path to a user-mode application which opens them (using just a filename) and scans its contents. What is hapenning is that, when a file is opened with ShareAccess == 0, the application gets (obviously) a STATUS_SHARING_VIOLATION error (I also get this error from Data->IoStatus.Status in the post-create).

I am able to open those files from the driver (by passing IO_IGNORE_SHARE_ACCESS_CHECK to FltCreateFile), but I would like to find a transparent way for the user-mode application (i.e. by still passing a filename, not a handle) to open the file for reading, while bypassing the share access check. I wouldn’t like to read the contents of the file in the kernel (like the sample “scanner” filter), nor duplicate the file, and give it to the user-mode app… I would prefer a transparent way, i.e., in response to a CreateFile(…, GENERIC_READ, …, SHARE_READ|SHARE_WRITE|SHARE_DELETE, …) from the scanner, the driver would (e.g.) catch (or anticipate) a SHARE_VIOLATION, possibly “fix” the error, and open the file in behalf of the scanner…

Do you see a way to implement this without changing the scanner itself? Do you have any advice for this case?

Thanks,
Regards

Wouldn’t it be more desirable to keep the application from accessing the
file until the scan has completed? I think most anti-virus/spam/rootkit
utilities work. Knowing after it has been opened seems to be like reviewing
your credit report only when you want new credit and finding out you owe
thousands of dollars on credit cards you never applied for or received.

Maybe you should hold onto the open until your application tells you it is
done. You can provide a handle to your application that will allow you to
do the reads etc of the file and since you are in the kernel you can use it
as long as you get a system context handle for it.

wrote in message news:xxxxx@ntfsd…
> Hello,
>
> This question is related to the thread
> http://www.osronline.com/showthread.cfm?link=151481 .
>
> My minifilter, much like a scanner, passes the filename of files that it
> catches in the post-create path to a user-mode application which opens
> them (using just a filename) and scans its contents. What is hapenning is
> that, when a file is opened with ShareAccess == 0, the application gets
> (obviously) a STATUS_SHARING_VIOLATION error (I also get this error from
> Data->IoStatus.Status in the post-create).
>
> I am able to open those files from the driver (by passing
> IO_IGNORE_SHARE_ACCESS_CHECK to FltCreateFile), but I would like to find a
> transparent way for the user-mode application (i.e. by still passing a
> filename, not a handle) to open the file for reading, while bypassing the
> share access check. I wouldn’t like to read the contents of the file in
> the kernel (like the sample “scanner” filter), nor duplicate the file, and
> give it to the user-mode app… I would prefer a transparent way, i.e., in
> response to a CreateFile(…, GENERIC_READ, …,
> SHARE_READ|SHARE_WRITE|SHARE_DELETE, …) from the scanner, the driver
> would (e.g.) catch (or anticipate) a SHARE_VIOLATION, possibly “fix” the
> error, and open the file in behalf of the scanner…
>
> Do you see a way to implement this without changing the scanner itself? Do
> you have any advice for this case?
>
> Thanks,
> Regards
>

Hello David,

Thanks for your reply.

I think that would be a nice alternative would the following be untrue:

  • It is not safe (as far as I know) to know the filename nor deal with contexts, in a safe manner, during the Pre-create path because the file has not be opened yet…
  • After the file has been opened, even if I hold onto the open until my scanner tells me whether I should allow it or cancel the operation with FltCancelFileOpen (which is what I am doing by default), my scanner just fails to scan the file because the file has already reached the Post-op path with ShareAccess == 0, and thus, no other user-mode application is allowed to re-open it.

I am really trying to avoid changing the scanner as much as possible, which receives a filename as input by default, and I would not definitely like to change that, so I tried the following in my post-create:

if (!NT_SUCCESS(Data->IoStatus.Status))
{
if ((Data->Iopb->MajorFunction == IRP_MJ_CREATE) &&
(Data->IoStatus.Status == STATUS_SHARING_VIOLATION) &&
(FLT_IS_IRP_OPERATION(Data)) &&
(!FLT_IS_REISSUED_IO(Data)) &&
(IS_SCANNER()))
{
Data->Iopb->OperationFlags &= ~(UCHAR)SL_FORCE_ACCESS_CHECK;
Data->Iopb->Parameters.Create.Options &= ~(ULONG)IO_FORCE_ACCESS_CHECK;
Data->Iopb->Parameters.Create.Options |= (ULONG)IO_IGNORE_SHARE_ACCESS_CHECK;
FltSetCallbackDataDirty(Data);
FltReissueSynchronousIo(FltObjects->Instance, Data);
}
return FLT_POSTOP_FINISHED_PROCESSING;
}

Actually that block is being executed but it does not change the fact that the scanner is still getting STATUS_SHARING_VIOLATION. I suppose I am doing something very wrong in the previous code.

Any (better) ideas?

Thanks in advance.

Your driver will have to accept, via a control channel, requests to read the
file. The handle is not usable for a program in another process. Also
since you are holding onto the create, the Win32 subsystem will not know the
file is available. Also doing it in the post create may be the best,
however your reading of the file will cause the cancel to not work since
caching will be established. I understand that recent operating systems
don’t have this restriction, but I believe that cancel will cause problems
in the post create. In the pre-create, you could open the file for your
application and allow access to it or just pass the filename and your app
can use NtCreateFile to read it and since you are holding the original
create, there can be no conflict. Win32 may not permit it to work. You
have to understand how CreateFile, NtCreateFile, file system filters, and
file systems work together to get this correct in all cases. You may need
to cache the name when checked and not do it again and again if you get
multiple opens with or without closes between them. You application can do
the caching of names so the impact is less than doing it in non-paged pool
in a driver. Don’t forget all filenames can be 64KB in size. I would not
allocate that size data unless needed, but it is legal. Not handling long
pathnames and ADS is a major bug in any malware protection software. The
application and more easily resolve each part of the name to its long
filename too without all the string work in a driver.

Your test application can use ICAR to test. It should create a pathname
with enough subdirectories to reach the 64KB limit. Don’t forget to hide it
in an ADS too. It can then remove each directory one at a time since it is
a real pain with the OS utilities.

wrote in message news:xxxxx@ntfsd…
> Hello David,
>
> Thanks for your reply.
>
> I think that would be a nice alternative would the following be untrue:
> - It is not safe (as far as I know) to know the filename nor deal with
> contexts, in a safe manner, during the Pre-create path because the file
> has not be opened yet…
> - After the file has been opened, even if I hold onto the open until my
> scanner tells me whether I should allow it or cancel the operation with
> FltCancelFileOpen (which is what I am doing by default), my scanner just
> fails to scan the file because the file has already reached the Post-op
> path with ShareAccess == 0, and thus, no other user-mode application is
> allowed to re-open it.
>
> I am really trying to avoid changing the scanner as much as possible,
> which receives a filename as input by default, and I would not definitely
> like to change that, so I tried the following in my post-create:
>
> if (!NT_SUCCESS(Data->IoStatus.Status))
> {
> if ((Data->Iopb->MajorFunction == IRP_MJ_CREATE) &&
> (Data->IoStatus.Status == STATUS_SHARING_VIOLATION) &&
> (FLT_IS_IRP_OPERATION(Data)) &&
> (!FLT_IS_REISSUED_IO(Data)) &&
> (IS_SCANNER()))
> {
> Data->Iopb->OperationFlags &=
> ~(UCHAR)SL_FORCE_ACCESS_CHECK;
> Data->Iopb->Parameters.Create.Options &=
> ~(ULONG)IO_FORCE_ACCESS_CHECK;
> Data->Iopb->Parameters.Create.Options |=
> (ULONG)IO_IGNORE_SHARE_ACCESS_CHECK;
> FltSetCallbackDataDirty(Data);
> FltReissueSynchronousIo(FltObjects->Instance, Data);
> }
> return FLT_POSTOP_FINISHED_PROCESSING;
> }
>
> …
>
> Actually that block is being executed but it does not change the fact that
> the scanner is still getting STATUS_SHARING_VIOLATION. I suppose I am
> doing something very wrong in the previous code.
>
> Any (better) ideas?
>
> Thanks in advance.
>

Thanks to your previous comment David, I think I found a good way to do what I wanted which is both safe (I guess) and easy to implement.

Although I was doing everything in the post-create path because I can assume many things (can deal with contexts, can trust FltGetFileNameInformation if file does not exist, etc.) now I am able to do successful scan before the file gets locked.
In short, I am calling FltGetFileNameInformation in the pre-create path when ShareAccess == 0, and try a blocking scan on the file. If a file like this is successfully opened (i.e., reaches the post-create without errors), then probably the scan was performed and allowed the pre-create. Of course there would be a small time window where other files could be trying to lock the file, but I am not worried with that special case, and since I just needed the file name to pass to my scanner (and not any contextual information), this works well for my purpose.

Thank you very much!