Asserting for Permissions in .NET 4 – #18

June 25th 2009

Security asserts are a way to tell the CLR to stop checking for permissions past a certain point in the call stack. Of course, not all code is allowed to assert, or we’d have some big security problems to worry about. Specifically, partial trust code and security transparent code cannot assert for permissions. You may ask why asserting is useful, then, when only fully trusted code can do it.

One use case where asserts are beneficial is in testing products in partial trust. Say we have some test code that runs in partial trust and calls LINQ to SQL to test that a certain scenario still works in a medium trust environment. However, the test framework that the test uses requires permissions that are not granted in medium trust for some operations. Since the test framework knows that its callers won’t do anything malicious, it can assert for the permissions it needs to run these privileged operations. To do this, however, the test framework must be fully trusted.

Let’s say I have a test that runs in medium trust and calls some code in LINQ to SQL to verify that that code path works under medium trust. However, during some part of the test, the test framework itself needs to read an environment variable to determine which version of SQL Server to execute the test against (e.g. SQL Server 2000, SQL Server 2005, or SQL Server 2008).

Here’s the beginning of a test. (Keep in mind that this code is just an example. It doesn’t represent real types that we use in the LINQ to SQL test code, but it does demonstrate security assertions, which is something we do in the test framework.)

[Test]

public void TestMediumTrust()

{

    DataContext context = DataContextFactory.CreateDataContext();

 

    // …

}

And here’s the code in the test framework that the test above calls.

public static class DataContextFactory

{

    public static DataContext CreateDataContext()

    {

        string sqlVersion = ReadSqlVersion();

 

        // …

        // Return the correct data context.

    }

 

    [SecuritySafeCritical]

    [EnvironmentPermission(SecurityAction.Assert, Read = "SQLVERSION")]

    private static string ReadSqlVersion()

    {

        return Environment.GetEnvironmentVariable("SQLVERSION");

    }

}

The TestMediumTrust method resides in a test assembly, while the DataContextFactory resides in another assembly which is part of the test framework. When we set up the medium-trust sandbox in which to run the test, we tell the CLR to fully trust the test framework assembly. Full trust implies two things: (1) that SafeCritical and Critical annotations are respected and (2) we can assert for permissions. Remember that security transparent code cannot assert for permissions; this is why the ReadSqlVersion method above must be SafeCritical.

Medium trust code does not have permission to read the SQLVERSION environment variable, so under normal circumstances calling Environment.GetEnvironmentVariable would throw a SecurityException. This is because the .NET Framework itself will do a full Demand for the EnvironmentPermission to read the SQLVERSION variable. Permission Demands walk the entire call stack to ensure that every frame in the stack has the relevant permissions; since the test code runs in medium trust, the CLR will throw once it checks the TestMediumTrust method.

Asserts are a way to tell the CLR to stop checking for permissions past a particular stack frame. Thus with the assert in place on the ReadSqlVersion method, the EnvironmentPermission check stops prematurely and the permission Demand will succeed. To put that graphically…

image

So what changes in .NET 4? The recommended guidance is now to assert for full trust instead of for a specific permission. This advice seems to contradict the principle of least privilege, but in reality, if you layer your transparent and critical code appropriately, then security transparency can help you realize least privilege much more effectively. A second reason is that asserting for a specific permission causes a dependency on the underlying implementation. (This is a less convincing argument for me personally.) So the ReadSqlVersion method above now becomes…

[SecuritySafeCritical]

[PermissionSet(SecurityAction.Assert, Unrestricted = true)]

private static string ReadSqlVersion()

{

    return Environment.GetEnvironmentVariable("SQLVERSION");

}

Posted by David DeWinter under .NET4/VS2010 & Security Tips | No Comments »

How to Build APIs with Transparency in Mind – #17

June 23rd 2009

In the .NET Framework there are a few types which expose both "safe" and "unsafe" equivalents of the same method. Both methods achieve the same goal e.g. BinaryFormatter.Deserialize and BinaryFormatter.UnsafeDeserialize will both deserialize a stream into a .NET object, but the safe variant will do a full Demand for the appropriate permissions. This ensures that callers without proper permissions will fail when trying to call the safe method. The unsafe variant, on the other hand, ensures only that the immediate caller has the necessary permissions. Previous versions of the .NET Framework enforce these invariants with Demands and LinkDemands, as shown in the example below. (Note that this isn’t exactly what you’ll see for these methods in the BinaryFormatter class if you examine them in Reflector, but the permission Demand and LinkDemand are present.)

[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]

public object Deserialize(Stream serializationStream)

{

   return this.UnsafeDeserialize(serializationStream);

}

 

[SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]

public object UnsafeDeserialize(Stream serializationStream)

{

    // Method body

}

The reason for the two different versions is that a permission Demand is expensive because it has to check the permissions of every frame in the call stack. If you know that you aren’t introducing a security hole by calling an unsafe method, then you can skip the permission Demand and avoid the performance hit.

In .NET 4 under the Level 2 security rules, LinkDemands have been replaced by the SecurityCriticalAttribute, which means the UnsafeDeserialize will look similar to this.

[SecurityCritical]

public object UnsafeDeserialize(Stream serializationStream)

{

    // Method body

}

Methods annotated with LinkDemands should migrate to use the SecurityCriticalAttribute because the whole purpose of security transparency is to promote this kind of safe/unsafe API layering. When a method is decorated with the SecurityCriticalAttribute, the CLR ensures that no security transparent code can call that method. When you consider that all code running in partial trust is security transparent, the SecurityCriticalAttribute is effectively the same as a LinkDemand for full trust.

Be careful though! This API layering works for the .NET Framework because the assemblies are installed in the GAC and are therefore fully trusted, even in a partial trust sandbox. If the assembly you create is loaded into a partial trust sandbox but is not fully trusted, then the SecurityCriticalAttribute will not enforce anything. Remember, all partial trust code is security transparent, even code annotated with the SecurityCriticalAttribute.

Finally, if your assembly is not intended for partially trusted callers, then do you don’t need to worry about any of this. :)

Check out the .NET 4 documentation on Demands vs. LinkDemands for more information.

Posted by David DeWinter under .NET4/VS2010 & Security Tips | No Comments »

Mixing Level 1 and Level 2 Transparency Rules – #16

June 9th 2009

Today’s tip addresses how assemblies using different transparency rules (CLR v2 and CLR v4) interact with each other in the same AppDomain. Remember you can use the SecurityRulesAttribute to specify which level of security rules your assemblies adhere to. The default in .NET 4 is level 2.

There are only two cases here—a level 1 assembly calling a level 2 assembly, and a level 2 assembly calling a level 1 assembly. Let’s take them one at a time.

Level 2 Assembly Calls Level 1 Assembly

Transparency rules are not enforced across assembly boundaries under the level 1 rules, but they are under the level 2 rules. When a level 2 assembly calls a level 1 assembly, transparency violations are not enforced—that is, if level 2 transparent code calls a level 1 critical method in another assembly, the call succeeds.

Level 1 Assembly Calls Level 2 Assembly

You might think that transparency is enforced across the assembly boundary since the roles are now reversed, but the CLR acts a bit more interestingly than that. If partial-trust code from a level 1 assembly tries to call a critical method in a level 2 full-trust assembly, then the call fails. Level 1 assemblies, which use the CLR v2’s transparency semantics, have no way to interpret a public security critical method as it exists in level 2; such a concept didn’t exist back in the second version of the CLR. Because of this, the CLR goes to great lengths to make everything appear as level 1 to the calling assembly. To do this the CLR transforms the method marked SecurityCritical into a LinkDemand for FullTrust. Thus the call to a public critical method from partial trust code fails.

In the CLR v4, methods that were marked with LinkDemands for FullTrust are now marked SecurityCritical, which is a stronger enforcement mechanism because it prevents all partial-trust code and all transparent code from calling it. It is not a stretch to see that the CLR will transform the SecurityCritical annotation back into a LinkDemand for FullTrust to make everything appear as level 1 to the level 1 assembly.

This means that transparent code in a level 1 assembly can call public critical code in a level 2 assembly if the level 1 assembly is fully trusted. The rule states only that partial trust code in a level 1 assembly cannot call fully trusted security critical code in a level 2 assembly.

Furthermore, partial trust code is always security transparent and thus can never call security critical code.

Posted by David DeWinter under .NET4/VS2010 & Security Tips | No Comments »

The SecurityRulesAttribute – #15

June 8th 2009

The SecurityRulesAttribute is a new attribute class introduced in .NET 4.0 to specify which set of security rules a particular assembly adheres to. The attribute is specified on the assembly level, and allows you to specify two pieces of information.

The first and more important piece is the version of transparency that your assembly follows. If you want to use the .NET 2.0 interpretation of transparency, specify SecurityRuleSet.Level1 as the argument to the SecurityRulesAttribute constructor. If you want to use the .NET 4.0 interpretation of transparency, specify SecurityRuleSet.Level2. Level2 is also the default for assemblies built on the .NET 4.0 runtime.

For CLRv2 transparency semantics:

[assembly: SecurityRules(SecurityRuleSet.Level1)]

For CLRv4 transparency semantics:

[assembly: SecurityRules(SecurityRuleSet.Level2)]

The second piece allows to tell the CLR that you want to skip IL verification of your assembly when it is fully trusted and transparent. Remember, transparent code can’t contain unverifiable code or P/Invokes, so the CLR usually must check that the transparent code it loads does not violate these invariants. You can skip this verification to increase your performance slightly when the JIT compiler compiles your code, but remember that doing this will allow unverifiable code in your assembly. I’d recommend using this only if you don’t have unverifiable code in your transparent assembly.

That last scenario is slightly abstract, so I want to show an example of the difference.

SecurityDriver.exe

public class Program : MarshalByRefObject

{

    static void Main(string[] args)

    {

        PartialTrustSetup.CreatePartialTrustInstance<Program>().PartialTrustMain();

    }

 

    public void PartialTrustMain()

    {

        Utility u = new Utility();

        u.ExecuteUnsafeCode();

    }

}

SecurityLibrary.dll (Pardon the trivial example of unverifiable code.)

[assembly: SecurityTransparent]

public class Utility

{

    public unsafe void ExecuteUnsafeCode()

    {

        int i = 0;

        int* p = &i;

        *p = 2;

        Console.WriteLine(i);

    }

}

The Main method in SecurityDriver.exe sets up a partial-trust AppDomain and instantiates a new instance of the Program class in that AppDomain. The partial trust code only has permission to execute (SecurityPermission with SecurityPermissionFlag.Execution). When it calls Utility.ExecuteUnsafeCode, the JIT compiler throws a VerificationException because it can’t verify the IL in Utility.ExecuteUnsafeCode.

But if we add this attribute to the SecurityLibrary assembly and ensure that it is fully trusted (by using the StrongName[] parameter of the AppDomain.CreateDomain method), then the JIT compiler will skip IL verification, and "2" will be printed to the console.

[assembly: SecurityRules(SecurityRuleSet.Level2, SkipVerificationInFullTrust = true)]

Remember, this only works when your transparent assembly is fully trusted.

Posted by David DeWinter under .NET4/VS2010 & Security Tips | No Comments »

Determining the Security Rules for Your Assemblies – #14

June 3rd 2009

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.

Posted by David DeWinter under .NET4/VS2010 & Security Tips | No Comments »

Transparency and Implicit Static Constructors – #13

June 2nd 2009

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

    }

}

Posted by David DeWinter under .NET4/VS2010 & Security Tips | No Comments »

Partial Trust, APTCA, and Security Transparency - #12

June 1st 2009

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.

Posted by David DeWinter under .NET4/VS2010 & Security Tips | No Comments »

LINQ Expression Trees and the Specification Pattern

May 31st 2009

Over the past couple of months I have tried to immerse myself in domain-driven design, which includes learning about its purpose, the methodology, and the domain patterns presented in Evans’ book and built upon in many other venues (blogs, conferences, etc.). While I have not worked on a full-fledged DDD project, I have fiddled with a lot of patterns. One of these is the Specification pattern, which says to introduce a predicate-like Value Object into the domain layer whose purpose is to evaluate whether an object meets some criteria. From what I’ve read in Evans’ book, specification objects typically have an isSatisfiedBy method that takes a domain object and returns a boolean. The specification therefore encapsulates a predicate that can be used to test an object to see if it satisfies the criteria.

image

The problem that Evans later calls out is that of querying a data store using specification objects as filters. Because using the specification to filter records from the database requires that those records be selected and reconstituted into objects, it can be inefficient for some applications to use specification objects as is. (Imagine using a specification object on one million rows in the Customer table just to find the gold Customers!) Surely we can do better.

Ideas

One idea in the book is to allow a repository to help with the implementation and utilize double dispatch to keep the separation of domain and infrastructure in tact. Application code calls a method on a repository to query for objects based on a specification. That repository passes itself to a method on the specification object, so the specification can utilize the repository’s power to query for the objects that fulfill the criteria, and then return that data to the application.

image

Another alternative is to harness the power of LINQ and expression trees to represent the predicate that the specification object encapsulates. This means that we can (1) use the expression trees in the infrastructure to let the data store take care of filtering and (2) still represent our rule in one location without resorting to compromises in the repository API.

Expression trees are abstract syntax trees that can represent the predicates that specification objects strive to encapsulate. With these expression trees, certain O/R mappers like LINQ to SQL, the Entity Framework, and LLBLGen Pro can determine the intent of the code and translate it into the corresponding T-SQL code to run against the database.

Creating an expression tree is very simple. In fact, if you’ve used any of the O/R mappers I mentioned above, you’ve probably used them already. Here’s an example of an expression tree being used in LINQ to SQL to generate the WHERE clause in the corresponding T-SQL query below.

NorthwindDataContext db = new NorthwindDataContext();

db.Products.Single(p => p.ProductName == "Aniseed Syrup");

SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]

FROM [dbo].[Products] AS [t0]

WHERE [t0].[ProductName] = @p0

– @p0: Input NVarChar (Size = 13; Prec = 0; Scale = 0) [Aniseed Syrup]

– Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.1

Normally the lambda expression ‘p => p.ProductName == "Aniseed Syrup"’ would be treated as a Func<Product, bool>. However, in this particular usage the compiler infers that it is an Expression<Func<Product, bool>>. The difference means that the LINQ to SQL library no longer has a method pointer. Instead, it has a tree which represents what that method does. LINQ to SQL can visit the nodes in this tree and translate what it finds into SQL without ever invoking the code itself. A simple Func does not have that capability; it is simply a method pointer, like any other delegate type.

I hope you start to see how expression trees and the specification pattern can be very powerful together. If in addition to exposing an isSatisfiedBy method on the specification object, we add something which exposes the raw Expression, the repository can compose this Expression into the query and filter the results using the infrastructure. Let’s look at some code.

For this example, let’s continue to use the Products table from Northwind. The specification we implement here will tell us whether a product is a low stock product i.e. whether the number of units in stock for a particular product falls below a certain threshold. That threshold is defined in another system, so we will feed that data to the specification.

Let’s start with the basics. Here’s the base class for all Specifications. Instead of using IsSatisfiedBy, we expose a method which returns an expression tree of type Expression<Func<T, bool>>.

public abstract class Specification<T>

{

    public abstract Expression<Func<T, bool>> IsSatisfied();

}

The Expression class is in the System.Linq.Expressions namespace which is a part of System.Core.dll. Remember, this is just a different representation of IsSatisfiedBy; instead of keeping the logic embedded in a method in the specification object, we package the logic in an expression tree. The predicate still receives an object and returns a boolean. Other classes, like the ProductRepository, can now leverage this expression tree to optimize the query it sends to the database.

public partial class ProductRepository : IProductRepository

{

    public IQueryable<Product> SelectSatisfying(Specification<Product> specification)

    {

        return this.context.Products.Where(specification.IsSatisfied());

    }

}

Here we use the Entity Framework to select the Products that match a certain Product Specification. (The field "context" is the ObjectContext, in this case.) However, we could switch this for any data access technology that can leverage expression trees and retrieve similar results.

The next step is to implement the actual specification.

public class LowStockSpecification : Specification<Product>

{

    public LowStockSpecification(int lowStockThreshold)

    {

        this.LowStockThreshold = lowStockThreshold;

    }

 

    public int LowStockThreshold

    {

        get;

        private set;

    }

 

    public override Expression<Func<Product, bool>> IsSatisfied()

    {

        return p => p.UnitsInStock < this.LowStockThreshold;

    }

}

Evans says that specifications should be value objects, so I’ve taken that to heart and made this class immutable. This allows us to make some optimizations with specifications (caching the expression tree, introducing an IsSatisfiedBy by reusing the logic in the expression tree, etc.) if we would like.

This final code snippet shows how to leverage the specification and repository together.

public class ProductReorderingService

{

    private IProductRepository productRepository;

 

    public ProductReorderingService(IProductRepository productRepository)

    {

        this.productRepository = productRepository;

    }

 

    public void ReorderLowStockProducts()

    {

        LowStockSpecification spec = new LowStockSpecification(5);

        foreach (var p in this.productRepository.SelectSatisfying(spec))

        {

            // Reorder product

        }

    }

}

Composing Specifications

One property of specifications is that they can be combined to form more interesting predicates. This would allow our ProductRepository to support queries that involve multiple specification instances—for example, a filter that checks for units with low stock OR units whose stock is below their re-order level. The most common implementation I’ve seen of this requirement involves three new classes, AndSpecification<T>, OrSpecification<T>, and NotSpecification<T>. While it’s easy enough to implement these when all you worry about is IsSatisfiedBy (e.g. spec1.IsSatisfiedBy(o) && spec2.IsSatisfiedBy(o) for the AndSpecification<T>), it’s actually a bit tricky to do this with expressions.

Fortunately, it’s not impossible, and Colin Meek has it documented on his blog post about combining predicates in the Entity Framework, but the concepts apply more generally to any provider that can use expression trees. Be careful though; if you’re using the Entity Framework you will have to copy more code than you would with LINQ to SQL. I am not sure about LLBLGen Pro.

If you use the extension methods that Colin provides for AND’ing and OR’ing expression trees together, you’ll end up with these implementations of AndSpecification<T> and OrSpecification<T>:

public class AndSpecification<T> : Specification<T>

{

    private Specification<T> spec1;

    private Specification<T> spec2;

 

    public AndSpecification(Specification<T> spec1, Specification<T> spec2)

    {

        this.spec1 = spec1;

        this.spec2 = spec2;

    }

 

    public override Expression<Func<T, bool>> IsSatisfied()

    {

        return this.spec1.IsSatisfied().And(this.spec2.IsSatisfied());

    }

}

public class OrSpecification<T> : Specification<T>

{

    private Specification<T> spec1;

    private Specification<T> spec2;

 

    public OrSpecification(Specification<T> spec1, Specification<T> spec2)

    {

        this.spec1 = spec1;

        this.spec2 = spec2;

    }

 

    public override Expression<Func<T, bool>> IsSatisfied()

    {

        return this.spec1.IsSatisfied().Or(this.spec2.IsSatisfied());

    }

}

We’ll have to write the NotSpecification<T> ourselves, but this is not as involved as And and Or, even with the Entity Framework. We essentially take the body of the expression tree from the original specification and negate the result. Using the patterns you can read about in Colin’s blog post, we can use the following class as our NotSpecification<T>.

public class NotSpecification<T> : Specification<T>

{

    private Specification<T> originalSpec;

 

    public NotSpecification(Specification<T> originalSpec)

    {

        this.originalSpec = originalSpec;

    }

 

    public override Expression<Func<T, bool>> IsSatisfied()

    {

        Expression<Func<T, bool>> originalTree = this.originalSpec.IsSatisfied();

        return Expression.Lambda<Func<T, bool>>(

            Expression.Not(originalTree.Body),

            originalTree.Parameters.Single()

        );

    }

}

This is all well and good, but doesn’t this tie my domain to my infrastructure?

I think you can find arguments for both viewpoints. The specification pattern allows you to encapsulate a predicate to determine whether an object matches a condition. My opinion is whether that predicate is exposed as a method or an expression tree, the intent is preserved and there is one place where the criteria for a specification are checked. It does require you to use infrastructure that can utilize expression trees, but I would say that there is nothing about expression trees that tie them to the infrastructure layer directly. The details of the underlying data store have not leaked into the domain layer. If I had a provider that could use expression trees for XML or an object database store, then my domain layer would not change.

I enjoy learning about DDD and what other folks have done in this area. I’d love to hear your feedback.

Posted by David DeWinter under Design & Entity Framework & LINQ to SQL | 3 Comments »

Type Transparency in .NET 4 – #11

May 29th 2009

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!

Posted by David DeWinter under .NET4/VS2010 & Security Tips | No Comments »

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

May 28th 2009

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!

Posted by David DeWinter under .NET4/VS2010 & Security Tips | No Comments »

Next »