Security transparency & sandboxed AppDomains

[This article is still a WIP. Updates may follow.]

Recently I am working on a C# sandbox for C# code, and come across a lot of buggy situations. Here I am just trying to sort them out.

To begin with…

I want to setup up a sandbox that executes C#. By mentioning “sandbox” I mean the hosted C# code must not “break the fourth wall”. For example, it shouldn’t have access to files (other than assembly files) and unmanaged code.

To begin with, I headed to porting.md and found out the following statements

Code Access Security (CAS)

Justification. Sandboxing, i.e. relying on the runtime or the framework to constrain which resources a managed application or library can run is not supported on .NET Framework and therefore is also not supported on .NET Core or .NET Native. We believe that there are simply too many pieces in the .NET Framework and runtime that can result in elevation of privileges. Thus we don’t treat CAS as security boundary anymore. On top of that, it makes the implementation more complicated and often has correctness performance implications for applications that don’t intend to use it.

Replacement. Use operating system provided security boundaries, such as virtualization, containers, or user accounts for running processes with the least set of privileges.

If you click on the “not supported on .NET Framework” link, you will also see a big “Caution” box telling you

We are updating our guidance to reflect that Code Access Security and Security-Transparent Code will not be supported as a security boundary with partially trusted code, especially code of unknown origin.

I am not going to elaborate how in-viable it is to “use virtualization, containers, or user accounts for running processes with the least set of privileges”. I just want do get my work done. So, CAS, I choose you. No possibility for .NET Core. Pity. I want to mention they have already re-introduced AppDomain & BinaryFormatter in .NET Standard/Core 2.0, though current  AppDomain API is still a little bit weak. I also want to mention that I am actually a huge fan of .NET Core and .NET Standard.

So, .NET Framework 4.6.2 and .NET Standard 2.0; that’s my choice.

Starting with AppDomain

I have seldom used AppDomain API, but now I get a chance. Using documentation as reference, I made out an AppDomain with least permissions ever, and used my JSON-RPC library for sandboxed AppDomain to directly talk with sandbox clients. Basically, you need to use the following overload to set up a partially trusted execution environment

While it’s easy to just run some overly simple demo code in the sandbox, it is much difficult to run some real-world code with some dependencies, namely, Newtonsoft.Json and JsonRpc.Standard; the latter is my JSON-RPC library. It is just difficult to get it right. For example, I found out that, if I used JsonRpcException of JsonRpc.Standard in the sandboxed AppDomain, CLR will inevitably throw a TypeLoadException:

Okay… CAS stuff. So I marked my GetObjectData with [SecurityCritical], just as the one in System.Exception. However, the problem is still there. I checked up my code over and over again. Surely it is not caused by the conditional switch?

I googled StackOverflow, and found out I am not alone. However, none of the answers solved my problem.

So… Is my GetObjectData implementation really security-critical? Maybe somehow the method is actually not security-critical at run time. Time for a test. I created the following class, and loaded the assembly into the sandboxed AppDomain.

Then, at run time, evaluate typeof(SecurityCriticalLibrary.MyClass).GetMethod("Method")   in the Watch window, and I have

Guess what? It’s security-transparent. What the…

Published by

CXuesong

Leave a Reply

Your email address will not be published. Required fields are marked *

*