Fabulous world of VSTO security still puzzles me after living in it for the past 3 years. Isn’t it especially remarkable since I almost memorized the code that builds the security policies for VSTO? So, here goes my little rant to Peter aka the mastermind. Since Peter is a visionary he anticipated the rant almost 2 years ago and would probably just chuckle by now.
I’m the first person to admit that the VSTO policy is very draconian and, quite frankly, a pain in the neck for a lot of developers who just want their code to work. But I’ll also be the first (and loudest) person to defend that design as being the only “right” choice for where we are today. (And if Siew Moi wasn’t on vacation, I’m sure she’d be second in line 🙂 ).
Little overview is needed though. VSTO security is build on top of CLR’s CAS security but with few modifications to it. Especially, VSTO disregards permissions granted to assemblies based on the Zone evidence. For example, I came across a managed EvilWinFormApp.exe that will format my hard drive. The .exe resides on a network location and, if try to run it, the application will either not run at all or will throw an exception when code trying to access my hard drive is about to execute. However, the moment I copy the EvilWinFormApp.exe onto my hard drive the assembly is now in My Computer zone and, hence, is granted FullTrust permission set under the default CAS policy. The moment I run it I can kiss my hard drive goodbye.
With VSTO it is not enough to copy an EvilVSTOCustomization.doc and EvilVSTOCustomization.dll onto the hard drive. If you really want to run this code you would also need to modify the CAS policy on the machine and grant the FullTrust based on the file location or strong name or some evidence other than based on assembly’s zone. Having to configure the CAS policy is usually a good enough barrier to not run the evil code on the end-users machine. The usability aspect is somewhat sacrificed here, but this is irrelevant to this rant.
VSTO IDE compiles the assemblies to the local disk. VSTO designer also places a URL-based code group into the user-level security policy giving FullTrust execution permission to this assembly. Additionally, Execution permission is granted to the entire folder the assembly was compiled into. So, the IDE makes managing the CAS policies transparent. But only on the developer’s machine. When you need to push your VSTO application to the end user you would need to come up with your own solution for setting up the security policy.
Fast forward to my rant. James, a tester in Office was playing with our VSTO Outlook project. For Outlook we generate a manifest on the local disk that points to the assembly that is placed alongside the manifest file. James decided to try out the network deployment scenarios. So, he copied the compiled assembly to a network share, manually updated the manifest to point to the new location of the assembly and added a code group to trust the assembly in the user-level security policy. He did boot Outlook and his addin does not run. So, he is clueless about what exactly went wrong. He contacts VSTO team and since I just happened to be in building 36 I got involved.
First troubleshooting tip. Set the environment variable VSTO_SUPPRESSDISPLAYALERTS to 0. I just use the Advanced tab in the System Properties dialog so the environment variable is machine wide. Now, boot Outlook and here is the exception that has happened. Of course it is a security exception.
Next step – look at the CAS policy. I am bringing up the Command Prompt. Run caspol -all -lg. Here it is – the path to the assembly is given FullTrust. Hmmm, what the heck is wrong? I am staring at my monitor and nothing comes to mind. I had to stare for another 10 minutes before it finally dawned on me: the machine level policy would not grant FullTrust to the assembly. The assembly permission set is calculated as an intersection of permission sets granted on Enterprise, Machine, User and Application level. Application level would grant FullTrust since we have explicitly granted FullTrust in user-level policy. But machine-level policy only grants FullTrust for MyComputer zone and network shares do not fall under MyComputer umbrella.
The easiest way to spot the problem is to run caspol -rsg command that would show permission sets granted to an assembly on every level. But, again, this trick just completely escaped my mind.
If there are a bit frustrated VSTO developers out there – guys, you are not alone.