[.net] Running untrusted code - Secuirty Attributes

Started by
5 comments, last by zangetsu 17 years, 6 months ago
In a recent thread I was converting a VSA based scripting system to use ICodeCompiler to create an assembly dynamically at run time. (OK, technically since its not interpreted at run time its not script. Its code converted to an assembly, but for purposes of this thread script refers to the code in the assembly created at run time.) I have this working now as close to my original specifications as can be reasonably expected. But I have a new concern. Just so anyone that reads this will understand the context, I have a half complete Virtual world engine. Now to extend the behavior of the system, the server administrator can add code that will be compiled at run time and converted into assembly. This assembly is basically full of event handlers, When conditions are met in the server, then the 'script' code will be invoked to react. Now the code also has the ability to invoke some functions in the server. For example, a script might want to move a player by calling the MoveObject function that is defined in the servers code. In turn this may cause other events to fire in the script. So, My call stack can easily end up jumping back and forth between my code and the script's code. Now Since the code is created from code explicitly written (or more likely copy-pasted) by the person running the system, what level of security is appropriate to apply to the created assembly, and whats a reasonable way to do it? Here is what I am thinking, I have a function that is used to invoke every call to the script assembly. If I use Declarative Security to say that the Invoke function only has permission to Execute. (IE no permission to manage threads, appdomains, IO, etc.) Will that permission cascade into the assembly? When the script's code jumps back up into the main application to do something like move an object, can I assert that the code to handle that object movement has normal default permissions? I imagine that since the script ends up in a separate assembly, it may be possible to set permissions using app domains. The trouble is that I am having trouble finding examples or documentation that really explain all this too me. I've found loads of pages that say you can do all sorts of cool stuff with app domains and security attributes, but lack a good example. I have also found examples that either don't show enough, or show too much without comments. I've been reading MSDN for days now and I still don't get it. (I got really mad when I found a MSDN page that said: "The following code fragment shows declarative syntax for requesting that your code's callers have a custom permission called MyPermission. This permission is a hypothetical custom permission and does not exist in the .NET Framework." That's nice, but where is the list of permissions that are in the Framework? Thanks!
Advertisement
Quote:
Will that permission cascade into the assembly? When the script's code jumps back up into the main application to do something like move an object, can I assert that the code to handle that object movement has normal default permissions?


Yes, it's a stack thing. The security check will be flagged to check the stack. So even when it gets back into your own code, it will walk up the stack, find your script entry point, and see you set the permissions. So it will fail.


Your best bet is probably a separate appdomain for the scripted code.
This is how it's done in the DirectX SDK (for example)

			PermissionSet permissions = new PermissionSet(PermissionState.None);			permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));			AppDomain domain = ...;			PolicyLevel policy = PolicyLevel.CreateAppDomainLevel();			policy.RootCodeGroup.PolicyStatement = new PolicyStatement(permissions);			domain.SetAppDomainPolicy(policy);




Quote:
That's nice, but where is the list of permissions that are in the Framework?

System.Security.Permissions

[wink]
Ok, So I already had some code that was creating the object that runs the script in a seperate domain so All I had to do was add the code that sets the policy on the AppDomain. I've run into a small problem here.

if I apply the policy to the object before its been created, then the create code (via CreateInstanceFromAndUnwrap) fails. As best I can tell from the exception it requires permission {System.Security.PermissionSet}. If I set the policy after creating the object, then the script can do things it shouldn't like access the filesystem.

So I must set the policy before creating the object if I want to secure the AppDomain. Hmm....
Activator.CreateInstance allows you to create an object on a different appdomain to the current domain.
Continuing the experimentation....
It doesn't seem to matter if I use AppDomain.CreateInstanceFromAndUnwrap or Activator.CreateInstance(.....).unwrap() both throw the same exception. So To experiment I tried to create an empty class that inherits MarshalByRefObject. This works just fine. So There is something in the class that I am trying to create an instance of that creates the exception.

So I have commented the contents of the class and started uncommenting one at a time until the exception is thrown. I found that two things will cause the exeception; Creating an instance of CompilerParameters or an instance of VBCodeCompiler. If I change the code to not create these objects until they are needed, the security exception happens at that point.

So Time to experiment some more...
By the way, Thanks for the help RipTorn.
Well I've finally gotten things working to some extent, but it only took me about 15 minutes to think of a hole in the security.

I got the code in the compiled assembly to run, and I even got it to throw a security exception when it tried to access the file system. So that was a huge improvement. What I have found out, is that If I create an unrestricted permission set inside the 'script' and Assert that set, then I can do whatever I want regardless of what permissions were set outside the script. Given this, its clear I need to figure out how to prevent the script code from accessing permissions.

Anyone have any ideas?

Ok, more replies to myself, but I've found the problem. Here is what is happening. I am creating the assembly dynamically at runtime. This new assembly is created in memory and inherits security evidence from my executable. So since my executable is running with full trust, the dynamically created assembly also has this full trust. Because it is now a full trust assembly, it can now use Assert to claim that full trust. To prevent this I have to create the assembly with a different evidence from the main application. Now I have been able to set the evidence to the sany of the various internet zones but this is configurable via the control pannel so I question if this is a good idea, or if I should find some other way of setting evidence. Hopefully once I get to the end of things, I'll be able to write something up explaining all of this so the thread becomes usefull to future readers.

This topic is closed to new replies.

Advertisement