简体   繁体   中英

Loading Assembly in sandbox Appdomain - SecurityException

I would like to invoke method from runtime created assembly. It is partially trusted code, so I want to create a sandbox application domain for it.

I create the Assembly with Roslyn, the result is a byte[] . I can load it and invoke from it in the default Appdomain , it works fine. The problem is (I guess) with the sandbox.

I used this tutorial .

Creating the sandbox Appdomain :

private AppDomain createAppdomain(string location)
{
     AppDomain currentAppdomain = AppDomain.CurrentDomain;

     // Create the permission set to be granted to the untrusted application
     Evidence ev = new Evidence();
     ev.AddHostEvidence(new Zone(SecurityZone.Internet));
     PermissionSet internetPS = SecurityManager.GetStandardSandbox(ev);
     var platform = Assembly.GetExecutingAssembly();
     internetPS.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, Path.GetDirectoryName(platform.Location)));

     // Sign the assembly that contains the hosting class (named Sandboxer in this example) that calls the untrusted code
     // .NET Framework assemblies such as mscorlib and System.dll do not have to be added to the full-trust list
     // because they are loaded as fully trusted from the global assembly cache.
     StrongName[] fullTrustAssembly = new StrongName[1];
     fullTrustAssembly[0] = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<StrongName>();

     // Initialize the AppDomainSetup parameter of the CreateDomain method
     //  The ApplicationBase property is an important setting,
     // and should be different from the ApplicationBase property for the AppDomain of the hosting application.
     // If the ApplicationBase settings are the same,
     // the partial-trust application can get the hosting application to load (as fully trusted) an exception it defines, thus exploiting it.
     AppDomainSetup adSetup = new AppDomainSetup();
     adSetup.ApplicationBase = Path.GetFullPath(location);


     // Call the CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to create the application domain
     // http://msdn.microsoft.com/en-us/library/ms130766(v=vs.110).aspx
     AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, internetPS, fullTrustAssembly);

     return newDomain;
}

Creating the sandbox (Sandboxer type is MarshalByRefObject ):

string physicalPath = HttpContext.Current.Request.PhysicalApplicationPath + @"App_Data\";
 AppDomain Sandbox = createAppdomain(physicalPath);

// http://msdn.microsoft.com/en-us/library/dd413384(v=vs.110).aspx
ObjectHandle handle = Activator.CreateInstanceFrom(
     Sandbox,
     typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,
     typeof(Sandboxer).FullName,
     true,
     BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance,
     null,
    // byte[] rawAssembly
     new object[] { rawAssembly },
     null,
     null);
Sandboxer newDomainInstance = (Sandboxer)handle.Unwrap();   

string s = newDomainInstance.callMethod();

Loading the Assembly , invoking the method:

private string callMethod()
{   
     // No Exception thrown yet, but some problems with the Evidence:
     // Evidence    'asm.Evidence' threw an exception of type 'System.Security.SecurityException'   System.Security.Policy.Evidence {System.Security.SecurityException}
     //"Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed."
     Assembly asm = Assembly.Load(rawAssembly);

     Type MyClass = asm.GetType(myClassName);

     // In this line I get the Exception:
     // System.Security.SecurityException
     // "Request failed."
     object obj = Activator.CreateInstance(MyClass);

     MethodInfo mi = MyClass.GetMethod(myMethodName);
     mi.Invoke(obj, null);

     // some code

     return s;
}

StackTrace:

"at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)\
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)\r\n   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type) ..."

What did I miss? (Sorry for my English.)

EDIT: Tried to add this line to the class to grant full permission:

[PermissionSet(SecurityAction.Assert, Unrestricted = true)]

After this object obj = Activator.CreateInstance(MyClass); worked fine. I need sandboxing, so this is not a solution.

I run into the same issue, and banged my head for an hour. Because I had the same code running well in another example! So I started to remove things until I found that the only difference was in the way the Assembly was loaded: Assembly.LoadFrom worked fine. Assembly.Load(byte[]) gave me a security exception, always.

The exception indicated my sandboxer DLL as the source of problems, which didn't helped. Because it turned out to be all in a single sentence in the MSDN docs:

The trust level of an assembly that is loaded by using this method is the same as the trust level of the calling assembly. To load an assembly from a byte array with the trust level of the application domain, use the Load(Byte[], Byte[], SecurityContextSource) method overload

Whoops! I suppose that loading an assembly with "full trust", in an appdomain with very restricted permissions, while not in the fully trusted list, made the CLR unhappy. First line executed from the loaded assembly -> bang! (that's why I asserted that the exception was confusing: it mentioned the "wrong" DLL as the exception source)

So I replaced the Load(byte[]) with Load(Byte[], null, SecurityContextSource.CurrentAppDomain) and now it works like for LoadFrom

Your problem is your loaded Sandboxer assembly while fully trusted is being called with an untrusted stack. Therefore you are getting a security exception somewhere in the activation (not 100% sure why based on your code). The solution is exactly as you found, to add the assert to the function. This would allow this function to execute with full trust (the assert will block the stack walk) but the loaded assembly is partially trusted so will still be sandboxed.

If you do this you need to ensure that the sandboxed code cannot interact with the method and therefore could abuse it. You can do this by marking the function SecurityCritical so that only fully trusted code can interact with the function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM