views:

44

answers:

1

Hi,

I'm building a C# application which uses plug-ins. The application must guarantee to the user that plug-ins will not do whatever they want on the user machine, and will have less privileges that the application itself (for example, the application can access its own log files, whereas plug-ins cannot).

I considered three alternatives.

  1. Using System.AddIn. I tried this alternative first, because it seamed much powerful, but I'm really disappointed by the need of modifying the same code seven times in seven different projects each time I want to modify something. Besides, there is a huge number of problems to solve even for a simple Hello World application.

  2. Using System.Activator.CreateInstance(assemblyName, typeName). This is what I used in the preceding version of the application. I can't use it nevermore, because it does not provide a way to restrict permissions.

  3. Using System.Activator.CreateInstance(AppDomain domain, [...]). That's what I'm trying to implement now, but it seems that the only way to do that is to pass through ObjectHandle, which requires serialization for every used class. Although plug-ins contain WPF UserControls, which are not serializable.

So is there a way to create plug-ins containing UserControls or other non serializable objects and to execute those plug-ins with a custom PermissionSet ?

+1  A: 

One thing you could do is set the current AppDomain's policy level to a restricted permission set and add evidence markers to restrict based on strong name or location. The easiest would probably be to require plugins are in a specific directory and give them a restrictive policy.

e.g.

public static void SetRestrictedLevel(Uri path)
{
    PolicyLevel appDomainLevel = PolicyLevel.CreateAppDomainLevel();            

    // Create simple root policy normally with FullTrust
    PolicyStatement fullPolicy = new PolicyStatement(appDomainLevel.GetNamedPermissionSet("FullTrust"));
    UnionCodeGroup policyRoot = new UnionCodeGroup(new AllMembershipCondition(), fullPolicy);

    // Build restrictred permission set 
    PermissionSet permSet = new PermissionSet(PermissionState.None);            
    permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));            
    PolicyStatement permissions = new PolicyStatement(permSet, PolicyStatementAttribute.Exclusive);
    policyRoot.AddChild(new UnionCodeGroup(new UrlMembershipCondition(path.ToString()), permissions));            

    appDomainLevel.RootCodeGroup = policyRoot;

    AppDomain.CurrentDomain.SetAppDomainPolicy(appDomainLevel);
}

static void RunPlugin()
{
    try
    {                
        SetRestrictedLevel(new Uri("file:///c:/plugins/*"));                

        Assembly a = Assembly.LoadFrom("file:///c:/plugins/ClassLibrary.dll");
        Type t = a.GetType("ClassLibrary.TestClass");
        /* Will throw an exception */                
        t.InvokeMember("DoSomething", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static,
                null, null, null);
     }
     catch (Exception e)
     {
         Console.WriteLine(e.ToString());
     }
}

Of course this isn't rigorously tested and CAS policy is notoriously complex so there is always a risk that this code might allow some things to bypass the policy, YMMV :)

tyranid
Thanks. I tried and I think it's just what I need.
MainMa