Driver Problems? Questions? Issues?
Put OSR's experience to work for you! Contact us for assistance with:
  • Creating the right design for your requirements
  • Reviewing your existing driver code
  • Analyzing driver reliability/performance issues
  • Custom training mixed with consulting and focused directly on your specific areas of interest/concern.
Check us out. OSR, the Windows driver experts.

OSR Seminars


Go Back   OSR Online Lists > ntfsd
Welcome, Guest
You must login to post to this list
  Message 1 of 15  
26 Jun 18 07:07
IanM
xxxxxx@gmail.com
Join Date: 01 Jun 2017
Posts To This List: 19
Completing a failed Create in post callback

Hi, I have a minifilter driver and I'm experimenting with 'fixing up' a failed IRP_MJ_CREATE in the post callback where certain creates have failed because of permissions (i.e. the file does actually exist). I am using FltCreateFile to create a new file object and cherry-picking FsContext, FsContext2, SectionObjectPointer and PrivateCacheMap out of it: FLT_POSTOP_CALLBACK_STATUS PostCreate(_Inout_ PFLT_CALLBACK_DATA pData, _In_ PCFLT_RELATED_OBJECTS pFltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags) { : PFILE_OBJECT pFileObject; HANDLE hFile; IO_STATUS_BLOCK IoStatusBlock; status = FltCreateFileEx( pFltObjects->Filter, pFltObjects->Instance, &hFile, &pFileObject, GENERIC_READ , &ObjectAttributes, &IoStatusBlock, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, 0, NULL, 0, IO_IGNORE_SHARE_ACCESS_CHECK); if (NT_SUCCESS(status)) { pData->Iopb->TargetFileObject->FsContext = pFileObject->FsContext; pData->Iopb->TargetFileObject->FsContext2 = pFileObject->FsContext2; pData->Iopb->TargetFileObject->SectionObjectPointer = pFileObject->SectionObjectPointer; pData->Iopb->TargetFileObject->PrivateCacheMap = pFileObject->PrivateCacheMap; pData->IoStatus.Status = STATUS_SUCCESS; return FLT_POSTOP_FINISHED_PROCESSING; } : } Superficially this seems to work but my questions are: first, is this an acceptable thing to do and if not, why not and is there an alternative; second, I am currently deliberately leaking pFileObject - how can I manage the lifetime of this object give that I've copied parts of it? Thanks, Ian.
  Message 2 of 15  
26 Jun 18 17:23
Scott Noone
xxxxxx@osr.com
Join Date: 10 Jul 2002
Posts To This List: 1026
List Moderator
Completing a failed Create in post callback

I'm not sure how you solve the lifetime tracking problem in this model. Specifically, FsContext2 is allocated as a *per File Object* value in the file system. You now have two File Objects with the same FsContext2 value. You either need to leak one (very bad) or somehow trick the file system into not crashing when the second one is freed (also very bad). There are lots of options in terms of how to proceed, it just depends on what exactly you're trying to do. Here's a few with some caveats (I don't intend this list or the problems/benefits to be exhaustive): 1. There's a NameChanger WDK sample that statically knows which paths will be redirected. It then does the redirection by replacing the file name in the File Object during PreCreate processing. Doing this in PreCreate isn't problem free (see the sample) but it's possible. Note that this only works if the redirection target is on the same volume (not sure if that matters for you) 2. You could FltReissueSynchronousIo in PostCreate with the new path. This also has the problem of only working if the redirection is on the same volume. You also need to make sure that you implement a Name Provider (amongst other things) because you're hiding the real path of the file from filters above you. 3. You could change the failure status to STATUS_REPARSE and let the I/O Manager deal with re-issuing the I/O request. This is conceptually simpler than the other two because you're not lying to the layers above you about the actual destination of the open (e.g. you do not need to be a Name Provider). It also works if the redirection target is another volume. In all cases, if you need to retroactively create paths that don'texist, be sure you test on NTFS and account for the security descriptor that ends up on the directories you create. Your FltCreateFile call is likely being made as a kernel mode request, which might create a directory that is inaccessible to the application that you're trying to fake out. If you can provide a bit more detail about what you're trying to accomplish we might be able to give more concrete advice. -scott OSR @OSRDrivers
  Message 3 of 15  
27 Jun 18 09:18
IanM
xxxxxx@gmail.com
Join Date: 01 Jun 2017
Posts To This List: 19
Completing a failed Create in post callback

Thanks Scott. What I'm trying to do is to catch failed creates in the post callback and, based on some rules, make the create operation succeed. The idea is to give processes running with limited rights access to certain files according to a set of dynamic rules (which precludes just statically changing the ACLs on the files). The rationale behind using the post-callback is to avoid doing costly rule processing in the pre callback by just handling failures. Doing the processing in the pre callback would also mean I'd have to work out whether the create is going to fail in order to intervene. Would it be possible to modify and reissue the IRP in a way that would allow it to succeed?
  Message 4 of 15  
27 Jun 18 20:59
Scott Noone
xxxxxx@osr.com
Join Date: 10 Jul 2002
Posts To This List: 1026
List Moderator
Completing a failed Create in post callback

Are you trying to bypass discretionary access checking or share access checking? Or both? And, just to be clear, these files/directories *exist*, it?s just a matter of the application not being able to access them for some reason. Correct? Also, presumably this is local only, correct? Sorry to just ask a bunch of questions, but it helps to have a complete picture. -scott OSR @OSRDrivers
  Message 5 of 15  
28 Jun 18 03:47
IanM
xxxxxx@gmail.com
Join Date: 01 Jun 2017
Posts To This List: 19
Completing a failed Create in post callback

Not at all. Sorry if I wasn't clear. Yes to both - I want to bypass the discretionary access checking in favour of my own (or maybe impersonate to achieve the same end). Yes, they're local files which exist. The application has failed to access the file because it doesn't have sufficient rights but on certain occasions I want to allow it.
  Message 6 of 15  
28 Jun 18 21:43
Scott Noone
xxxxxx@osr.com
Join Date: 10 Jul 2002
Posts To This List: 1026
List Moderator
Completing a failed Create in post callback

OK, got it. It seems like this should be simple, but it's more complicated than you might expect given that the system is designed to NOT work this way. Also, solving the discretionary access checking problem and the share access checking problem are orthogonal. Going through these as a mental exercise: One could, in theory, solve the discretionary access checking problem by changing the RequestorMode to KernelMode. However, this isn't supported by Filter Manager (rightfully so, it's a bit cavalier). This also wouldn't do anything for share access checking. Another option might be to change the desired access of the open the way down so that the file system sees very little access (e.g. read attributes) but the I/O Manager above you sees the original access (e.g. read). After open, access checking is mostly handled by the I/O Manager above you, so in theory if you get the bits right the application will be able to use their handle for more than the file system expects. This also probably solves the share access checking problem because we only share access check on read/write/delete access. The down side is that this really only works by way of implementation and not by way of architecture. This is confirmed by the fact that NTFS will fail a limited number of operations if it didn?t see data access on the open. You might be able to solve this purely with impersonation, though that would probably involve changing the AccessState parameter to the create operation. The docs say don?t do this and I?ve never tried. It feels a bit icky to me to go digging in there and changing the SubjectSecurityContext. Even if you got this working it would again be by way of implementation. Probably the best approach is what we refer to as ?shadowing?. This is like Isolation, but you don?t take over the management of the file system data cache. It basically looks a lot like what you?ve already done. For a create that fails, you submit an equivalent FltCreateFile in its place. You then complete the original create request with success. However, YOU need to implement FsContext and FsContext2. As operations arrive at your filter, you note which ones arrive for your FsContext/FsContext2. If the operation is for you, you swap the TargetFileObject and pass it along. This takes a bit more to get going than you might expect. Challenges include: - Performing an equivalent FltCreateFile call to an incoming IRP_MJ_CREATE callback data. The arguments are scattered all over the place so it just sucks if you want the new IRP_MJ_CREATE to look as much like the old one as possible - There are a LOT of operations that require swapping the File Object. Expect a lot of boilerplate code - You need to set up your FsContext as if you're a file system (i.e an FSRTL_ADVANCED_FCB_HEADER). Not super complicated, but just something else to manage The shadow approach is probably more code than you were expecting, but it?s a reasonably well worn path at this point. That?s how I would approach this for a prototype so I could see what kind of problems I encountered. Aside #1: You definitely want to run the IFS Tests with something like this, they?re usually pretty good at finding unexpected interactions with the system. Aside #2: I do feel obligated to note that whatever you come up with will likely also have the effect of bypassing system access checking (i.e. auditing). So, if someone is using the security log to know when someone has successfully accessed a file then they might be unhappy (which is a nice way of saying "screwed"). -scott OSR @OSRDrivers
  Message 7 of 15  
02 Jul 18 13:16
IanM
xxxxxx@gmail.com
Join Date: 01 Jun 2017
Posts To This List: 19
Completing a failed Create in post callback

Thanks Scott, that's really interesting, and very useful. I have quickly tried tweaking the desired access and it seems to work. I will be testing it fully, but do you have any thoughts on which NTFS operations are likely to fail? Also, I (clearly incorrectly) thought that access checking was delegated to the file system. This is definitely not the case then? The shadowing approach looks the best way to go although it's going to take me longer to get a prototype together. Thanks again, Ian
  Message 8 of 15  
02 Jul 18 15:08
Scott Noone
xxxxxx@osr.com
Join Date: 10 Jul 2002
Posts To This List: 1026
List Moderator
Completing a failed Create in post callback

<QUOTE> I will be testing it fully, but do you have any thoughts on which NTFS operations are likely to fail? </QUOTE> IIRC EFS and reparse point related operations. <QUOTE> Also, I (clearly incorrectly) thought that access checking was delegated to the file system. This is definitely not the case then? </QUOTE> Access checking is performed by the file system at time of open. The result is then cached in the HANDLE table and enforced by the I/O Manager on subsequent HANDLE operations (i.e. ReadFile/WriteFile). -scott OSR @OSRDrivers
  Message 9 of 15  
11 Jul 18 10:26
IanM
xxxxxx@gmail.com
Join Date: 01 Jun 2017
Posts To This List: 19
Completing a failed Create in post callback

Right, I've been trying the Shadowing approach. In the post-create callback I create the phony FsContent and FILE_OBJECT plus I set my FsContext into the TargetFileObject and change the IoStatus. In the other callbacks I change the TargetFileObject if the phony FsContext if present. Unfortunately it seems that my phony FsContext is being used in Ntfs functions called by FltpLegacyProcessingAfterPreCallbacksCompleted: : 0b fffff880`06b985a0 fffff880`012eb1c5 nt!KiPageFault+0x422 0c fffff880`06b98730 fffff880`012edb6f Ntfs!NtfsCommonDirectoryControl+0x35 0d fffff880`06b98770 fffff800`02f35d56 Ntfs!NtfsFsdDirectoryControl+0x10f 0e fffff880`06b987e0 fffff880`0115b83f nt!IovCallDriver+0x566 0f fffff880`06b98840 fffff880`0115a6df fltmgr!FltpLegacyProcessingAfterPreCallbacksCompleted+0x24f 10 fffff880`06b988d0 fffff800`02f35d56 fltmgr!FltpDispatch+0xcf 11 fffff880`06b98930 fffff800`02d1b0da nt!IovCallDriver+0x566 12 fffff880`06b98990 fffff800`02acc9d3 nt!NtQueryDirectoryFile+0x1aa : In this example NtfsCommonDirectoryControl is accessing some member at FsContext+78h which is beyond the end of FSRTL_ADVANCED_FCB_HEADER so i think it assumes it has a complete FCB. Ntfs!NtfsCommonDirectoryControl: fffff880`012eb190 48895c2408 mov qword ptr [rsp+8],rbx fffff880`012eb195 4889742410 mov qword ptr [rsp+10h],rsi fffff880`012eb19a 57 push rdi fffff880`012eb19b 4883ec30 sub rsp,30h fffff880`012eb19f 488b82b8000000 mov rax,qword ptr [rdx+0B8h] fffff880`012eb1a6 488bfa mov rdi,rdx fffff880`012eb1a9 488bf1 mov rsi,rcx fffff880`012eb1ac 4c8b4030 mov r8,qword ptr [rax+30h] <- r8 = FileObject fffff880`012eb1b0 4d8b4818 mov r9,qword ptr [r8+18h] <- r9 = fffffa8033a1e950 = my phony FsContent fffff880`012eb1b4 4d85c9 test r9,r9 fffff880`012eb1b7 0f84a1c10600 je Ntfs! ?? ::NNGAKEGL::`string'+0x15beb (fffff880`0135735e) fffff880`012eb1bd 498b5978 mov rbx,qword ptr [r9+78h] <- Page Fault It also happens with other IRPs like IRP_MJ_QUERY_SECURITY. Am I doing something wrong? Should I somehow suppress this legacy processing or maybe construct a more complete FCB?
  Message 10 of 15  
11 Jul 18 11:48
Scott Noone
xxxxxx@osr.com
Join Date: 10 Jul 2002
Posts To This List: 1026
List Moderator
Completing a failed Create in post callback

Your file objects are leaking to the lower file system. You need to handle every possible IRP_MJ_XXX code and make sure you always swap the file objects. If you miss one the lower file system will crash. Are you handling IRP_MJ_DIRECTORY_CONTROL? -scott OSR @OSRDrivers
  Message 11 of 15  
11 Jul 18 13:49
IanM
xxxxxx@gmail.com
Join Date: 01 Jun 2017
Posts To This List: 19
Completing a failed Create in post callback

Thanks Scott. Yes, I am handling IRP_MJ_DIRECTORY_CONTROL. Here's the Debug output from the same run. Found [\Device\HarddiskVolume1\Users\Ian] g_pShadowFileObject FFFFFA8033E747F0 Creating FsContext FFFFFA8033A1E950 Setting FsContext FFFFFA8033A1E950 Pre IRP_MJ_FILE_SYSTEM_CONTROL. Replacing FFFFFA80363574E0 with FFFFFA8033E747F0 Pre IRP_MJ_DIRECTORY_CONTROL. Replacing FFFFFA80363574E0 with FFFFFA8033E747F0 *** Fatal System Error: 0x00000024 (0x00000000001904FB,0xFFFFF88006B984F8,0xFFFFF88006B97D60,0xFFFFF880012EB1C5) Break instruction exception - code 80000003 (first chance) A fatal system error has occurred. Debugger entered on first try; Bugcheck callbacks have not been invoked. A fatal system error has occurred. After my pre handler has swapped the TargetFileObject the filter manager is offering the IRP for 'LegacyProcessing' by FltpLegacyProcessingAfterPreCallbacksCompleted after the minifilter callbacks have been processed.
  Message 12 of 15  
11 Jul 18 16:55
Scott Noone
xxxxxx@osr.com
Join Date: 10 Jul 2002
Posts To This List: 1026
List Moderator
Completing a failed Create in post callback

Post your swapping code. Are you calling FltSetCallbackDataDirty? -scott OSR @OSRDrivers
  Message 13 of 15  
12 Jul 18 08:46
IanM
xxxxxx@gmail.com
Join Date: 01 Jun 2017
Posts To This List: 19
Completing a failed Create in post callback

Doh. Of course. No, I wasn't. Thanks, that's got me a lot further. I now have it working although my code for managing the phony FsContent is a bit shonky. For each unique file path I have a single FsContext and use a refcounting mechanism to manage its lifetime, but I was wondering if there's a better way of doing this? I believe the FLT_STREAM_CONTEXT's lifetime is the same as the FCB so could I use that? Or is there some mechanism whereby I can be notified that the FsContext needs to be destroyed? Thanks again.
  Message 14 of 15  
12 Jul 18 14:33
Scott Noone
xxxxxx@osr.com
Join Date: 10 Jul 2002
Posts To This List: 1026
List Moderator
Completing a failed Create in post callback

It's your FCB, so you need to figure out the right time to delete it. A file system would normally use a reference count (see usage of FatDeleteFcb in the fastfat source). However, with shadowing/isolation you can leverage the fact that the lower FCB and the upper (i.e. your) FCB have a matching lifetime. So, put a stream context on the lower file and you can delete the upper FCB when your stream context goes away. -scott OSR @OSRDrivers
  Message 15 of 15  
Yesterday 10:43
IanM
xxxxxx@gmail.com
Join Date: 01 Jun 2017
Posts To This List: 19
Completing a failed Create in post callback

I actually ended up putting a context on the upper file but the lower one makes more sense - I had to make sure my FCB was properly initialised, in particular Flags2 needed FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS set. However, I still have a couple of issues: 1) I think my fake SECTION_OBJECT_POINTERS structure or its contents is finding its way into the cache manager. If I open a file with notepad using this approach I get a crash in CcFlushCache after the final IRP_MJ_CLOSE has been seen. Looking at the disassembly I think that CcFlushCache is referencing a NULL SharedCacheMap. I see no sign of the SECTION_OBJECT_POINTER structure that I allocated for my 'upper' file object though. Should I be doing more than creating an empty SOP: pSectionObjectPointer = ExAllocatePoolWithTag(NonPagedPool, sizeof(SECTION_OBJECT_POINTERS), FSFILTER_TAG); RtlZeroMemory(pSectionObjectPointer, sizeof(SECTION_OBJECT_POINTERS)); pData->Iopb->TargetFileObject->SectionObjectPointer = pSectionObjectPointer; : FltSetCallbackDataDirty(pData); Here's the stack: nt!KiBugCheckDispatch+0x69 nt!KiPageFault+0x448 (TrapFrame @ fffff880`05c4f780) nt!CcFlushCache+0x103 nt!CcWriteBehind+0x1c6 nt!CcWorkerThread+0x1c8 nt!ExpWorkerThread+0x111 nt!PspSystemThreadStartup+0x194 nt!KxStartSystemThread+0x16 2) Also, with procmon in the equation I get a crash: nt!KiPageFault+0x422 Ntfs!NtfsDecodeFileObject+0x48 Ntfs!NtfsCommonQueryInformation+0x98 Ntfs!NtfsFsdDispatchSwitch+0x106 Ntfs!NtfsFsdDispatchWait+0x14 nt!IovCallDriver+0x566 fltmgr!FltpLegacyProcessingAfterPreCallbacksCompleted+0x24f fltmgr!FltPerformSynchronousIo+0x2ca fltmgr!FltpQueryInformationFileFromInstance+0x74 fltmgr!QueryStandardLinkInformationFromInstance+0x4c fltmgr! ?? ::NNGAKEGL::`string'+0x2477 fltmgr!FltpGetFileNameInformation+0x1fb fltmgr!FltGetFileNameInformation+0x187 PROCMON23+0x2a12 fltmgr!FltpPerformPreCallbacks+0x50b fltmgr!FltpPassThrough+0x2f7 fltmgr!FltpDispatch+0xb7 nt!IovCallDriver+0x566 nt!IopSynchronousServiceTail+0xfa nt!NtWriteFile+0x80a nt!KiSystemServiceCopyEnd+0x13 I am handling every IRP so how I don't understand how ntfs has got hold of my 'upper' file object. I notice it's getting file name information. Does my filter driver need to be a name provider? As I've been Googling around these problems I keep finding references to isolation drivers and how long they take to get right. Am I getting sucked into implementing something huge or is the basic shadowing I'm trying to accomplish be more easily achievable?
Posting Rules  
You may not post new threads
You may not post replies
You may not post attachments
You must login to OSR Online AND be a member of the ntfsd list to be able to post.

All times are GMT -5. The time now is 19:27.


Copyright ©2015, OSR Open Systems Resources, Inc.
Based on vBulletin Copyright ©2000 - 2005, Jelsoft Enterprises Ltd.
Modified under license