Search code examples
c#reflection.net-assemblyappdomainin-memory

Attach in-memory assembly in custom AppDomain


I have created a sandbox AppDomain:

public AppDomain CreateSandbox()
{
    var setup = new AppDomainSetup { ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase };
    var permissionSet = new PermissionSet(PermissionState.None);
    permissionSet.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.NoFlags));
    permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
    permissionSet.AddPermission(new FileIOPermission(PermissionState.Unrestricted)); // TODO: Restrict IO
    var appDomain = AppDomain.CreateDomain("Sandbox", null, setup, permissionSet);
    return appDomain;
}

I also have an assembly loaded from a byte[] fileData:

var assembly = Assembly.Load(fileData);
var appDomain = CreateSandBox();

How can I load this assembly or the fileData bytes into the appDomain and then use it?


Solution

  • You get your new AppDomain to do it. You have to instantiate a class (that inherits MarshalByRefObject) that will run in the chosen AppDomain and load the assembly for you. This involves .NET remoting. Tell me more in this MSDN article. Though it mentions partially trusted code, great sections still apply.

    It's vitally important to have the class inheriting MarshalByRefObject running in the sandbox domain to load the assembly in case the code is not trust-worthy.

    Proxy/Sandbox/Helper Class

    This class acts as an intermediary between your code running in the primary AppDomain (where you created the child domain) and any code that you wish to run in the sandbox/child domain. When using child domains, objects in the primary domain should only talk directly to the proxy class that is running in the child domain for security reasons.

    Communication is by .NET Remoting behind the scenes - not that you would know it. Hence why the class is MarshalByRefObject.

    e.g. (modified MSDN example)

    class Sandboxer:MarshalByRefObject
    {
        public void LoadDodgyAssembly(string path) { ... }
    }
    

    Host Code

    Use this code where you create the child AppDomain. The following code should run in the primary AppDomain:

    var appDomain = CreateSandBox();
    
    var handle = Activator.CreateInstanceFrom(
    appDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,
           typeof(Sandboxer).FullName );
    
    var sandboxer = (Sandboxer) handle.Unwrap();
    sandboxer.LoadDodgyAssembly("pleaserunme.dll");
    

    Return Values

    Be careful of what your proxy class returns to your calling code in the primary AppDomain. If you don't trust the loaded assembly might be best to mark your methods as void otherwise consider using your own trustworthy types marked as [Serializable].

    Tell me more

    There was a magnificent article in MSDN Magazine circa ~2005 entitled "Add-ins: Do you trust it" or something similar but am unable to find.