I think I'm stuck with using .net 4.0 new security model. In general, I just want to load 3rd party assemblies into a sandbox. Sounds easy, right? Nevertheless...
I have 2 projects in my solution: CrossAppDomain.exe and UntrustedCode.dll.
In CrossAppdomain I created following base class for all my marshallables:
public abstract class Marshallable : MarshalByRefObject, IDisposable
{
[SecurityCritical]
public override object InitializeLifetimeService()
{
return null;
}
public void Dispose()
{
if (!RemotingServices.IsTransparentProxy(this))
{
RemotingServices.Disconnect(this);
}
}
}
And created base class for objects i will work with
public abstract class BaseClass : Marshallable
{
}
In UntrustedCode.dll I created derrived class
public class UntrustedClass : BaseClass
{
}
To create instance of UntrustedClass i use following factory:
public sealed class Factory
{
public BaseClass Create(string assName, string typeName)
{
var domain = CreateAppDomain();
ObjectHandle handle;
try
{
// This throws SecurityException with informational message "RequestFailed"
handle = domain.CreateInstance(typeof(AppDomainWorker).Assembly.FullName, typeof(AppDomainWorker).FullName);
}
catch (SecurityException)
{
// While this works fine...
handle = Activator.CreateInstanceFrom(domain,
typeof(AppDomainWorker).Assembly.ManifestModule.FullyQualifiedName,
typeof(AppDomainWorker).FullName);
}
var worker = (AppDomainWorker)handle.Unwrap();
worker.LoadAssemblies();
var obj = worker.Create(assName, typeName);
worker.Dispose();
return obj;
}
private AppDomain CreateAppDomain()
{
var name = Guid.NewGuid().ToString();
var permissions = new PermissionSet(PermissionState.None);
permissions.AddPermission(new SecurityPermission(PermissionState.Unrestricted));
permissions.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));
permissions.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
var appSetup = new AppDomainSetup
{
ApplicationName = name,
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
ShadowCopyDirectories = Path.GetFullPath(@"..\..\..\UntrustedCode\bin"),
ShadowCopyFiles = "true"
};
// Since Marshallable.InitializeLifetimeServices is overriden and marked with [SecurityCritical]
// we should add this assembly in full trusted list.
// Otherwise. TypeLoadException is thrown with message "Inheritance security rules violated while overriding member:
// 'CrossAppDomains.Marshallable.InitializeLifetimeService()'. Security accessibility of the overriding method must
// match the security accessibility of the method being overriden.
var sn = typeof (AppDomainWorker).Assembly.Evidence.GetHostEvidence<StrongName>();
var domain = AppDomain.CreateDomain(name, null, appSetup, permissions, sn);
return domain;
}
private sealed class AppDomainWorker : Marshallable
{
public BaseClass Create(string assName, string typeName)
{
var assembly = AppDomain.CurrentDomain.GetAssemblies()
.Single(a => assName.StartsWith(a.GetName().Name));
// Here TypeLoadException is thrown: Inheritance security rules violated by type: 'UntrustedCode.UntrustedClass'.
// Derived types must either match the security accessibility of the base type or be less accessible.
var obj = (BaseClass)Activator.CreateInstanceFrom(assembly.Location, typeName).Unwrap();
Debug.Assert(!RemotingServices.IsTransparentProxy(obj));
return obj;
}
public void LoadAssemblies()
{
var assemblyName = AssemblyName.GetAssemblyName(Path.GetFullPath(@"..\..\..\UntrustedCode\bin\Debug\UntrustedCode.dll"));
Assembly.Load(assemblyName);
}
}
}
And here where problem comes:
In Factory.Create() i successed creating AppDomainWorker class only when I used Activator.CreateInstance from. While more straightforward AppDomain.CreateInstanceAndUnwrap failed. This looks so unsteady, I mean this is either bug or security hole. But okay, the workaround works
In AppDomainWorker.Create() i get TypeLoadException: Inheritance security rules violated by type: 'UntrustedCode.UntrustedClass'. Derived types must either match the security accessibility of the base type or be less accessible. I dont know how to fix it. This is my problem
P.S. I know about [assembly: SecurityRules(SecurityRuleSet.Level1)] , but I'd like to know how to get things working in .net 4.0 security model
Edit: After adding [assembly: AllowPartialTrustCallers] I got a bunk of new problems: I need explicitly mark with [SecuritySafeCritical] all code which creates nlog loggger using LogManager.GetCurrentClassLogger() and then all code that uses the initialized field with logger. It is not acceptable. So maybe there are other ways around?