Filtering processes that connect using a filter communication port

Dear all,

I’m writing a file system minifilter driver and I would like to gatekeep the processes that connect to the filter communication port the driver exposes thanks to FltCreateCommunicationPort.

I checked the documentation of FltCreateCommunicationPort and more closely to the connect/receive message callbacks, but it seems there is no argument containing an identifier of the calling user-mode process.

Could someone advice my on the way to identify the user-mode process that create the communication port and send messages through it please ?

Many thanks !

I guess I’d ask you why you want to know which process connected to the communications port you created?

If the idea is to validate that “the right service” is connecting, you’d probably be better off protecting the communications port with a proper ACL.

Peter

Hello Peter,

Thanks for your answer. I’m developing a driver that aims to provide software enclaves that protects against accounts which would have the right ACLs to communicate with that port. My idea is to sign the binary of the program that communicates with the driver and check the validity of that signature when a communication is established. Imagine delivering a driver and a software that communicates to that driver for an untrusted environment. I would like to prevent one to reuse my driver API for other purposes as well. Verifying the certificate of the calling application is the easiest solution I could find. Nonetheless, if you come up with better ideas, I’m always open to them! :slight_smile:

In all the cases, I would like to know how I can determine the pid of a process that communicates with the driver, so I can retrieve its file path afterwards. Is there any API for that ?

Thanks !

The ConnectNotifyCallback for a minifilter communication port is called in the context of the thread opening a handle to the port, so you can simply obtain the PID or process with PsGetCurrentProcessId or PsGetCurrentProcess. You can use ObOpenObjectByPointer(WithTag) and ZwQueryInformationProcess with ProcessImageFileName, or SeLocateProcessImageName from ntifs.h.

However, even if you were to obtain the PID, the idea of authenticating the calling process by checking the digital signature on the process EXE is of limited value. As I understand it you say a protective ACL on the filter port is unsuitable for your scenario because untrusted code might run under the accounts you would grant access to. If that’s the case, such a malicious process could inject a malicious DLL to the process with your trusted EXE and have code in that DLL access your port. If you start authenticating all loaded DLLs in the calling process, a malicious 2nd process could still remotely allocate executable memory and write code into it which accesses the port. If you start validating the calling process doesn’t have any executable memory regions which are not backed by mapped image files, someone could still run it with the debugging API, break it right after FilterConnectCommunicationPort returns successfully and then duplicate the opened port handle to their own process and do with it as they please.

In other words, since there is no real security boundary between your trusted client process and those callers you are trying to protect against, your goal would be difficult to achieve.

@Koby_Kahane said:
The ConnectNotifyCallback for a minifilter communication port is called in the context of the thread opening a handle to the port, so you can simply obtain the PID or process with PsGetCurrentProcessId or PsGetCurrentProcess. You can use ObOpenObjectByPointer(WithTag) and ZwQueryInformationProcess with ProcessImageFileName, or SeLocateProcessImageName from ntifs.h.

Oh great ! Many thanks for this information !

However, even if you were to obtain the PID, the idea of authenticating the calling process by checking the digital signature on the process EXE is of limited value. As I understand it you say a protective ACL on the filter port is unsuitable for your scenario because untrusted code might run under the accounts you would grant access to. If that’s the case, such a malicious process could inject a malicious DLL to the process with your trusted EXE and have code in that DLL access your port. If you start authenticating all loaded DLLs in the calling process, a malicious 2nd process could still remotely allocate executable memory and write code into it which accesses the port. If you start validating the calling process doesn’t have any executable memory regions which are not backed by mapped image files, someone could still run it with the debugging API, break it right after FilterConnectCommunicationPort returns successfully and then duplicate the opened port handle to their own process and do with it as they please.

To overcome the process injection concern, I have planned to set up object callbacks to strip the handles opened to secured processes/threads. Thus, a process will not be able to get a valid handle to read/write into the user-mode application that communicates with the driver. Furthermore, dependencies that are used by a protected process are turned as read-only to prevent indirect injections, thanks to the file system minifilter driver I aim to develop.

Of course, one can write an hypervisor using the Intel’s VMX instructions to be one layer on top of the kernel in order to extract such information. Every attack vector has its mitigation and its vulnerabilities at the end.