Reading docs/prototyping and it seems I do not understand the big picture in the new .NET 4 security model. Ok, I understand and even prototyped the 3-layer security model (transparent code, security-safe-critical code, and security-critical code). Works fine.
What I cannot understand is how it relates to the permissions. I need to have SecurityTransparent
code that does not have any permissions except to execute and then I need to have SecurityCritical
code that has all permissions. I tried playing in the ConsoleApp. In the ConsoleApp in the default domain SecurityTransparent
code has all permissions and so could actually do whatever it wants, e.g. create files, write reg keys, etc. And if I create "sandbox" (aka AppDomain) and restrict permissions all code running the domain has such permissions, for example, both SecurityTransparent
or SecurityCritical
has no access to e.g. Files, Registry and etc. So, I clearly do not understand what is this 3 layers security model (transparent code, security-safe-critical code, and security-critical code) gives us if security critical code when running in the sandbox has same permissions level as security transparent.
Another question is what is "Full Trust" assembly property reeeeeeallly means and when it could be anything other than Full Trust and how it all affects security.
Update 1 - Code
class Program
{
public static PermissionSet GetPermissionSet()
{
var permissions = new PermissionSet(PermissionState.None);
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
// Just to be able to write to the Console
permissions.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
return permissions;
}
public static string GetDomainInfo(AppDomain domain)
{
StringBuilder sb = new StringBuilder();
//check the domain trust
sb.AppendFormat("Domain Is Full Trusted: {0} \n", domain.IsFullyTrusted);
//show the number of the permission granted to the assembly
sb.AppendFormat("\nPermissions Count: {0} \n\n\n", domain.PermissionSet.Count);
sb.AppendFormat("\nPermissions Is Homogenous: {0} \n\n\n", domain.IsHomogenous);
return sb.ToString();
}
public static StrongName GetTypeAssemblyStringName(Type type)
{
var name = type.Assembly.GetName();
return new StrongName(new StrongNamePublicKeyBlob(name.GetPublicKey()), name.Name, name.Version);
}
public static AppDomain CreateDomain()
{
//create the AppDomainSetup
AppDomainSetup info = new AppDomainSetup();
//set the path to the assembly to load.
info.ApplicationBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
//create the domain
AppDomain domain = AppDomain.CreateDomain(
"MyCoolDomain",
null,
info,
GetPermissionSet(),
GetTypeAssemblyStringName(typeof(SecurityCriticalApi1Class)), /* Get's full trust but operates as partial trust */
GetTypeAssemblyStringName(typeof(SecurityCriticalApi2Class)), /* same */
GetTypeAssemblyStringName(typeof(SecuritySafeApiClass)) /* same */
);
return domain;
}
public static void ShowAssemblyInfo(Type type)
{
var a = Assembly.GetAssembly(type);
ShowAssemblyInfo(a);
}
public static void ShowAssemblyInfo(Assembly a)
{
var sb = new StringBuilder();
//show the transparency level
sb.AppendFormat("\nAssembly: {0}\n", a.GetName().Name);
sb.AppendFormat("Security Rule Set: {0}\n", a.SecurityRuleSet);
//show if it is full trusted
sb.AppendFormat("Is Fully Trusted: {0}\n", a.IsFullyTrusted);
try
{
sb.AppendFormat("Permissions Count: {0} \n", a.PermissionSet.Count);
}
catch (Exception ex)
{
sb.AppendFormat("Error while trying to get the Permission Count: {0} \n", ex.Message);
}
Console.WriteLine(sb);
}
static void Main(string[] args)
{
try
{
Console.WriteLine("Started");
var domain = CreateDomain();
Console.WriteLine(GetDomainInfo(domain));
Type t = typeof(TransparentApiClass);
ObjectHandle handle = Activator.CreateInstanceFrom(domain, t.Assembly.ManifestModule.FullyQualifiedName, t.FullName);
var api = (TransparentApiClass)handle.Unwrap();
api.DoIt();
Console.WriteLine("Stopped");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
[SecuritySafeCritical]
public class SecuritySafeApiClass
{
public void DoIt()
{
Console.WriteLine("SecuritySafeApiClass calling SecurityCritical API");
var api = new SecurityCriticalApi1Class();
api.DoIt();
Console.WriteLine("SecuritySafeApiClass Done");
}
}
public class SecurityCriticalApi1Class
{
public void DoIt()
{
Console.WriteLine("SecurityCriticalApi1Class");
// Throws exception - require permission
var key = Registry.ClassesRoot.GetSubKeyNames();
Console.WriteLine("SecurityCriticalApi1Class Done");
}
}
If I understand things right my problem description could be shorten - in my case code loaded with Full Trust by specifying corresponding strong names in the domain setup acts as partial trust, mean operates with same permissions set as doman.
Update 2
I tried to use Assert
public class SecuritySafeApiClass
{
public void Assert()
{
var permissions = new PermissionSet(PermissionState.Unrestricted);
permissions.AddPermission(new RegistryPermission(PermissionState.Unrestricted));
permissions.Assert();
}
public void DoIt()
{
Console.WriteLine("SecuritySafeApiClass calling SecurityCritical API");
Assert();
var api = new SecurityCriticalApi1Class();
api.DoIt();
Console.WriteLine("SecuritySafeApiClass Done");
}
}
And it not helped :( :(
The error I'm getting is:
Failed to execute action. error System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.RegistryPermission, mscorlib, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089' failed. at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet) at System.Security.CodeAccessSecurityEngine.Check(CodeAccessPermission cap, StackCrawlMark& stackMark) at System.Security.CodeAccessPermission.Demand() at Microsoft.Win32.RegistryKey.CheckPermission(RegistryInternalCheck check, String item, Boolean subKeyWritable, RegistryKeyPermissionCheck subKeyCheck) at Microsoft.Win32.RegistryKey.GetSubKeyNames() at SecurityCriticalApi1.SecurityCriticalApi1Class.DoIt() in C:\Dev\SecurityProofOfConcept\SecurityCriticalApi1\SecurityCriticalApi1Class.cs:line 20 at SecuritySafeApi.SecuritySafeApiClass.DoIt() in C:\Dev\SecurityProofOfConcept\SecuritySafeApi\SecuritySafeApiClass.cs:line 29 at TransparentApi.TransparentApiClass.b__2_0() at TransparentApi.TransparentApiClass.TryToExecute(Action a, String caller) The action that failed was: Demand The type of the first permission that failed was: System.Security.Permissions.RegistryPermission The Zone of the assembly that failed was: MyComputer