Asserting for Permissions in .NET 4 – #18

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");

}

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.