Running runtime compiled c # script in appdomain sandbox

My application should be scriptable for users in C #, but the user script should work in a restricted AppDomain to prevent accidentally damaging scripts, but I cannot get it to work, and since my understanding of AppDomains is sadly limited, I cannot say why .

Currently, this solution is based on this answer https://stackoverflow.com/a/212618/

This is a model of my situation (everything except Script.cs living in a strongly named assembly). Sorry for the wall of code, I could not condense the problem.

class Program { static void Main(string[] args) { // Compile the script CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp"); CompilerParameters parameters = new CompilerParameters() { GenerateExecutable = false, OutputAssembly = System.IO.Path.GetTempFileName() + ".dll", }; parameters.ReferencedAssemblies.Add(Assembly.GetEntryAssembly().Location); CompilerResults results = codeProvider.CompileAssemblyFromFile(parameters, "Script.cs"); // ... here error checks happen ....// var sandbox = Sandbox.Create(); var script = (IExecutable)sandbox.CreateInstance(results.PathToAssembly, "Script"); if(script != null) script.Execute(); } } public interface IExecutable { void Execute(); } 

Sandbox Class:

 public class Sandbox : MarshalByRefObject { const string BaseDirectory = "Untrusted"; const string DomainName = "Sandbox"; public static Sandbox Create() { var setup = new AppDomainSetup() { ApplicationBase = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BaseDirectory), ApplicationName = DomainName, DisallowBindingRedirects = true, DisallowCodeDownload = true, DisallowPublisherPolicy = true }; var permissions = new PermissionSet(PermissionState.None); permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess)); permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); var domain = AppDomain.CreateDomain(DomainName, null, setup, permissions, typeof(Sandbox).Assembly.Evidence.GetHostEvidence<StrongName>()); return (Sandbox)Activator.CreateInstanceFrom(domain, typeof(Sandbox).Assembly.ManifestModule.FullyQualifiedName, typeof(Sandbox).FullName).Unwrap(); } public object CreateInstance(string assemblyPath, string typeName) { new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, assemblyPath).Assert(); var assembly = Assembly.LoadFile(assemblyPath); CodeAccessPermission.RevertAssert(); Type type = assembly.GetType(typeName); // ****** I get null here if (type == null) return null; return Activator.CreateInstance(type); } } 

Loaded Script:

 using System; public class Script : IExecutable { public void Execute() { Console.WriteLine("Boo"); } } 

In CreateInstance of SandBox I always get null in the marked line. I tried various forms of naming, including reading the type name (or fuly qualified name) from results.CompiledAssembly using reflection. What am I doing wrong here?

+1
source share
1 answer

The first thing I will check is if there are compilation errors (I had several headaches caused by these problems)

The second idea is to allow assemblies. I always add an event handler for AppDomain.CurrentDomain.AssemblyResolve as a security check, where I look for my famous path for missing assemblies. When the assembly not found is the one I just compiled, I add a static link to it and return it.

I usually do the following:

  • Create a new assembly in the compiler file system
  • Download its contents using File.ReadAllBytes
  • Load the dll using Assembly.Load in the AppDomain in which I will use the object
  • Add AppDomain.CurrentDomain.AssemblyResolve event

Just in case (since I use this a lot), I created a small library to do such things

Code and documentation are here: Kendar Expression Builder Although the nuget package is here: Nuget Sharp Template

0
source

Source: https://habr.com/ru/post/1206896/


All Articles