Determining the Security Rules for Your Assemblies – #14

If you’ve followed this tip series you’ll know about two different kinds of security transparency, one present in CLR 2.0 and one in CLR 4.0. And you know that in CLR 4.0, you can decide to use the legacy transparency rules in CLR 2.0. And you know about this attribute called APTCA. Maybe a bit about permissions, too.

It can be really hard to keep all this information straight, so I’ve put together a flowchart to help you determine which transparency rules a particular assembly is using. I hope it’s useful!

image

As you can see, while the number of rules is not totally unmanageable, it can be difficult to keep them straight. There are also a few situations where two different paths lead to the same outcome. For example, your assembly can be fully critical when it is a level 2 assembly marked with the SecurityCriticalAttribute or when it is a level 1 assembly marked with the SecurityCriticalAttribute with SecurityCriticalScope.Everything. Keep in mind that even though the assembly is fully critical in both cases, the meaning of critical depends on the current level, level 1 or level 2. If you need a review, consult my previous tips on CLR v2 transparency and CLR v4 transparency.

Transparency and Implicit Static Constructors – #13

When you create classes that have static fields, and you initialize those fields inline, the compiler will split the code into two parts: the field declaration and the field initialization. Field initialization occurs within a static constructor, whether it’s declared or not. Have a look at the following class as it appears in C#.

public class Wrapper

{

    private static IntPtr handle = InitializeHandle();

 

    private static IntPtr InitializeHandle()

    {

        // get handle

    }  

}

It’s almost the same as doing this.

public class Wrapper

{

    private static IntPtr handle;

 

    static Wrapper()

    {

        handle = InitializeHandle();

    }

 

    private static IntPtr InitializeHandle()

    {

        // get handle

    }

}

The difference between the implicit static constructor and explicit static constructor is that the implicit constructor performs much better than the explicit one. (You can read more about this difference here.)

What if I deem that the handle itself should be SecurityCritical? This is where things get interesting…

public class Wrapper

{

    [SecurityCritical]

    private static IntPtr handle = InitializeHandle();

 

    private static IntPtr InitializeHandle()

    {

        // get handle

    }

}

If I instantiate a new Wrapper instance, this code still runs correctly, but if I mark this assembly with APTCA, it fails. What’s happening here?

We get a FieldAccessException whose message is "ConsoleApplication2.Wrapper.handle" and whose stack trace is "at ConsoleApplication2.Wrapper..cctor()." The ".cctor" is the static constructor. From this we can deduce that the static constructor can’t initialize the field, and that’s because the static constructor generated by the compiler is transparent code when we mark the assembly with APTCA.

Unfortunately this is a case in which you must sacrifice performance for security. This might be changed before .NET 4 RTM, but for now, you’ll need to explicitly specify the static constructor and mark it as security safe critical or security critical. (You can mark it security critical because the runtime itself will call the static constructor from native code.)

public class Wrapper

{

    [SecurityCritical]

    private static IntPtr handle;

 

    [SecurityCritical]

    static Wrapper()

    {

        handle = InitializeHandle();

    }

 

    private static IntPtr InitializeHandle()

    {

        // get handle

    }

}

Partial Trust, APTCA, and Security Transparency – #12

We’ve talked about APTCA. We’ve talked about security transparency. Do they relate? Yes, at least in .NET 4.

Marking your assembly with APTCA means that your entire assembly becomes security transparent. However, you can still explicitly annotate portions of the code as SecuritySafeCritical or SecurityCritical.

You may wonder what happens if you don’t mark your assembly APTCA. Partial trust code obviously cannot call it, but for a different reason. If you remember back to my APTCA article, you’ll remember that partial trust code can’t call strong-named assemblies that aren’t marked APTCA. However, in .NET 4, by default, partial trust code can’t call any assembly. This is because partial trust code is always security transparent, and the default transparency level for .NET 4 code is security critical. Security transparent code can’t ever call security critical code unless it goes through security safe critical code first.

Type Transparency in .NET 4 – #11

Up to this point I have focused on transparency with regards to .NET methods, but you can utilize the transparency attributes on types as well. They basically imply the same layering as they do when applied to methods, but there are some interesting invariants that the CLR will enforce with regards to type transparency.

There are two attributes of interest, the System.Security.SecuritySafeCriticalAttribute and the System.Security.SecurityCriticalAttribute. If you remember from the last tip, transparent code can only call critical code through safe critical code. So what does it mean for a type to safe critical or critical?

In most cases, it means that every member—this includes methods, fields, property getters and setters, nested classes, and delegates—inherits the annotation. Have a look at the class below.

[SecurityCritical]

public class Foo

{

    public static int Bar;

 

    public static class Bar

    {

        public static void Exec() { }

    }

 

    public Foo()

    {

    }

 

    public void Baz()

    {

    }

}

The Foo class is marked SecurityCritical, which means that transparent code cannot do the following:

  • Instantiate a new Foo.
  • Access the static Bar field.
  • Call the Exec method on the nested Bar class.
  • Call the Baz method.
  • Use reflection to call any of the above.

So even though the fields, methods, and nested classes aren’t explicitly marked security critical, the attribute on the class forces the critical behavior to flow down to all its members.

When you start mixing transparency and inheritance, it gets a bit tricky. There are some simple rules you can learn to help.

1. Derived types must be at least as restrictive as their base types.

If I decide to extend Foo with a FooBar class, then it must be marked with the SecurityCriticalAttribute if you want to use the class. Otherwise, when the JIT compiler encounters code that instantiates or uses FooBar, it will throw a TypeLoadException. In other words, Main will not even execute here:

public class FooBar : Foo

{

}

 

static void Main(string[] args)

{

    new FooBar();

}

Here is a list of the allowed combinations of base types and derived types.

Base Type Derived Type
Transparent Transparent
Transparent Safe Critical
Transparent Critical
Safe Critical Safe Critical
Safe Critical Critical
Critical Critical

 

2. Overridden methods must be as restrictive as the base method.

This means that when you override a Critical method, your method must also be marked Critical. However, Transparent and Safe Critical are considered as the same restriction from this rule’s point-of-view, so I can have a Transparent override of a Safe Critical method, and vice versa, without problems.

What, then, is the problem with this code?

[SecurityCritical]

public class RemotableObject : MarshalByRefObject

{

    public override object InitializeLifetimeService()

    {

        return base.InitializeLifetimeService();

    }

}

In .NET 4 the MarshalByRefObject.InitializeLifetimeService method is Critical, but we also established earlier in this post that if you mark a type as Critical, then every member inside of it is also Critical, right?

Well, I said "in most cases." This is the exception to the rule. From there we come to the last rule.

3. Overridden methods are always Transparent by default.

The problem above, then, can be remedied by marking InitializeLifeTimeService with the SecurityCriticalAttribute explicitly.

And that’s it for type transparency!

An Introduction to Security Transparency in .NET 4 – #10

Last week I covered security transparency in CLR 2.0 by looking at topics like how transparency can reduce your security footprint, using transparency in CLR 2.0, and transparent code behavior in CLR 2.0.

As you may have noticed, the transparency story changes in .NET 4. It would be too much to write about everything that has changed, so I’ll address the high-level points in this post and build on that foundation in future posts.

In the second version of the CLR, which includes .NET 2.0 to .NET 3.5 SP1, transparency’s goal was to separate code into layers to reduce time needed for security audits. The rationale was most code in an assembly is transparent and thus doesn’t require a lot of attention because it doesn’t do anything interesting from the point-of-view of security (like call unmanaged code or unverifiable code). The critical code is what requires careful scrutiny.

.NET 4 has improved security transparency by making it a full-fledged enforcement mechanism for these invariants. Consider one of the differences between the models. Transparent code in CLR 2.0 can still call unmanaged code (through P/Invoke, COM Interop) if it has UnmanagedCode permissions. However, since native code isn’t governed by the permission set of the AppDomain, this is a potentially dangerous operation. This means that you still had to audit transparent code in CLR 2.0 in case it called unmanaged code. In CLR 4.0, an Exception is thrown when transparent code attempts to call native code, regardless of its grant set.

Transparent code still can’t assert for permissions, and it still can’t satisfy a demand for permissions. One change, though, is that in CLR 2.0, LinkDemands were converted to full Demands if a transparent method called a method with that LinkDemand. In CLR 4.0, transparent code cannot satisfy a LinkDemand, and an Exception is thrown.

Another means by which the enforcement is improved is the emergence of a more rigid boundary between transparent code and critical code. In CLR 2.0, transparent code in assembly Foo can call public critical code in assembly Bar. In CLR 4.0, again, an Exception is thrown. The transparency rules are now fully enforced across assembly boundaries. Transparent code cannot call any critical code directly. End of story.

Security Transparency LayeringIn order for transparent code to call critical code now, it must call it via a method that is marked with the System.Security.SecuritySafeCriticalAttribute. This essentially replaces the need for the SecurityTreatAsSafeAttribute (which I discussed in the CLR 2.0 transparency post). You can think of safe critical code as a gateway for transparent code to call critical code. The restriction is only one way, however—that is, security critical code can call transparent code without problems.

There is so much more to cover with regards to transparency in .NET 4 that I think this is a good stopping point for today. If you can’t wait for more information, you can read the documentation as well as watch a Channel 9 interview of Shawn Farkas, a Senior SDE on the CLR security team, where he digs into the new security rules in .NET 4. Enjoy!

Hosting Conditional APTCA Assemblies – #9

Last Friday I discussed how to host a partial trust sandbox, and yesterday I touched on conditional APTCA in .NET 4. By the title of this post, it’s probably no surprise that we’re going to combine the two concepts and examine how to allow partially trusted code to call a conditional APTCA assembly.

Creating a sandbox requires an instance of the AppDomainSetup class. This class has a new property in .NET 4 called PartialTrustVisibleAssemblies. This is a string array where each value in the array contains an assembly’s simple name along with its public key (not the public key token!). Let’s look at an example.

Here I have a simple console application that attempts to create a new HttpCookie in partial trust.

public class Program : MarshalByRefObject

{

    static void Main(string[] args)

    {

        RunInPartialTrust();

    }

    private static void RunInPartialTrust()

    {

        AppDomainSetup setup = new AppDomainSetup

        {

            ApplicationBase = Environment.CurrentDirectory

        };

 

        PermissionSet grantSet = new PermissionSet(null);

        grantSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.AllFlags));

        AppDomain domain = AppDomain.CreateDomain("PT Sandbox", null, setup, grantSet);

 

        Program p = (Program)domain.CreateInstanceAndUnwrap(

            Assembly.GetExecutingAssembly().FullName,

            typeof(Program).FullName

        );

 

        p.PartialTrustMain();

    }

    public void PartialTrustMain()

    {

        // Oops…

        HttpCookie cookie = new HttpCookie("Foo");

    }

}

(If you need a refresher on what the code in the RunInPartialTrust method does, check out my previous tip on hosting partial trust sandboxes.)

The System.Web.HttpCookie class is in the System.Web assembly, which is marked as conditional APTCA in .NET 4. Because we haven’t done anything special in our hosting code, calling the HttpCookie constructor throws an all too familiar SecurityException…

SecurityException: That assembly does not allow partially trusted callers.

We need to modify our AppDomain setup code to allow this call to work. For this we’ll need the name and public key of the assembly. The name is “System.Web,” but what’s the public key?

If you’re like me and don’t memorize public keys, you’ll need some help here. Remember your trusty friend sn.exe, the Strong Name Tool? It has a useful function that allows you to extract a public key from a strong named assembly.

sn.exe –Tp <assembly>

Public Key - System.Web

Taking this information and modifying the AppDomainSetup instance yields this small change.

AppDomainSetup setup = new AppDomainSetup

{

    ApplicationBase = Environment.CurrentDirectory,

    PartialTrustVisibleAssemblies = new string[] { "System.Web, PublicKey=0024000004800000940000000602000000240000525341310004000001000100 etc." }

};

Note the presence of “PublicKey=” in the string. This must be present in order for partial-trust visible assembly registration to work. Also, don’t copy and paste this, as I obviously didn’t have room to paste the entire public key. :)

Re-running the application will allow the call to System.Web.HttpCookie’s constructor.

Interesting Tidbit: On the Entity Framework we ran into a bug where we called APIs in System.Web in partial trust where the host was a XAML Browser Application (XBAP), not ASP.NET. The SecurityException above was thrown, and now you know why! So be careful if you are calling into framework code like System.Web from partial trust, and the host is not the common one.

In these situations it might be useful for you to check which conditional APTCA assemblies can be called from partial trust. You can do this by reading the PartialTrustVisibleAssemblies property of the current AppDomain through the following string of property calls.

AppDomain.CurrentDomain.SetupInformation.PartialTrustVisibleAssemblies

image

Tomorrow we’ll move out of APTCA and partial trust hosting onto something new.

Conditional APTCA in .NET 4 – #8

The first item on this week’s security tips is about a new feature in .NET 4 called conditional APTCA. If you read my previous tip on the AllowPartiallyTrustedCallersAttribute (APTCA), you’ll know that you can decorate assemblies with this attribute in order to allow calls into that assembly’s public API from partial trust.

.NET 4 advances the capabilities of APTCA to reflect the decision to give control of permissions to hosts instead of machine-wide policy. Assemblies can now specify whether they allow partially trusted callers based on whether the host allows it. ASP.NET is a good example of why this feature is useful. In .NET 4, System.Web.dll is marked conditionally APTCA, because it accepts calls from partially trusted code only if the host is ASP.NET itself. If the host is a ClickOnce application or Internet Explorer in the case of a control hosted by the browser, then partially trusted code cannot call into the System.Web assembly.

This doesn’t mean that an assembly can choose which hosts can allow partially trusted code to call it, only that the host must explicitly give access for partially trusted code to call that assembly. This means that as an application developer, I can create my own host that allows code from partial trust to call System.Web.dll. We’ll cover this in tomorrow’s tip.

In order to mark your assembly conditionally APTCA, set the attribute’s PartialTrustVisibilityLevel property to PartialTrustVisibilityLevel.NotVisibleByDefault.

[assembly: AllowPartiallyTrustedCallers(PartialTrustVisibilityLevel = PartialTrustVisibilityLevel.NotVisibleByDefault)]

Next time we’ll talk about how to setup `a host to enable partially trusted code to call conditional APTCA assemblies.

How to Host a Partial Trust Sandbox – #7

In previous tips, I referenced some APIs that allowed me to run code in partial trust, and we’ll finally cover that code today, as well as some API changes made in .NET 4 to make it easier to set up the sandbox.

Where We’ve Come From

In .NET 1.1 and below, the only way to control trust levels was through CAS Policy, which was a powerful but very complex system for managing which permissions apply to given assemblies loaded in your application. The gist is that there are multiple levels of policy—Enterprise, Machine, User, and AppDomain—each with code groups and membership conditions for those code groups. Each code group specified a permission set, and the membership conditions specified which assemblies were classified in a given code group, based on its evidence, like its Zone, StrongName, Url, etc. Since an assembly can belong to multiple code groups, the permissions for an assembly were unioned across all code groups within a policy level, and then intersected across policy levels. But wait, there’s more! You can specify any policy level to be a "final" level or an "exclusive" level, which affects how the permissions are intersected…

If you’re feeling confused, then don’t worry. You’re not alone. If you want a more thorough discussion of CAS Policy, you can Google it. With CAS Policy’s deprecation and the subsequent focus on hosts to provide permissions instead of policy, the focus of this post is on the host, not CAS policy.

Where We Are

In .NET 2.0, the CLR team introduced new APIs which allow code to create a partial trust sandbox, where only the permissions that the host requests are granted to the code running within the sandbox. These sandboxes are actually homogeneous AppDomains, where every piece of code running in the assembly is subject to one of two permission grant sets:

  1. Full Trust
  2. The grant set of the AppDomain.

Assemblies will be full trust if they either (1) are loaded from the GAC or (2) appear on the AppDomain’s list of trusted assemblies. Here’s the method behind the sandboxing magic.

public static AppDomain CreateDomain(

    string friendlyName,

    Evidence securityInfo,

    AppDomainSetup info,

    PermissionSet grantSet,

    params StrongName[] fullTrustAssemblies

)

The interesting parameters are the PermissionSet and the array of StrongName instances that are considered full trust in the sandbox. The CLR will enforce that the sandbox has only the permissions of the PermissionSet passed to this method. The set of StrongNames that you can supply describes assemblies which the AppDomain will treat as full trust. You may wonder what it means to be a full trust assembly when demands for permissions traverse the entire call stack in an AppDomain; essentially, full trust assemblies are allowed to elevate their permissions using asserts and they can satisfy LinkDemands for permissions you don’t normally have in the AppDomain.

Let’s look at an example use of the AppDomain.CreateDomain sandbox method.

static void RunInPartialTrust()

{

    AppDomainSetup setup = new AppDomainSetup

    {

        ApplicationBase = Environment.CurrentDirectory

    };

 

    PermissionSet permissions = new PermissionSet(null);

    permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

    permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));

    AppDomain appDomain = AppDomain.CreateDomain(

        "Partial Trust AppDomain",

        null,

        setup,

        permissions

    );

 

    Program p = (Program)appDomain.CreateInstanceAndUnwrap(

        typeof(Program).Assembly.FullName,

        typeof(Program).FullName

    );

 

    p.PartialTrustMain();

}

The setup process is simple. Creating the PermissionSet requires a few lines of code where you explicitly supply which permissions you want for the sandbox, and creating the AppDomainSetup object is also trivial. From there, create the AppDomain with the CreateDomain method, instantiate a new object in that AppDomain, and call a method on it. As soon as you call that method, your code will transition from the default AppDomain to the new sandboxed domain. Note that the class you instantiate should inherit from ‘>MarshalByRefObject in order for it to be marshalled across AppDomain boundaries. (In the example above, the Program class inherits from MarshalByRefObject.)

You may wonder why I pass null for the Evidence parameter. Most APIs in .NET 4 that expose an Evidence parameter are deprecated because those methods typically interact with CAS policy to achieve their objectives. However, passing null is the same as passing the Evidence of the current (full-trust) AppDomain, which means it will not affect the sandbox. In fact, based on what I see in Reflector, if you pass in custom evidence, it will be ignored.

The more interesting use of the sandbox API arises when you need full trust assemblies in your new sandbox, but they don’t live in the GAC. Here you can use an improved version of the Evidence API exposed in .NET 4 to retrieve the StrongName instance from a given assembly. (Yes, that’s right. In order to be a full trust assembly in a sandbox, the assembly must be strong named.)

StrongName foo = typeof(Foo).Assembly.Evidence.GetHostEvidence<StrongName>();

 

If this were .NET 3.5, you would have to do this, so I’m sure you can appreciate the brevity of the new API.

StrongName sn;

IEnumerator enumerator = typeof(Foo).Assembly.Evidence.GetHostEnumerator();

while (enumerator.MoveNext())

{

    sn = enumerator.Current as StrongName;

    if (sn != null)

    {

        break;

    }

}

 

After you aggregate all of the StrongName instances that you need, pass them as the last parameter of AppDomain.CreateDomain to treat the assemblies identified by those StrongNames as full trust. Afterwards your sandbox is up and running, and you can start playing with partially trusted code.

Opting Out of Security Changes in .NET 4 – #5

I decided to provide another tip today since .NET 4 Beta 1 was released! I definitely like the changes that the security team has made to make permissions easier to understand and to improve enforcement of transparency, but there are breaking changes here that require work you may not be ready for. If you need to revert to the old behavior (e.g. using CAS policy, CLR 2.0 transparency, or the old SecurityActions) in order to prepare for migration, then take a look below.

To enable legacy CAS policy, support for the obsolete SecurityActions, and anything else that can make AppDomains heterogeneous, add the NetFx40_LegacySecurityPolicy element to the runtime element of your configuration file. This will enable the legacy behavior only for the application for which you make the configuration change. 

<configuration>

  <runtime>

    <NetFx40_LegacySecurityPolicy enabled="true" />

  </runtime>

</configuration>

 

To revert to CLR 2.0 transparency, add the System.Security.SecurityRulesAttribute to your assembly and specify the Level1 SecurityRuleSet. (Level1 = CLR 2.0, Level2 = CLR 4.0)

[assembly: SecurityRules(SecurityRuleSet.Level1)]

 

Update June 8, 2009: The configuration switch for enabling legacy CAS policy under .NET 4 Beta 2 has changed to NetFx40_LegacySecurityPolicy, and I’ve updated the post above. In case you are using .NET 4 Beta 1, the switch is legacyCasPolicy, as shown below.

<configuration>

  <runtime>

    <legacyCasPolicy enabled="true" />

  </runtime>

</configuration>

What’s New With Security in .NET 4? – #4

A lot.

A whole lot.

The main reason I started this series was because of the vast amount of changes coming in security in the latest release of the .NET Framework. Now that .NET 4 is publically available, I want to call attention to these changes. In future tips, I’ll address them in more detail, but for now there are three big things (IMO) you should be aware of. (The documentation lists more but they are minor compared to the first three.)

CAS Policy is DEPRECATED and DISABLED by Default

With the release of .NET 4, the CLR starts the move away from machine-wide policy enforcement. This means no more code groups and membership conditions to deal with in caspol.exe or the .NET configuration tool; no more considering Enterprise, Machine, and User permissions; and no more considering how LevelFinal and Exclusive throw a monkey wrench in determining which assemblies get which permissions.

So this means that everything runs in full trust unless the host specifies otherwise. The CLR now gives full control to the host to create AppDomains that sandbox code into using particular sets of permissions. Examples of hosts are ASP.NET, Internet Explorer, and ClickOnce, where people are already used to sandboxing their applications (e.g. medium trust in ASP.NET).

As a result, all AppDomains are now homogeneous, which is just a fancy way of saying that all assemblies running in that AppDomain have one of two different permission grant sets—the grant set of the AppDomain (default) or full trust (assemblies in GAC or assemblies in AppDomain’s full trust list).

Security Transparency, Level 2

All of the previous posts I’ve done on transparency thus far have focused on transparency in the second version of the CLR. If you are using transparency today, there are changes you need to be aware of when migrating your application to .NET 4. While the intent for transparency has not changed (to isolate different groups of code based on privilege), the CLR has stepped up its enforcement based on how Silverlight implemented transparency.

I’ll cover the new rules in a later post.

Support Removed For SecurityActions: Deny, RequestMinimum, RequestOptional, RequestRefuse

In the second version of the CLR you could place permission requests as attributes on your assemblies. If CAS policy evaluated that a particular assembly couldn’t the permissions it requested, then it would fail to load in the application. If the application itself couldn’t receive its requested permissions, then it would fail to start completely.

In .NET 4, support for these assembly-wide permission attributes has been removed for various reasons, the main one being that they contravene the push to make permissions simpler to understand and evaluate. Remember, AppDomains are now homogeneous, so specific assemblies cannot control their own permissions. That power belongs in the hands of the host.

SecurityAction.Deny was removed because it could easily be overridden by using an assert, thus opening a security hole.

 

In future tips I’ll look deeper at each of these areas. Be sure to check out and give feedback on the beta security documentation as well!