This is the thirteenth in a series of notes about UAC in MSI. Per the earlier caveat, these are just my notes and not an official position from the Windows Installer team. The previous entries
- Architecture Insights
- Common Package Mistakes
My Four Square Diagram
When talking about UAC in MSI, I need to lay the foundation of how the Windows Installer architecture works. Given most programmers haven't worked with the type of technology and architecture underlying the Windows Installer, I start with drawing the the "Saw Tooth" diagram and explaining how credential prompt and permissions) occur in the "saw tooth" workflow that processes a package. With just the workflow diagram, I can relate the story behind the top four UAC in MSI mistakes: AdminUser, InstallUISequence CA, InstallExecuteSequence CA, and NoImpersonate bit. For some customer audiences, the workflow explanation is enough. Some segment of customers are still wondering "why is the Windows Installer architecture this way?"
At this point, I usually go to my whiteboard and draw the "four square" diagram starting with this base diagram:
I usually call this my four square diagram. The term "four square" refers to the name of an elementary school playground game which has a court looks a lot like this diagram. I attribute this as "my" diagram just to distinguish it from the definitive security diagrams Carolyn will draw. This diagram only aspires to be good enough to help customers understand the implications of the decisions they are making. The key difference is that I may make technical mistakes and omissions where Carolyn doesn't.
The introduction to this diagram goes something like the following. On the left hand column here we have the permissions that the user runs in. On the right hand column here we have the elevated permissions a service like Windows Installer needs to be able to access anywhere on the machine. The top row are processes that run at the for a period of the task at hand and then terminate. The bottom row are processes that run for as long as the machine is in operations. The bottom row usually consists of full windows services and client processes that don't want to die such as terminate-and-stay-resident or various run on startup registry hives.
Security Context of the Four Square Diagram
To sharpen the message here with customers, I try to relate this diagram with it's security implications. First I point out that a Black Hat traversing from the left hand column to the right hand column unimpeded is what the Security team calls an Elevation of Privilege attack. Second I point out the opportunity for vulnerability increases for programs in the bottom row as a Black Hat can count on them being running on the machine at any time.
As an installer, we have to be able to make changes anywhere on the system so some portion of the Windows Installer has to run as Local System. Given this, a large amount of work has been invested into making the opportunity to go from the left to the right very specific and highly managed. A result of this security consciousness is that the capacities you may have wanted for your custom action may not be available for security reasons.
Given the heightened security consciousness since the Trustworthy Computing initiative started, there has emerged a camp with the philosophy that says all applications should be per-user and no per-machine applications should be allowed. In my discussions with customers, I do suggest this option however the majority of customers I talk to find the constraints of an entirely per-user installation too restrictive.
Processes in the Four Square Diagram
At this point, customers are usually glad that we're solving this problem for them but still wondering where is the part they need to know. I add the following four boxes to the existing basic four square diagram to represent the relevant processes:
In the upper left hand corner, we have a client side process that usually is responsible for the user interface for the setup program. In the lower right, we have the installer service which is what does the built-in heavy lifting for a package. The remaining two squares in the bottom boxes, represent the main two types of custom action sandboxes. To the left, we have the impersonated custom action sandbox and to the right we have the non-impersonated custom action sandbox.
The important point here is that custom actions need to be run in a sandbox. Given custom actions are foreign code that could try to do anything, we need to isolate ourselves from them to keep them from harming the Windows Installer service. This assists in basic robustness of the service and it also happens to prevent a Denial of Service attack (intentional or not) from crashing the service via a custom action.
In the early history for the development of the Windows Installer (before the original 1.0 release) custom actions were not in a sandbox. The first set of custom actions were written by the Windows Installer team so they were well written and well behaved. The second set of custom actions were not so well written so they started to cause failures in the service. Sandboxing caused a tremendous reduction in the bugs that were assigned to the core team.
To one original team member I asked 'Why wouldn't sandboxing have been part of the original architecture?' to which came the reply 'Custom Actions themselves were not part of the original architecture because we wanted an entirely data driven installer. Over time customers increasingly came to the Windows Installer team with legitimate needs for functionality and we couldn't keep up with the requests. As hard as we worked at an entirely data driven engine, scaling out to the breadth of needs requires custom actions.'
Assuming I had enough whiteboard space, I'll connect the "saw tooth" diagram with the "four square" diagram by pointing out the Violet Region in the "saw tooth" is the top row in the "four square" and the Orange region in the "saw tooth" diagram is the bottom row of the "four square" diagram.
Process Flow in the Four Square Diagram
After adding the four boxes to represent the relevant processes, I draw in the lines of process flow:
To these lines, I add the following explanations
- Black "Start Here" Line: In the upper left, we start from the Start Here line (obviously ;^) that invokes the user interface for the installation in a client process with the users permissions. After doing the needed UI work like picking an install location, feature selection, and costing.
- Green "Install" Line: In the upper right, the client process actually requests an install via this green "Install" line. The service remembers enough of the client to pass back progress and respond to user cancel but otherwise the client process is now out of the loop.
- Black "Isolate" Lines: Inside the service, it performs standard actions and custom actions. Standard Actions run in-process with the service because we built them, test the heck out of them, and therefore trust them. Custom Actions we explicitly don't trust therefore we place them in these out of process sandboxes. You can see control path that creates the custom action sandboxes in the black lines that run out from the bottom of the Windows Installer service process box. As with the client call to the service, this is mostly a one way call with a few exceptions for things like progress.
- Blue "Progress" Lines: In the center of the diagram you can see the blue line that represents the progress from the service to the client. You can see the progress path from the custom actions to the Windows Installer service with the blue lines at the bottom of the diagram.
Can you start to see were the restrictions come from?
At this point, I step away from the whiteboard (frankly a bit out of breath from talking so much ;^) and ask the question: 'can you start to see where the restrictions come from?' If I had drawn the "saw tooth" with any of the top four UAC in MSI mistakes I'd ask: 'does this help you understand why the mitigation I'd mentioned earlier makes sense?' The common respond is: "yeah but I need to think about it a little more".
For me, it's a good day when customers say they'll "think about it" because they usually do work a lot of it out. ;^)