Welcome to MSDN Blogs Sign in | Join | Help

Strong Name Bypass

Many managed applications start up slower than they really need to because of time spent verifying their strong name signatures.  For most of these applications, the strong name verification isn't buying the application anything - especially fully trusted desktop applications that are using C# as a better C++.

Since these applications were paying the cost of verifying their assemblies at load time, but were not receiving any benefit from that cost, we've made a change in .NET 3.5 SP1 which lets these applications bypass strong name signature verification.

Specifically, for any assembly which is:

  1. Fully signed (delay signed assemblies still require a skip verification entry)
  2. Fully trusted (without considering its strong name evidence)
  3. Loaded into a Fully trusted AppDomain
  4. Loaded from a location under the AppDomain's ApplicationBase

The CLR will no longer verify the assembly's strong name when it is loaded.

This provides an assembly load performance win for most full trust applications, however not all applications will want to have their fully trusted assemblies skip strong name verification.  If your application wants to re-enable strong name verification, it can add a .exe.config file with the following setting:

<configuration>
    <runtime>
        <bypassTrustedAppStrongNames enabled="false"/>
    </runtime>
</configuration>

Also, if a machine administrator wants to disable strong name bypass for all assemblies loaded on a particular computer, they can set the DWORD registry value named AllowStrongNameBypass to 0 under the HKLM\Software\Microsoft\.NETFramework key:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework]
"AllowStrongNameBypass"=dword:00000000

(The usual disclaimers apply about modifying the registry only if you know what you're doing)

As with other strong name configuration, on a 64 bit machine this registry setting will need to be set in both the 32 and 64 bit HKLM\Software keys.

For users who have the SDK installed, SN.exe also adds an option to query and update this key for you.  You can run SN -Pb [y|n] to allow or disable assemblies from bypassing strong name verification on your machine. (Again, using both a 32 and 64 bit SN.exe on 64 bit machines).  SN -Pb with no argument will display the current value of the setting.

Posted by shawnfa | 0 Comments
Filed under: , ,

FullTrust on the LocalIntranet

We released the first beta of .NET 3.5 SP 1 this morning, and it includes a change to the default grant set for applications launched from the LocalIntranet zone.  The quick summary is that as of .NET 3.5 SP1, applications run from a network share will receive a grant set of FullTrust by default, making them act the same as if they were launched off of your computer directly.  Since this is an issue that I know a lot of people run into, I hope that this change makes it easier to use and deploy managed applications.  For people who want to keep their machines working the same as they did for previous .NET Framework releases, you can set the DWORD registry value LegacyMyComputerZone to 1 in the HKLM\Software\Microsoft\.NETFramework registry key.

With the high-level summary out of the way, let's take a look under the hood to see what changed to make this possible :-)

The core of this change is a modification in how we assign evidence to network launched applications.  When we see an .exe launched directly off a network share, rather than giving that .exe Zone evidence of LocalInranet, we instead give the .exe Zone evidence of MyComputer.  This causes the .exe to match the default MyComputer code group rather than the LocalIntranet group, and in default CAS policy that code group grants FullTrust.   (This also explains why the opt-out registry value is named LegacyMyComputerZone)

In addition to the entry point .exe of the application, we'll also extend this MyComputer evidence to any assembly loaded from the same directory as the .exe.  So, if you place any managed .dll's immediately next to your .exe, those will also all be given FullTrust by default in .NET 3.5 SP1.

Since we're only including assemblies loaded from the same directory as the entry point application, things will just work for most applications, however more complicated programs that need to load assemblies from different subdirectories or other network shares may not see all of their assemblies get fully trusted by default.  For these more types of applications, ClickOnce deployment is the recommended way to elevate to FullTrust.

We've specifically disabled this change for any hosted applications.  So this means that if your program uses the CorBindToRuntime API to host the CLR, we won't start trusting assemblies it loads from a share.  Similarly, hosts like Internet Explorer will not start trusting controls that it loads into the browser.

To summarize the under the hood changes, assemblies which will now receive Zone evidence of MyComputer and therefore be fully trusted by default are:

  1. Any managed .exe which is launched directly from a network share
  2. Any assembly in that .exe's process which is loaded from the same directory as the .exe itself was.

Assemblies which will not see this change include:

  1. Assemblies loaded from a subdirectory of the share where the .exe was launched from
  2. Assemblies loaded from shares other than the one where the main .exe was launched
  3. Any assembly loaded on a machine with the LegacyMyComputer registry value set to 1
  4. Any assembly loaded into a CLR host, including assemblies loaded into Internet Explorer as controls.
  5. Any assembly loaded from shares by an application that was launched from the "real" MyComputer zone.
Posted by shawnfa | 0 Comments
Filed under: , , ,

Disabling the FIPS Algorithm Check

.NET 2.0 introduced a check for FIPS certified algorithms if your local security policy was configured to require them.  This resulted in algorithms which are not FIPS compliant (or implementations which were not FIPS certified) throwing an InvalidOperationException from their constructors.

In some cases this isn't a desirable behavior.  For instance, some applications need to use the MD5 hashing algorithm for compatibility with an older communication protocol or file format.  Prior to .NET 3.5, the AES algorithm was only available in an implementation which was not FIPS certified, and if you needed to use that algorithm the FIPS check could also block you.

To help these cases, we added a configuration file switch to .NET 2.0 SP 1 (and therefore .NET 3.5) which allows an application to say "I know what I'm doing, please don't enforce FIPS for me".  For these applications, they can setup a configuration file similar to:

<configuration>
    <runtime>
        <enforceFIPSPolicy enabled="false"/>
    </runtime>
</configuration>

Which will prevent the CLR from throwing InvalidOperationExceptions from the constructor of uncertified algorithms and implementations.

Posted by shawnfa | 0 Comments

CAS and Native Code

CAS is complicated enough to understand when all of the moving parts are written in managed code (and therefore have all the associated managed meta-information like grant sets, etc).  However, once native code comes into play things can get even more confusing.  Let's take a look at how CAS works when there's native code on the call stack.

For this discussion, lets assume we have a call stack (growing down) like so:

Managed code: M1
Managed code: M2
Native code: N1
Managed code: M3
Managed code: M4
AppDomain: AD

So in this example, M1 calls M2, which calls N1, which calls back to managed code M3 and M4.  All of the managed objects live in AppDomain AD.

Full Demands

Now lets consider what happens when M4 triggers a full stack walk for a demand.  In this case, the CLR essentially ignores the native code on the stack, and does a stack walk looking at M3, M2, M1, and AD.  Intuitively, this is done because the native code doesn't have a grant set associated with it, and therefore including it on a CAS stack walk wouldn't make much sense.

It's important to note however that the stack walk proceeds through N1, rather than stopping at it.  So in this case if M3 and M2 are fully trusted, but M1 is partial trust and M4 triggered a FullTrust demand, that demand would fail.

Stack walk modifiers like Assert continue to work just as you would expect as well, so it's perfectly legal for M2 to Assert FullTrust, which would make M4's demand succeed.

Link Demands

Link demands are much more interesting when native code gets involved.  In our example, imagine that managed method M3 has a LinkDemand for FullTrust on it.  Normally, LinkDemands are evaluated at JIT time against the caller of the method with the demand.  But in this case, the caller of M3 is native code which is not JITed (and doesn't have a grant set to evaluate against in any event).

The obvious solution then is to evaluate the LinkDemand against the last managed frame on the call stack before we transitioned to native code.  At the time we're JITing this method however, we only know that it's calling a native method -- we don't know what managed code that native code is going to turn around and call later on.  In this example, when M2 is being JITed we know that it may call N1, however we don't know that N1 will turn around and call M3 and therefore don't know that M3 has as a LinkDemand to evaluate against M2.

However, it turns out that we don't need to know what M3 is going to LinkDemand of M2.  Since M2 is calling N1, it must have UnmanagedCode permission, and since UnmanagedCode permission is never handed out without FullTrust, we can reason that M2 must be fully trusted.  If M2 is fully trusted, then it will satisfy any LinkDemand that M3 will require.

With this analysis, we could say that LinkDemands are implicitly satisfied by native code callers.  However, that may not be the effect that we want in all cases.  For instance, one common scenario might be to expose a managed object via COM Interop to a script.  (For instance, make a managed object available via COM to some JavaScript in a web page).

From the CLR's perspective, this script is just native code, so our reasoning would lead to any link demands on methods the script calls being satisfied.  However, we may not want the script to satisfy all link demands.  In order to solve this problem, the CLR treats calls to managed code from native via COM Interop differently.

If native code uses a COM interface to call a managed method protected with a LinkDemand, then that LinkDemand is evaluated against the AppDomain which the managed object lives in.

Let's go back to our example again, and see how these rules apply.  Let's suppose that N1 calls M3 through COM Interop, M3 has a LinkDemand for FullTrust, and the AppDomain AD is also fully trusted.  In this case, the call succeeds because the AppDomain's grant set satisfies M3's LinkDemand.

Now let's consider the case where this AppDomain is hosted by Internet Explorer, and therefore has only the Internet grant set.  When N1 calls into M3, we'll see that the object M3 is being called on lives in AppDomain AD, and that causes us to look up the grant set of that domain.  We then check M3's LinkDemand for FullTrust against the AppDomain's grant set of Internet.  Since the AppDomain's grant set does not satisfy the LinkDemand, we throw a SecurityException.  Note that this is true even if the last managed frame on the stack (M2) is fully trusted.

If we make one more change to the scenario, and have N1 call M3 via reverse P/Invoke we a different result.  Even though the AppDomain is partially trusted, since M3 was not invoked from COM Interop, we allow the call to succeed.

3 Rules for Native Code CAS Evaluation

That's a ton of complexity, but thankfully we can boil it down to three rules depending upon your scenario:

  1. If a full demand is done, native stack frames are ignored and the stack walk proceeds exactly as if there were only managed frames on the stack.
  2. If a link demand is done via COM Interop, the link demand is evaluated against the grant set of the AppDomain that the managed object lives in.
  3. If a link demand is done via reverse P/Invoke, the link demand is satisfied and the call succeeds.
Posted by shawnfa | 0 Comments
Filed under: , ,

Which Groups Does WindowsIdentity.Groups Return?

WindowsIdentity exposes a Groups property which returns a collection of IdentityReferences for the groups that a particular user is a member of.  However, if you look closely, you'll find that these returned groups won't necessarily include all of the groups that the user is a member of.

Under the covers, WindowsIdentity populates the groups collection by querying Windows for information on the groups that the user token is a member of.  However, before returning this list, the Groups property filters out some of the returned groups.

Specifically, any groups which were on the token for deny-only will not be returned in the Groups collection.  Similarly, a group which is the SE_GROUP_LOGON_ID will not be returned.

Generally, this is exactly the behavior you want.  For instance, if your application is going allow a specific action because the user is a member of a group, you don't want to allow it if the user is a member of the group for deny-only.

If you want to retrieve all of the groups however, there's not an easy built-in way for you to do this.  Instead, you'll have to P/Invoke to the GetTokenInformation API to retrieve the groups yourself.

It can be interesting to dump out the groups that specific users are part of -- here's a simple little snippet of code that does just that.  (And uses some of those fancy new C# 3.0 features to display them grouped by domain):

    public static void Main()

    {

        using (WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent())

        {               

            var groups = // Get all of the groups from our account, and translate them from IdentityReferences to NTAccounts  

                        from groupIdentity in currentIdentity.Groups

                        where groupIdentity.IsValidTargetType(typeof(NTAccount))

                        select groupIdentity.Translate(typeof(NTAccount)) as NTAccount into ntAccounts

 

                        // Sort the NTAccounts by their account name

                        let domainName = ntAccounts.GetDomainName()

                        let groupName = ntAccounts.GetAccountName()

                        orderby domainName

 

                        // Group the sorted accounts by the domain they belong to, and sort the grouped groups by domain name

                        group ntAccounts by domainName into domainGroups

                        orderby domainGroups.Key

                        select domainGroups;

 

            foreach (var domainGroups in groups)

            {

                Console.WriteLine("Groups from domain: {0}", domainGroups.Key);

 

                foreach (var group in domainGroups)

                {

                    Console.WriteLine("    {0}", group.GetAccountName());

                }

            }

        }

    }

 

    private static string GetDomainName(this NTAccount account)

    {

        string[] split = account.Value.Split('\\');

        return split.Length == 1 ? String.Empty : split[0];

    }

 

    private static string GetAccountName(this NTAccount account)

    {

        string[] split = account.Value.Split('\\');

        return split[split.Length - 1];

    }

Posted by shawnfa | 0 Comments
Filed under: ,

Manifested Controls Redux

Last year, I made a series of posts about a new feature available in the betas of .NET 3.5 which enabled you to specify declaratively the set of permissions that IE hosted managed controls should run with.  Since the betas there have been a couple of tweaks to the manifest control model, so those posts need a refresh.

Most notably, the Low Safety (Unrestricted) setting for the Permissions for Components with Manifests URL action is not a part of the final shipping Orcas bits.  Instead, the two options are:

  • High Safety - manifested controls can run with the permissions it requests, but only if those permissions are a subset of the permissions it would have been granted by CAS policy or if the manifests are signed by a trusted publisher.
  • Disabled - manifested controls may not run at all.

If you're using a machine that had one of the .NET 3.5 betas on it, the Low Safety option will still appear in your Internet Explorer dialog box, however the CLR will treat a value of Low Safety as if it were Disabled.

A lot of times when people look at this feature, they would like a full end-to-end sample of a control in a web page taking advantage of a manifest to elevate its permissions.  I've attached a ZIP file containing a sample control to this post.

In order to use this sample:

  1. Create a ManifestControl subdirectory in your wwwroot.
  2. Copy ManifestControl.control, ManifestControl.dll, ManifestControl.dll.manifest, and ManifestControl.html to the ManifestControl directory created in step 1.
  3. Ensure that your web server is setup to allow downloading of .dll, .control, and .dll.manifest files.
  4. Install ManifestControl.cer in your Trusted Publishers certificate store.
  5. Install ManifestControl.cer in your Trusted Root Certification Authorities certificate store. (Once you are done with the sample, the test certificate should be removed from both of these certificate stores)
  6. Navigate Internet Explorer to http://localhost/ManifestControl/ManifestControl.html
Posted by shawnfa | 0 Comments
Filed under: , , ,

Attachment(s): ManifestControl.zip

Transparency as Least Privilege

In my last post I mentioned that there is a better alternative to RequestRefuse for achieving least privilege. The tool I like to use for least privilege is actually the security transparency model available in v2.0+ of the CLR (and which became the basis of the Silverlight security model).

On the desktop CLR, transparent code cannot elevate the privileges of the call stack in any way.  Let's take a quick look at how this is enforced:

Uverifiable code - if a transparent method contains unverifiable code, the CLR injects a demand for SecurityPermission/UnmanagedCode.

Satisfy a LinkDemand - LinkDemands satisfied by a transparent method are converted into full demands

Use the SuppressUnmanagedCodeAttribute - this is really an extension of the LinkDemand rule.  the SuppressUnmanagedCodeAttribute converts the full demand for SecurityPermission/UnmanagedCode into a LinkDemand for the same permission.  However, since link demands satisfied by transparent code are converted into full demands, the net effect is that SuppressUnmanagedCodeAttribute becomes a no-op.

Assert permissions - Asserts are an explicit attempt to elevate the permissions of the call stack, and are therefore disallowed in transparent code.  They are not converted into full demands

Call critical code without going through a TreatAsSafe layer - the treat as safe layer is responsible for validating inputs and outputs of critical code, and transparent code must access critical code via this layer.  Attempts to call critical code or access critical data directly are disallowed.

This effectively means that fully trusted transparent code runs "as caller".  It won't cause any security demands to fail, however it won't cause them to succeed either. If the caller of the transparent code is allowed to do the security operation it will succeed, otherwise it fails.

What's interesting is that if we take this principal to the extreme, and have the entire call stack be transparent (such as in Silverlight), transparency transitions from running "as caller" to running "as application".  This is because each level in the transparency call chain passes the security demand up to its caller, until we hit the top of the stack -- and find the AppDomain.  Since all security demands end up going against the AppDomain's permission set, that permission set alone controls what may happen within the domain.

In this way, my fully trusted code will be fully trusted if it is run within a FullTrust domain.  However, that same code run within an AppDomain with the Internet permission set (perhaps if it's being used by a control in the browser), will effectively be running with Internet permissions.  Any demand for a permission outside of the Internet permission set will be passed along until it hits the AppDomain and fail.

Let's say that you're writing an application that you know will never need to interact with native code.  You'd normally do a RequestRefuse for UnmanagedCode permission on your application's assemblies to ensure that it's never accidentally satisfying an UnmanagedCode demand.  Instead of doing that, you can make sure that your application assemblies are entirely transparent and that they are run in a domain without UnmanagedCode permission -- perhaps via ClickOnce deployment.

This way you can use ClickOnce to explicitly control the grant set of the applicaiton, and transparency to ensure that you're not accidentally causing an elevation outside of that call stack, even if some of your application is installed in the GAC and fully trusted.

Posted by shawnfa | 0 Comments
Filed under: ,

Avoiding Assembly Level Declarative Security

I've written in the past about the three assembly level declarative security actions: RequestMinimum, RequestOptional, and RequestRefuse.  Although the CLR has supported these since v1.0, I tend to stay away from using them as much as I possibly can, and also recommend that others avoid them as well.  Let me go through each one individually:

RequestMinimum

RequestMinimum is the most common of the three, and in fact is mentioned by a FxCop rule and automatically inserted by the C# compiler in some cases.  There are several reasons I don't like to use this security action.

The first problem I have with RequestMinimum is a usability problem stemming from the fact that if your assembly is not granted its RequestMinimum permission set, the CLR will refuse to load it by throwing an exception.  If the assembly in question happens to be the entry point of my application, that means the user of my app ends up staring down an unhandled exception dialog (since my code never got loaded, and therefore never had a chance to handle this error more gracefully).  If my mother runs an app I give her and it throws a FileLoadException due to insufficient permissions, she's not going to have any idea what to do with that.

Even if the assembly is not the entry point assembly, gracefully handling failure to load due to RequestMinimum means that an application needs a try ... catch around every code path which could potentially lead to loading the assembly in question; that's not something that a lot of applications are setup to do.

The other problem I find with RequestMinimum is that in the case of writing a shared library it's very difficult to figure out what the correct grant set to request is.  Unless all of the APIs being exposed require the same set of permissions, having only a single RequestMinimum set doesn't help much.  For instance, an assembly like System.dll exposes hundreds of classes each with indivdual permission requirements varying from SecurityPermission/Execution to FullTrust.  If we decided to use the minimum grant set of any API in the assembly as the ReuqestMinimum, we've somewhat defeated the purpose of the security action; now I cannot be assured that the assembly loading means that it has the required permissions to work in all cases.  On the other hand, if I use the maximum grant set required, the assembly won't load even if an application was only intending to use APIs that would work in the grant set that the assembly is loaded into.

Finally, since security demands go against the entire call stack, even if the assembly in question has all the permissions that it needs to run doesn't mean that all assemblies and AppDomains on the call stack will have those permissions.  So even if an assembly does have its minimum grant set met, it doesn't have any guarantee that its APIs will all work without throwing a SecurityException.

RequestOptional

RequestOptional is probably the least commonly used assembly level security action, and with good reason.  This security action is somewhat poorly named, and people who use it for the first time often don't realize that it will actually remove permissions from your grant set.  In fact, I run across RequestOptional most commonly when helping someone debug a SecurityException that they can't figure out.  ("Why does this exception occur? All assemblies should be fully trusted!")

Even once you do understand the full effect of RequestOptional, the fact that it is confusingly named and that most people do not understand it is argument enough for me to stay away.  Code readability is extremely important, and if I can expect that the next person to read through my code will be confused by that RequestOptional I stuck on my assembly, that's not a good thing -- especially when it comes to security.

RequestRefuse

I expect this is the most controversial security action to take a stance against.  A good number of people probably use RequestRefuse as a least-privilege mechanism.  My problem with that is that you're stating "I don't want permissions A and B", however when someone comes along and introduces permission C you haven't refused it, and therefore you still get it.  Personally, I believe the CLR has other, much better, least-privilege mechanisms available -- and I prefer to use those whenever possible.  (Sounds like the topic of a future blog post :-) ).

Finally, and this should come as no surprise to any regular visitors, I'm a huge fan of the model where every sandboxed AppDomain has exactly two permission sets -- FullTrust and one sandbox grant set.  RequestRefuse (and RequestOptional) both detract from this model by creating multiple permission sets within an otherwise homogenous AppDomain.  By keeping AppDomains entirely homogenous, it's much easier to reason about security within the domain.  And, in my opinion, keeping the security model as simple as possible can only be goodness -- complexity can lead to mistakes in reasoning, which leads to security holes. 

So What Instead?

Some of the abilities promised by the assembly level declarative security actions seem to be very useful at first glance.  Notably the ability to specify a grant set that the code was tested to run in (which is what RequestMinimum seems to promise) and the ability to run with least privilege (via RequestRefuse).

For RequestMinimum, I think that ClickOnce is a far superior alternative for a variety of reasons.  Most importantly, ClickOnce gives the user of the application a nicer experience when the application does not by default meet the minimum grant set.  Rather than throwing an exception in the face of a non-developer, a friendly user interface is displayed which may even offer the ability to grant the application the ability to run.

Also, the grant set specified for a ClickOnce application applies to all of the assemblies in the application as well as the AppDomain  (hey -- it's my favorite homogenous model again!).  This means that you don't have to worry about the scenario where your assembly meets its minimum grant set, but some APIs still fail with SecurityExceptions because another assembly further up the call stack did not meet the minimum grant set.

That covers RequestMinimum -- but what about the least privilege promise of RequestRefuse?  As AB might say -- that's another show.

Posted by shawnfa | 0 Comments
Filed under: , , ,

CLR Inside Out: Digging into IDisposable

My third MSDN magazine article, Digging into IDisposable, appeared in this month's issue in the CLR Inside Out Column.  It's a bit of a departure from my usual security fare; this time looking at how to best handle writing class libraries that must manage resources.

Also in this month's issue, Kenny Kerr provides a good introduction to the new CNG APIs available on Vista.  Especially interesting is the code snippets he provides translating from CNG RSA keys to RSAParameters for use with RSACryptoServiceProvider.  (And for a quick rundown of the managed CNG classes Kenny mentions in the v3.5 framework, you can see the posts in my CNG category).

Posted by shawnfa | 0 Comments
Filed under: , ,

Silverlight Security Cheat Sheet

Over the last week we took a look at the new Silverlight security model.  When you're writing a Silverlight application though, there's a lot of information there that you may not want to wade through to get yourself unblocked.  Here's a quick cheat sheet highlighting the important points that you'll need to know when working with the Silverlight security model:

  • All applications written for Silverlight are security transparent.  This means that they cannot: [details]
    • Contain unverifiable code
    • Call native code directly
  • Silverlight applications can access public methods exposed by platform assemblies which are either: [details]
    • Security transparent (neither the defining type nor the method has any security attributes)
    • Security safe critical (the method has a SecuritySafeCriticalAttribute)
  • Silverlight applications may contain types which derive from: [details]
    • Other types defined in the application
    • Unsealed, public, security transparent types and interfaces defined by the platform
  • Silverlight applications may contain types which override virtual methods and implements interface methods which are: [details]
    • Defined in the application itself
    • Defined by the platform and are transparent or safe critical
Posted by shawnfa | 3 Comments
Filed under: ,

Silverlight Security III: Inheritance

Over the last few days we've looked at the basics of the CoreCLR security model in Silverlight, and how to tell which platform APIs are available for applications to call.  Let's wrap up this mini-series on CoreCLR security by looking at how the CoreCLR transparency model interacts with inheritance in the Silverlight platform.

From what we already know, we can define a logical ordering among the transparency levels:

  • Transparent (application / platform)
  • Safe critical (platform only)
  • Critical (platform only)

What's all this got to do with inheritance?  This ordering becomes very important when determining if a class is allowed to derive from a parent class.  A class may only derive from a type at its level in that ladder or higher.  It may never derive from a base class lower on the ladder.  This means, for instance, that critical types can derive from any other type while a transparent type may only derive from other transparent types.

We can apply this to types in a Silverlight application relatively easily.  Since all application code is transparent, it stands to reason that all of the types in application assemblies are also transparent.  Applying this rule, we see that application types may only derive from other application types or transparent platform types. (*)

In the same way that the security rules for method access are on top of the standard runtime access rules, the rules for inheritance are also in addition to the standard runtime inheritance rules.  So an application type may not derive from a sealed transparent type in a platform assembly for instance, since the CLR does not allow derivation from sealed types.

One of the more interesting things to do once you've derived from a type is to start overriding virtual methods (or implementing interface methods).  Not surprisingly, we have security checks for these overrides as well which are also based upon the transparency model.  When talking about overriding methods, it's convenient to group the different security groups into two accessibility levels:

  1. Transparent and safe critical code
  2. Critical code

When grouped this way, we see that transparent code has access to everything in the first level while only critical (including safe critical) code has access to the second level.

With that in mind, the simple rule is that a method may only be overridden by another method in the same accessibility level.  So a Silverlight application may override any virtual from within their application, as well as any transparent or safe critical platform virtuals.  (Assuming, of course, that the application type was allowed to derive from the platform type).

The same rule applies when it comes to interface implementations.  A Silverlight application may implement all methods on any interface defined by the application itself.  If the interface is supplied by a platform assembly, then the application my only implement methods which are either transparent or safe critical.  Practically speaking this means that Silverlight applications may not implement any interface which contains any critical members.

We can summarize the CoreCLR security inheritance rules for applications into three quick rules:

  1. Types may only derive from base types that are transparent.
  2. Only transparent or safe critical methods may be overridden
  3. Only transparent or safe critical interface methods may be implemented

 (*) This true in 99.9% case.  There is another rule about the visibility of the default constructor of a class (which we'll get into next week when we dig deeper into the security model), which also requires that the base class' default constructor (if it has one), must be transparent as well.  Practically speaking, you're not generally going to find interesting transparent types in the platform which do not also have transparent default constructors, so this rule doesn't normally come into play.

Posted by shawnfa | 2 Comments
Filed under: ,

Silverlight Security II: What Makes a Method Critical

Yesterday we talked about the CoreCLR security model, and how it is built upon the transparency model introduced in the v2.0 .NET Framework.  The quick summary was that all Silverlight application code is transparent, and transparent code may only call other transparent code and safe critical code.  With that in mind, lets take a look at figuring out how can tell which platform APIs fall into each category ... allowing us to know which APIs our applications are allowed to call.

In Silverlight, by default all code is transparent.  (This is different from the desktop CLR, where all code is critical by default).  For application code, that's the end of the story -- as we said yesterday, a fundamental tenant of the CoreCLR security model is that all application code is transparent.

Platform code can be either transparent, safe critical, or critical however.  CoreCLR will detect platform code by knowing where the assembly is loaded from (platform assemblies must be loaded from the Silverlight installation directory), and also by checking the assembly's public key.  Only assemblies signed with specific Microsoft's public keys will be considered platform assemblies; because of this public key requirement, no Silverlight application code can ever be considered a platform assembly.

We can tell if a method is security critical or transparent by looking at the attributes on the method in question (and on the class that contains the method).  To simplify this discussion, I'll talk directly about attributes on methods, however if the class containing the method has one of the security attributes, then this attribute will apply to every method within the class.

If a method in a platform assembly is marked with the SecurityCriticalAttribute, this means that it contains critical code.  Even if the method is public, no application code can call it since transparent code may never directly call into critical code.  Any attempt to break this rule will lead to a MethodAccessException at runtime.

For example, the constructor for FileStream in the Silverlight 1.1 alpha bits (snipped below) is security critical which we can see from the SecurityCriticalAttribute on line 5:

    1   .method public hidebysig specialname rtspecialname 
    2           instance void  .ctor(string path,
    3                                valuetype System.IO.FileMode mode) cil managed
    4   {
    5     .custom instance void System.Security.SecurityCriticalAttribute::.ctor() = ( 01 00 00 00 ) 
    6 
    7     // ...
    8   }

Similarly, every method in the Marshal class is also critical, since the entire class is marked with the SecurityCriticalAttribute on line 4:

    1 .class public abstract auto ansi sealed beforefieldinit System.Runtime.InteropServices.Marshal
    2        extends System.Object
    3 {
    4   .custom instance void System.Security.SecurityCriticalAttribute::.ctor() = ( 01 00 00 00 ) 
    5 
    6   // ...
    7 } // end of class System.Runtime.InteropServices.Marshal

 

A method in a platform assembly marked with the SecuritySafeCriticalAttribute is, of course, safe critical.  Application code may call into these methods, since transparent code may call safe critical code.  And since safe critical code is critical, it can then turn around and call critical APIs on behalf of the application.

One example of a safe critical API is the IsolatedStorageFileStream.Write, which we can see on line 6 of its disassembly:

    1   .method public hidebysig virtual instance void 
    2           Write(uint8[] buffer,
    3                 int32 offset,
    4                 int32 count) cil managed
    5   {
    6     .custom instance void System.Security.SecuritySafeCriticalAttribute::.ctor() = ( 01 00 00 00 ) 
    7 
    8     // ...
    9   }

 

An interesting note is that the SecuritySafeCriticalAttribute is really just a combination of the desktop framework's SecurityCriticalAttribute and SecurityTreatAsSafeAttribute.  If you're familiar with the desktop CLR's transparency model, then you'll know that the TreatAsSafe attribute is implied for all public critical methods.  This is not true in the CoreCLR security model for Silverlight -- instead, safe critical methods must be explicitly marked.

Since there are no more implicit treat as safe methods, the need to explicitly annotate a method with both the SecurityCritical and the SecurityTreatAsSafe attributes became much more common, so SecuritySafeCritical was introduced as a shortcut; it saves time when typing and also reduces metadata size.  However, if you are familiar with the desktop CLR transparency model, it's safe to read "SecuritySafeCritical" as "SecurityCritical, SecurityTreatAsSafe" when reasoning about an API set.

If a method has neither the SecurityCritical attribute nor the SecuritySafeCritical attribute applied to it, then the method must be transparent (since we said above that all code is transparent by default).  If this method is visible to the application code, that means that the application can call into it because transparent code is always allowed to call other transparent code.

Incidentally, if a Silverlight application tries to be tricky and mark itself with one of the SecurityCritical or SecuritySafeCritical attributes nothing will happen.  The CLR knows that application code must be transparent, so it doesn't even bother to look for those two attributes when examining a method from a non-platform assembly.  Instead, the method with the disallowed attributes will continue to be treated as transparent, and if they try to do anything that is not allowed from a transparent method, an exception will be thrown.

Finally, it's important to note that these rules do not replace the standard public / private / protected / internal access rules for the runtime; instead they supplement them.  So application code may not call an internal method in a platform assembly, even if the method is transparent. 

To summarize:

  Security Attribute Means Directly callable by application code
(if the method is visible)
Application Code - Transparent Yes
Platform None Transparent Yes
Platform SecuritySafeCritical Safe critical Yes
Platform SecurityCritical Critical No

 Next time, we'll look at how this security model interacts with inheritance.

Posted by shawnfa | 10 Comments
Filed under: ,

The Silverlight Security Model

Silverlight

You may have heard a thing or two last week about a little project we like to call Silverlight, including a small version of the CLR that will run in the browser on both Windows and the Mac.  (If you haven't grabbed the Silverlight v1.1 alpha bits yet, I highly recommend it -- as well as grabbing the SDK and heading over to the quickstarts site and forums so that you can try it out for yourself).

Since the v1.1 release of Silverlight includes a slimmed down version of the CLR, you might be wondering what the managed security story for Silverlight is and how it compares to CAS on the desktop version of the CLR.

The good news for everyone who's spent hours deciphering cryptic caspol commands is that Silverlight removes CAS entirely.  Instead, the security model is based around an enhanced version of the v2.0 transparency model.  When I say CAS is gone, I mean it's really gone --  there are no permissions, no policy levels, and no stack walks in CoreCLR.  The System.Security namespace is pretty barren indeed!  (But wait -- why is SecurityPermission still exposed from mscorlib then?  It turns out that the C# compiler will emit a RequestMinimum for SkipVerification if your assembly contains unverifiable code.  Since we need to be able to use the existing C# compiler to create Silverlight assemblies, we had to keep that one permission in the public surface area).

In place of CAS, the CoreCLR security model can be boiled down to the following two statements:

  1. All user code that runs on CoreCLR is entirely transparent
  2. Platform code may contain both transparent and critical code; it is responsible for providing a gateway for transparent code to safely access various system services.

Which means that the essence of the CoreCLR security model is that Silverlight applications may not contain unverifiable code and may only call transparent or safe critical APIs exposed from the platform.  Let's dig a little deeper into this.

Since transparency forms the, ahem, core of the CoreCLR security model, let's take a minute to refresh the basics of what transparency means, starting with the model we already know on the v2.0 framework.  Transparent code is code which cannot perform any actions that would elevate the permissions of the call stack.  Essentially, security transparent code cannot cause any security check to succeed (although it can cause them to fail); so you can think of it as running with the permissions of its caller.  The opposite of transparent code is critical code, and assemblies may contain a combination of transparent and critical code.  Individual methods may only be transparent or critical however; they cannot contain a mix of both.

The specific restrictions placed upon security transparent code is that it may not:

  1. Satisfy a LinkDemand
  2. Perform a CAS Assert
  3. Contain unverifiable code
  4. Call native code via a P/Invoke or COM Interop
  5. Access critical code or data which does not specifically allow it.

So let's start to translate this to the Silverlight world.  We know that there's no such thing as CAS in Silverlight, so the first two restrictions don't make sense there.  (Without CAS there are no permissions to assert or do a demand for, even just a LinkDemand).  On the desktop CLR, the next two restrictions are enforced by injecting a demand for UnmanagedCode.  Since we don't have a concept of demands in Silverlight, that enforcement mechanism isn't appropriate, and instead we just throw a MethodAccessException if transparent code tries to violate one of these rules.

The last rule is the most interesting in the group.  If transparent code attempts to directly call critical code, a MethodAccessException will be thrown.  However, most of the interesting system services are required to be implemented in critical code (for instance, in order to access the file system, we need to P/Invoke to the operating system's file IO APIs.  Since calling native code is only available to critical code, any APIs which write to the file system must therefore be critical).  If that's the case, how does a Silverlight application access any of these interesting services?

This is accomplished by having an intermediate layer of safe critical code that act as gate keepers for the critical methods, ensuring that it is safe for the transparent code to perform the operation that it is asking to do.  These safe critical APIs may do various checks before passing control to a critical API, including validating incoming parameters and ensuring that the application state is acceptable for this call to continue.  Since safe critical methods are in fact critical code, once they ensure that the caller is allowed to proceed they are allowed to invoke a critical method on the caller's behalf.

For example, earlier I mentioned that file IO must be implemented as critical code.  Being able to have some form of persistent storage is useful for an application however, so we'll need a safe critical layer that transparent code can call, and after ensuring that the call is valid will pass on requests to the critical file IO layer.  In Silverlight, this safe critical layer is IsolatedStorage.   When a Silverlight application calls IsolatedStorage, the IsolatedStorage APIs will validate the request by making sure that the Silverlight application is requesting a valid file and is not over its quota.  Then it calls the critical file APIs to perform the actual work of reading or writing to disk.

You can think of this as being very similar to an operating system model.  In that analogy:

Operating System CoreCLR IsolatedStorage Example
User mode code Transparent code Silverlight application
System call Safe critical API System.IO.IsolatedStorage
Kernel code Critical API System.IO.FileStream

 In the same way that applications running on Windows or the Mac cannot call directly into the kernel of the operating system without passing through a system call layer, Silverlight applications cannot directly call critical code without passing through a safe critical layer.  In the file IO example, a Silverlight application may not directly write to disk without first passing through the IsolatedStorage layer.

That's a lot of information -- but thankfully it can be summed up very easily:  The CoreCLR security model in Silverlight is that all Silverlight applications consist of entirely security transparent code, and this security transparent code may only call other transparent code or safe critical code.

Over the next few posts, we'll explore a few more details of the security model, such as how to tell what code is transparent and critical and some new rules regarding inheritance.

Posted by shawnfa | 12 Comments
Filed under: ,

Bypassing the Authenticode Signature Check on Startup

A while back I wrote about the performance penalty of loading an assembly with an Authenticode signature.  The CLR will attempt to verify the signature at load time to generate Publisher evidence for the assembly.  However, by default most applications don't need Publisher evidence.  Standard CAS policy does not rely on the PublisherMembershipCondition, so unless your application will run on a machine with custom CAS policy modifications, or is intending on satisfying demands for PublisherIdentityPermission (taking into mind that FullTrust means FullTrust in v2.0 of the framework), this is wasted startup cost that could be done without.

Obviously if you know your application doesn't need the Publisher evidence, you won't want to pay the cost of having the signature verified.  If you download the Orcas Beta 1 bits, you'll be able to take advantage of a feature in the runtime that disables this signature verification.  Your application can now opt out of Authenticode signature verification; which will mean that time to load each assembly will improve (therefore leading to an improvement in startup time if your entry point assembly has an Authenticode signature).  The tradeoff of course is that assemblies will no longer receive Publisher evidence or PublisherIdentityPermission.  Applications which wish to take advantage of this can add the following line to their .exe.config file:

<configuration>
    <runtime>
        <generatePublisherEvidence enabled="false"/>
    </runtime>
</configuration>

Which will prevent the CLR from verifying the Authenticode signatures of any assembly loaded by the application. 

Posted by shawnfa | 0 Comments
Filed under: , ,

Loading an Assembly as a Byte Array

One of the various ways that you can load an assembly is by supplying the raw bytes of an assembly as a byte array.  The security identity of an assembly loaded this way turns out to be different than if you were to load the same assembly by name or by file.  In the case that you load an assembly with its name or its file name, we generate all the evidence that you normally think of -- such as Zone, Site, Url, StrongName, Publisher, etc.

Now, when we've loaded via a byte array, a lot of that information is not available to us.  Specifically, we don't know the location based evidence for the assembly, like Zone, Site, and Url.  Since the standard security policy makes nearly all of its trust decisions based upon this location evidence, there's a bit of problem when attempting to figure out what grant set this assembly should get.

What ends up happening is that the CLR will consider the new assembly as having the same security identity of the assembly that loaded it.  Unless the new assembly is loaded with explicit evidence, we will give it the same evidence as the assembly doing the loading.  This is analogous to the Reflection.Emit scenario, and it makes a lot of sense in the case that this extra assembly is really an extension of the loading assembly, such as when the byte array was stored as a resource in the loading assembly.

The scenario where you really need to be aware of this is when you're a fully trusted assembly which is loading a byte array containing a lower trust assembly.  In that case, it's very likely that you do not want the default behavior of letting the byte array have the same security identity as you.  Instead, the Assembly.Load method that takes both a byte array and Evidence should be used.  This will let you supply the specific security identity of the lower trust byte array to use when resolving policy for the assembly.

Posted by shawnfa | 1 Comments
Filed under: , ,
More Posts Next page »
 
Page view tracker