How do I temporary override .NET system security configuration?
I have an application installed on my local disk.
This application runs with FullTrust privileges.
I'm trying to load an assembly giving it FullTrust (same privileges of the loader assembly).
My assembly to load is located on a network share.
I'm actually using this code but I get a security exception:
An exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll and wasn't handled in the appdomain it was thrown from
Additional information: Could not load file or assembly 'Main, Version=2.2.2029.19859, Culture=neutral, PublicKeyToken=2244f6f9e95cedae' or one of its dependencies. Failed to grant minimum permission requests. (Exception from HRESULT: 0x80131417)
(If I configure manually the assembly with "Microsoft .NET Framework Configuration" it works.)
What's wrong in the code?
| | Dim DLLUrlAsString ="file://fileserver/ShareName/Main.dll" Dim adAs AppDomain = AppDomain.CurrentDomain Dim domainPolicyAs PolicyLevel = PolicyLevel.CreateAppDomainLevel() domainPolicy.RootCodeGroup =New UnionCodeGroup(New UrlMembershipCondition(DLLUrl),New PolicyStatement(domainPolicy.GetNamedPermissionSet("FullTrust"))) ad.SetAppDomainPolicy(domainPolicy) ad.SetShadowCopyFiles() Dim anAsNew AssemblyName() an.CodeBase = DLLUrl Dim AssemblyToLoadAsAssembly = ad.Load(an)
|
Please note:
I don't want to permanently change the system security configuration with "System.Security.SecurityManager" or executing "caspol.exe" (I could do this because I'm running with FullTrust) but I want only to "bypass" the default configuration without changing it.)
Thank you all!
[2329 byte] By [
Lino] at [2008-2-25]
Really thank you for your answer but I feel I didn't understood correctly.
If I apply that SecurityPermissionAttribute to the assembly I'm trying to load then I'm skipping the security checks whatever loader attempts to load it...
IE: If my "loader" runs with "Internet" security then it could load/call any method in the loaded assembly skipping any security verification.. And this is very bad...
The logic I want to obtain is very simple: the loaded assembly must be checked
against the loader security settings...
Let's take the real example:
The assembly to load has
| | <Assembly: FileDialogPermission(SecurityAction.RequestMinimum, Unrestricted:=True)> <Assembly: FileIOPermission(SecurityAction.RequestMinimum, Unrestricted:=True)> <Assembly: RegistryPermission(SecurityAction.RequestMinimum, ViewAndModify:="HKEY_LOCAL_MACHINE\Software\Company")> <Assembly: SecurityPermission(SecurityAction.RequestMinimum, Assertion:=True, ControlPrincipal:=True, ControlThread:=True, Execution:=True, SerializationFormatter:=True, UnmanagedCode:=True)> |
The loader doesn't have any security attributes declared but it already has those rights (because it's running as "fulltrust"/administrator from local disk), so the assembly to load should be loaded without exceptions (if loaded from local network or internet or wherever it could be).
If I follow your suggestion maybe I should be able to load the assembly but security goes to flowers.. :)
(I could successfully load the assembly even if the "loader" is launched from "internet")
..or am I wrong?
Thank you very much,
Lino.
- FullTrust? No, your assembly does not have it. Does it have a Strong Name? Does it show in the list when you run caspol -listfulltrust at the command prompt? Just because your loader app is present on your machine does NOT mean that it is full trust. Several things are required.
- You write: The loader doesn't have any security attributes declared ... This makes NO sense -- grab a good 70-306/316 book and read the section on "Assemblies, Configuration and Security"...
- The design scenario you are following makes little sense -- the only scenario that I conceive for using your approach is an attempt to get a user to load malicious code. Any LEGITIMATE distribution would include all of the files in it. Any LEGITIMATE patch would come with an installer. Is your intent to infect someone with a virus or trojan? If not please explain your purpose.
- BEFORE YOU ATTEMPT TO DEFEND, your code snippet raises red flags -- it asks for permissions that should generally be avoided, that are excessive for most legitimate purposes, etc. Your snippet requests unrestricted File IO, registry writes, security control, serialization control and unmanaged code permissions -- this set of permissions is seldom if ever needed, is manifestly unwise to grant to internet-zone code, etc.
stand__sure wrote: |
| FullTrust? No, your assembly does not have it. Does it have a Strong Name? Does it show in the list when you run caspol -listfulltrust at the command prompt? Just because your loader app is present on your machine does NOT mean that it is full trust. Several things are required. |
|
Yes, both the loader and the to-load assemblies have strong names. Yes, the loader has fulltrust declared by the setup. (Actually I know it's too much.. but I don't know how to make it work)
stand__sure wrote: |
| You write: The loader doesn't have any security attributes declared ... This makes NO sense -- grab a good 70-306/316 book and read the section on "Assemblies, Configuration and Security"... |
|
I don't need declarative security on the loader because it's only job is to load the .DLL and launch an "entry point"-like procedure. Then all I/O, user interface, application logic is handled by that dll.
stand__sure wrote: |
| The design scenario you are following makes little sense -- the only scenario that I conceive for using your approach is an attempt to get a user to load malicious code. Any LEGITIMATE distribution would include all of the files in it. Any LEGITIMATE patch would come with an installer. Is your intent to infect someone with a virus or trojan? If not please explain your purpose. |
|
It is simple: One network. One program to run on different machines. One little and fast installation (only loader + setup reg keys + icons) for the client. One big installation on the server (main application, reports, Database, and so on). The loader only purpose is to load the assembly (main application) from a common source (the server) and run it locally. Moreover.. this advantages a quick patch scenario: I have to patch ONLY the main application on the server only (main application, reports, database...). (take it as a "ClickOnce"-like technology)By the way: If I want to deliver a spyware on a end-user machine (and I've already an "high-privileged" .exe running on it) I should copy the assembly to load on the local machine to give it the "permanence".. and not run it from any network share. Don't you think?
By the way number 2: If I would like to deliver a spyware or something similar.. do you think I would mind about security? do you think I would say "I don't want to change permanently the security settings on the machine"? Do you think I would say "every caller could call the 'assembly to load' and this is bad"?
stand__sure wrote: |
| BEFORE YOU ATTEMPT TO DEFEND, your code snippet raises red flags -- it asks for permissions that should generally be avoided, that are excessive for most legitimate purposes, etc. Your snippet requests unrestricted File IO, registry writes, security control, serialization control and unmanaged code permissions -- this set of permissions is seldom if ever needed, is manifestly unwise to grant to internet-zone code, etc. |
|
The "main application" (known before as "assembly to load") requests all those requirements because it simply uses it :) Registry to store local program preferences (user-indipendent), unrestricted file IO because its work is to read and write files to the disk letting the user specify the path (FileDialogPermission), unmanaged code because it uses p/invoke for a lot of reasons (like control hooking, internet connection checking, network enumeration, and so on), serialization because it serializes/deserializes some parts of itself and so on...Are you still convinced that "I want to do bad things"?
Do you need more explanations? :)
Now.. I'm sure that the permission requested by the loaded "assembly" are a little high but are all necessary.
Actually I have to copy locally the main.dll (assembly to load) on the same path of the loader and then load it.
I was simply asking if someone knows what's the correct way to handle this.
(Security in .NET is an obscure thing for me...so I was asking an hint...)
Thank you.
stand__sure wrote: |
- FullTrust? No, your assembly does not have it. Does it have a Strong Name? Does it show in the list when you run caspol -listfulltrust at the command prompt? Just because your loader app is present on your machine does NOT mean that it is full trust. Several things are required.
|
|
Just to clarify, the way to see what permission set an assembly would be granted (aside from the AppDomain policy) is to use caspol -rsp <assembly>; caspol -rsg <assembly> will show you how it got those permissions.
caspol -listfulltrust is not to be used to determine if an assembly is fully trusted. That full trust list is a seperate entity used by assemblies that contain policy objects. For more information on that full trust list, please see What's the FullTrust List For Anyway?
stand__sure wrote: |
| You write: The loader doesn't have any security attributes declared ... This makes NO sense -- grab a good 70-306/316 book and read the section on "Assemblies, Configuration and Security"... |
|
He's probably talking about assembly-level declarative security.
-Shawn
Hi Lino,
What version of the CLR are you using? If you're on v1.x, you'll run into a problem in that each of the four policy levels can only decrease the trust granted by the others, not increase it.
That means that since the machine level is granting partial trust to your assembly on the network, no matter what you do for AppDomain policy, you cannot increase that back to FullTrust.
However, if you're on v2.0 of the CLR you can create an AppDomain with the new AppDomain.Create overload that takes a PermissionSet as a parameter. If you pass new PermissionSet(PermissionState.Unrestricted) as that parameter, any assembly loaded into that domain will be granted FullTrust.
-Shawn
First of all, I would like to really thank you both for your help.
Maybe I was not clear since the beginning.
Shawn Farkas - MS wrote: |
| What version of the CLR are you using? |
|
2.0 July CTP
Shawn Farkas - MS wrote: |
| If you're on v1.x, you'll run into a problem in that each of the four policy levels can only decrease the trust granted by the others, not increase it.That means that since the machine level is granting partial trust to your assembly on the network, no matter what you do for AppDomain policy, you cannot increase that back to FullTrust. |
|
I understand.. Yesterday I gave up with this because I found a document
here that states what you've just said here.
That document wrote: |
| At load time, the code access security system examines all policy levels and the resulting permission grant is the intersection of all allowed permissions in each level.Administrators of a lower policy level cannot loosen a policy decision made on a higher level, but they can tighten policy as much as they want.The default security policy resides on the machine policy level. |
|
Since the "AppDomain" level is lower than the "Machine" one "the intersection" means that I simply can't give the code more permissions than what the CLR determines.
Shawn Farkas - MS wrote: |
| However, if you're on v2.0 of the CLR you can create an AppDomain with the new AppDomain.Create overload that takes a PermissionSet as a parameter. If you pass new PermissionSet(PermissionState.Unrestricted) as that parameter, any assembly loaded into that domain will be granted FullTrust. |
|
This is what I was looking for!!! I tried before with AppDomain.Create (instead of Appdomain.CurrentDomain) but I never saw the overload with the PermissionSet parameter!!!!
Actually I workarounded this by reading the assembly into a byte[] and calling the Load(byte[]) overload. This fools the "code source location" (and security) of the CLR.
Shawn Farkas - MS wrote: |
| Just to clarify, the way to see what permission set an assembly would be granted (aside from the AppDomain policy) is to use caspol -rsp <assembly>; caspol -rsg <assembly> will show you how it got those permissions. |
|
I actually use the "evaluate assembly" menus on .NET Configuration/runtime security (that is a gui for CasPol) ;)
Shawn Farkas - MS wrote: |
| He's probably talking about assembly-level declarative security. |
|
Yes! I would mean that :)
Thank you very much, Shawn!!!!
Lino wrote: |
First of all, I would like to really thank you both for your help. Maybe I was not clear since the beginning. Since the "AppDomain" level is lower than the "Machine" one "the intersection" means that I simply can't give the code more permissions than what the CLR determines.
|
|
Just want to clarify a bit here ... the wording of that document can be a bit confusing. There's really no such thing as "higher" and "lower" for policy level intersection. No level can result in more permissions being granted than the least restrictive level allows .... if that makes sense.
Enterprise ^ Machine ^ User ^ AppDomain = Final ... since set logic allows us to rewrite that as:
AppDomain ^ Machine ^ Enterprise ^ User, or Machine ^ Enterprise ^ User ^ AppDomain, etc.
Lino wrote: |
I actually use the "evaluate assembly" menus on .NET Configuration/runtime security (that is a gui for CasPol) ;)
|
|
Yep, they'll both work equally well -- just wanted to point out that the CasPol "full trust list" is not what you need to be checking.
Glad to help out!
-Shawn