views:

105

answers:

1

I'm trying to create a sandboxed AppDomain for loading extensions/plugins. I have a MarshalByRefObject that in instantiate inside the appdomain to load the dll. I'm getting SecurityExceptions when trying to load the dll and I can't figure out how to get around them while still limiting what the third party code can do. All my projects are .net 4.

The InDomainLoader class is in a fully trusted domain, the method is marked SecuritySafeCritical. From everything I've read, I think this should work.

Here is my Loader class that creates the AppDomain and jumps into it:

public class Loader
{
    public void Load(string dll, string typeName)
    {
        Log.PrintSecurity();

        // Create new AppDomain
        var setup = AppDomain.CurrentDomain.SetupInformation;
        var permissions = new PermissionSet(null);
        permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
        var strongname = typeof(InDomainLoader).Assembly.Evidence.GetHostEvidence<StrongName>();
        var strongname2 = typeof(IPlugin).Assembly.Evidence.GetHostEvidence<StrongName>();
        AppDomain domain = AppDomain.CreateDomain("plugin", null, setup, permissions, strongname, strongname2);

        // Create instance
        var loader = (InDomainLoader)domain.CreateInstanceAndUnwrap(
            typeof (InDomainLoader).Assembly.FullName, typeof (InDomainLoader).FullName);

        // Jump into domain
        loader.Load(dll, typeName);
    }
}

And here's the bootstrap loader that runs in the domain:

public class InDomainLoader : MarshalByRefObject
{
    [SecuritySafeCritical]
    public void Load(string dll, string typeName)
    {
        Log.PrintSecurity();

        var assembly = Assembly.LoadFrom(dll);  // <!-- SecurityException!
        var pluginType = assembly.GetType(typeName);

        var demoRepository = new DemoRepository();
        var plugin = (IPlugin)Activator.CreateInstance(pluginType, demoRepository);
        Console.WriteLine(plugin.Run());
    }
}

Some logging statements tell me that the assembly's IsFullyTrusted is true and the method has both IsSecurityCritical and IsSecuritySafeCritical set to true, IsSecurityTransparent is false.

I zipped up the whole project to http://davidhogue.com/files/PluginLoader.zip in case that makes this easier.

If anyone has any ideas, I'd be very grateful. I seem to be stuck at a dead end here.

+1  A: 

Well for a start you probably shouldn't be marking the function as SecuritySafeCritical as that implies untrusted callers can call you, which you probably don't really want (not that it should be a major issue).

As for your problem the issue is that by default you still don't run with any special permissions, the normal easy way to do the assembly loading is you create your own AppDomainSetup and point it's ApplicationBase at a Plugin directory of some kind (which isn't a bad idea in general), you can then use the normal Assembly.Load("AssemblyName") to load out of the base. However if you must load an arbitrary file then you need to assert FileIOPermission for the plugin dll (full path), i.e.

private Assembly LoadAssemblyFromFile(string file)
{
    FileIOPermission perm = new FileIOPermission(FileIOPermissionAccess.AllAccess, file);
    perm.Assert();

    return Assembly.LoadFile(file);
}
tyranid
Alright, I'll try that. I think it will get me around my current problem. Though, shouldn't my assembly be fully trusted, therefore able to do pretty much anything it wants?
David Hogue
It is fully trusted, just at the point you get the security exception the _thread_ (for any better definition) isn't. The full trust allows you to assert the correct permission, if that function was in a partial trust assembly it wouldn't be allowed to unless it was explicitly in the grant set.
tyranid