📜 ⬆️ ⬇️

Compile and securely execute code on the fly

Problem


In your application, you need to execute code that is not known at the compilation of the application. It can be a variety of plugins, extensions, calculations, etc.

Decision


.NET allows you to compile and execute code. Moreover, the code can be executed safely by narrowing the range of resources that the executable code can use.


')

Implementation


To compile, we need CodeDomProvider, with which you can instantiate a compiler instance for any .NET language. Let's go to the code.

  1. private string EvalCode ( string typeName, string methodName, string sourceCode )
  2. {
  3. string output = ":)" ;
  4. var compiler = CodeDomProvider. CreateProvider ( "CSharp" ) ;
  5. var parameters = new CompilerParameters
  6. {
  7. CompilerOptions = "/ t: library" ,
  8. GenerateInMemory = true
  9. IncludeDebugInformation = true
  10. } ;
  11. var results = compiler. CompileAssemblyFromSource ( parameters, sourceCode ) ;
  12. if ( ! results. Errors . HasErrors )
  13. {
  14. var assembly = results. CompiledAssembly ;
  15. var evaluatorType = assembly. GetType ( typeName ) ;
  16. var evaluator = Activator. CreateInstance ( evaluatorType ) ;
  17. output = ( string ) InvokeMethod ( evaluatorType, methodName, evaluator, new object [ ] { output } ) ;
  18. return output ;
  19. }
  20. output = " \ r \ n Houston, we have a problem at compile time!" ;
  21. return results. Errors . Cast < CompilerError > ( ) . Aggregate ( output, ( current, ce ) => current + string . Format ( " \ r \ n line {0}: {1}" , ce. Line , ce. ErrorText ) ) ;
  22. }
  23. [ FileIOPermission ( SecurityAction. Deny , Unrestricted = true ) ]
  24. private object InvokeMethod ( Type evaluatorType, string methodName, object evaluator, object [ ] methodParams )
  25. {
  26. return evaluatorType. InvokeMember ( methodName, System. Reflection . BindingFlags . InvokeMethod , null , evaluator, methodParams ) ;
  27. }


As you can see, there is nothing supernatural. We create a compiler, pass the code into it, we get a DLL. With the help of reflection we launch the necessary method.

Code in action:


Line 27 is interesting. With it, you can limit the rights that the code has (not only dynamic). In .NET there is a mechanism of Code Access Security , through which you can manage the security of executable code.

Security error while attempting to write to disk:


Despite the fact that code execution looks very “harmless”, it is worth remembering that this is a very resource-intensive process. For example, if you execute code in the current application domain (as it was done in the demo), if the application runs for a long time, the memory may simply end (.NET cannot unload assemblies from the domain).

Demo:
DynDllFunWf.zip

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


All Articles