Search code examples
c#.netsandboxappdomaincode-access-security

Sandbox exception "Derived types must either match the security accessibility of the base type or be less accessible."


I am getting the following error when I trying to enable code access security in a sandboxed app domain.

Inheritance security rules violated by type: 'XXX'. Derived types must either match the security accessibility of the base type or be less accessible.

Here is what I have: Plugin assembly has a class which implements an interface defined in a sdk assembly. Plugin assembly is not signed. Also, the plugin assembly has [assembly: SecurityTransparent] in AssemblyInfo.cs Example:

public Class Bar : AbstractBase
{
// This class implements an abstract method defined in the base class

}

AbstractBase is defined in the SDK binary and it is signed. Also, when I create a domain in the executing assembly, it is marked as Trusted.

[SecuritySafeCritical] public abstract class AbstractBase : MarshalByRefObject, IDisposable { public abstract void BaseMethod();

[SecurityCritical]
    [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
    public override object InitializeLifetimeService()
    {
        var lease = (ILease)base.InitializeLifetimeService();
        if (lease != null && lease.CurrentState == LeaseState.Initial)
        {
            lease.InitialLeaseTime = TimeSpan.FromHours(1);
            lease.SponsorshipTimeout = TimeSpan.FromHours(1);
            lease.RenewOnCallTime = TimeSpan.FromHours(1);
        }

        return lease;
    }

    protected void MethodFoo()
    {
    ...
    }

    public virtual Foo FooItIs{get;set;}   // Foo is a class which is a MarshallByRefObject and is implemented in the executing assembly
}

Here is what I have tried in AssemblyInfo.cs of SDK binary.

[assembly: AllowPartiallyTrustedCallers]
[assembly: SecurityRules(SecurityRuleSet.Level2, SkipVerificationInFullTrust = true)]
//[assembly: SecurityRules(SecurityRuleSet.Level1)]

Finally, there is the executing assembly which creates a domain and applies security restriction. I get the exception when I call CreateInstanceAndUnWrap.

private void CreateAppDomain()
    {
        AppDomainSetup domainSetup = new AppDomainSetup();
        domainSetup.ApplicationName = "Plugins";
        domainSetup.ApplicationBase = Section.Instance.BaseDirectory;
        domainSetup.ConfigurationFile = domainSetup.ApplicationName + ".config";
        PermissionSet domainPermissions = new PermissionSet(PermissionState.None);

        domainPermissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
        domainPermissions.AddPermission(new IsolatedStorageFilePermission(PermissionState.Unrestricted));
        domainPermissions.AddPermission(new FileIOPermission(PermissionState.Unrestricted));

        domainPermissions.AddPermission(new System.Net.WebPermission(PermissionState.Unrestricted));
        domainPermissions.AddPermission(new System.Net.Mail.SmtpPermission(PermissionState.Unrestricted));

        domainPermissions.AddPermission(new System.Configuration.ConfigurationPermission(PermissionState.Unrestricted));
        domainPermissions.AddPermission(new System.Data.SqlClient.SqlClientPermission(PermissionState.Unrestricted));

        StrongName plugins = typeof(AbstractBase).Assembly.Evidence.GetHostEvidence<StrongName>();
        this.appDomain = AppDomain.CreateDomain(domainSetup.ApplicationName, null,
            domainSetup, domainPermissions,
            plugins);
    }

And here is how I create an instance:

action =
                        this.appDomain.CreateInstanceFromAndUnwrap(
                        Path.Combine(pluginProperties.AssemblyBaseDirectory, pluginProperties.AssemblyName),
                        className) as
                        AbstractBase;

I am not sure what it is I am missing or is my architecture wrong in some way for code access security? Any help is appreciated!

Edit: Here is the stack trace. My UT does the exact same thing described above

at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type) at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase) at System.Activator.CreateInstanceFromInternal(String assemblyFile, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo) at System.AppDomain.CreateInstanceFrom(String assemblyFile, String typeName) at System.AppDomain.CreateInstanceFromAndUnwrap(String assemblyName, String typeName) at System.AppDomain.CreateInstanceFromAndUnwrap(String assemblyName, String typeName) at Microsoft.Windows.Infrastructure.MissionControl.Eventing.Agent.Tests.ActionProcessorTests.TestActionExecuted() in ActionProcessorTests.cs: line 196


Solution

  • Well, this is an old post, but I stumbled across it while trying to solve the same problem. The problem is that you've marked the entire AbstractBase class with the SecuritySafeCritical, but the Bar class, because it is unsigned, must be SecurityTransparent. Deriving a SecurityTransparent class from a SecuritySafeCritical class is not allowed.

    The solution is to remove the [SecuritySafeCritical] attribute from the AbstractBase class. Because you've marked the antire assembly as AllowPartiallyTrustedCallers, the AbstractBase class will default to SecurityTransparent, and both AbstractBase and Bar will be Transparent.

    Then, when you need access to SecuritySafeCritical or SecurityCritical functions, you would mark the individual function inside of AbstractBase as SecuritySafeCritical. This will allow those methods to access more restricted classes.