The XenApp Application Streaming system uses a File System Filter Driver (FSFD) to implement file system isolation. I have previously described the isolation layers and how they present a different image of the system to each sandboxed application. This post describes where in the system that the file system filtering occurs and points out places where things can get “interesting” when having a system with multiple filters, all competing to handle the file system operations.
GEEK SPEEK is turned on for this post
File system 101 – in two paragraphs…
Before considering filtering, first consider the world without filtering. What happens when my application tries to open “letter to mom.doc”. The answer is that your application issues a command to Windows to ask it to open the file. This almost always starts with the CreateFile() Win32 API. It travels from “high level” Windows to “details level” Windows where it lands in the Windows NT I/O Manager. The I/O manager looks around its registered “File Systems” and finds one who is willing to take on the work of satisfying this file operation and “sends it down”. Eventually, the file system will respond “done” and the I/O manager returns to the application.
The file system (think NTFS or FAT32), would like to move things to and from disk, but it doesn’t really know how. Instead, the file system does it’s stuff to convert the high level concept of a file to “blocks” of same sized binary data that it will ask other device drivers to actually move to/from permanent storage (call it a DISK DRIVE). The DISK device driver doesn’t actually know what it is storing, but it absolutely assures the file system that if it is asked to store 512 or 256 bytes of data at location 123456, when the file system later asks for the data at 123456, it will get back the same data that it put there last week. It is the file systems responsibility to convert high level concepts like a “file” into low level concepts like “blocks of data” that can be stored.
Most of the above describes OPERATING SYSTEM components. To implement “isolation”, you have to interfere with what the operation system really wants to accomplish and that’s where filter drivers come in.
Here’s a graphic.
Ponder for a moment the opening of any file. It travels from the I/O Manager, through a number of file system filters, into the file system and eventually on to the disk device driver. To implement isolation, we are one of the file system filter drivers and that pus us “above” the file system. Notice that the filter drivers “below” the file system are called are not file system filters, they are “block” filters. For application isolation systems, we focus on file system filtering.
You will hear the term “IRP”. Not to get too deep, but an IRP is the I/O managers definition of an I/O operation – it stands for “Input/Output Request Packet”. The I/O manager sends IRPs down and filter drivers and file systems do stuff to satisfy the commanded operation. To do application isolation, the filter driver “changes” the IRP along the way so that operations intended for one location actually effect another. I have commented before that there is no “magic” in application isolation. Smoke and mirrors however do exist and for isolated file operations, the smoke and mirrors redirection is done in the file system filter driver.
Where the world gets interesting
Everybody wants to be on top! The “highest” filter is the one that sees the I/O operation first. In principle, if you’re higher up the stack, you can satisfy the I/O operation without the lower level filter drivers ever being informed that there was an IRP on the way and nothing those other guys do will interfere with you, well at least not until it recurses, but stick with me on the concept – If you get to see it first, you “win” compared to the other filters.
Who should win?
Put your programmer hat on… The answer is that it isn’t necessarily you. The right answer can become so complicated that it becomes hard to contemplate. Here is a link to the MSDN documentation.
Priceless stuff. What it comes down to is that when installing, a filter driver can ask the system to load it at a particular “level” or “altitude” in the filter stack. The registry item that controls this is called “Group”.
Here’s a snapshot from my notebook for the Citrix FSFD, CTXSBX.sys at the XenApp 5.0 / App Streaming 1.2 level.
Notice that it has requested to be a “FSFilter Content Screener”. This puts it, kind of in the middle of filters. Anti-virus is “higher” and some other filter types are lower. Read the MSDN docs for the whole list, but it is a very complicated puzzle. Anyone who has stayed with this article all the way to here probably already knows that it’s complicated….
As the programmer who owned the device driver for the development of Application Streaming, I had to work out the “right” position in the filter stack. Occasionally, folks inquire to relative positions and we have to look up information like this to know where one companies filters should live in relation to others. There is a bit of “art” in the selection. It is such an interesting thing that Microsoft holds “plug fests” where various filter driver writers can show up and test inter-operation with other vendors, in particular anti-virus.
A final note
Every few years, the model for device drivers changes. The CTXSBX.sys device driver is a “legacy filter driver”. It had to be to be compatible with Windows 2000, which was one of its design requirements. Since then, Microsoft have built the “mini filter” model which is the normal thing for writing filters today. In addition to being cooler because they are “mini”, mini filters also have a more refined system for specifying load order position. I’ll leave that for a MSDN inquiry, but it ultimately comes down to the same question: who’s above me, who’s below me.
This was probably more techno bit-head stuff than anyone wanted to read, but there it is…
Citrix Systems, Fort Lauderdale, FL