Whidbey’s Security Off Model


Although the v1.0 and v1.1 versions of CasPol provided a switch to disable the CLR’s security system, running without CAS enforcement on was never a scenario that we encouraged for obvious reasons.  The choice to disable security was a system wide switch that affected any managed application on any version of the runtime, and made running managed code incredibly unsafe.


As of Whidbey, you’ll find that the switch to turn security off no longer works as it used to.  If you run caspol -s off with beta 2 or later of Whidbey installed, you’ll see:



C:\WINDOWS\Microsoft.NET\Framework\v2.0.50215>CasPol.exe -s off
Microsoft (R) .NET Framework CasPol 2.0.50215.44
Copyright (C) Microsoft Corporation. All rights reserved.

CAS enforcement is being turned off temporarily. Press <ENTER> when you want to
restore the setting back on.

Security will then be disabled as long as the CasPol process remains active.  When CasPol is terminated, it returns security to the on state.  Even abruptly terminating the CasPol process will still return security to its on state. 


This works because the implementation of the internal security off flag has changed.  Instead of using a registry key to indicate the status of CLR security, we now use a named mutex which CasPol holds to indicate to the CLR that it should disable security.  Examining the the handles held by the CasPol process in a debugger will enable you to quickly identify this mutex:



0:000>!handle 0 4 Mutant
Handle 4c
  Name          \BaseNamedObjects\CLR_CASOFF_MUTEX
Handle 428
  Name          <none>
Handle 4a8
  Name          \BaseNamedObjects\ShimCacheMutex
Handle 624
  Name          <none>
4 handles of type Mutant

Since security is being disabled by this mutex, the CasPol process is resilient to being terminated unexpectedly, because Windows will just clean up the handle for CasPol when cleaning up the process.  Another side effect is that if the machine is rebooted, the security state will revert to on.


If we fire up the kernel debugger, we can take a look at the ACL of the mutex:



lkd> !object \BaseNamedObjects\CLR_CASOFF_MUTEX
Object: 85088d88  Type: (8679f040) Mutant
    ObjectHeader: 85088d70
    HandleCount: 1  PointerCount: 2
    Directory Object: e179f980  Name: CLR_CASOFF_MUTEX

lkd> dt nt!_OBJECT_HEADER 85088d70
   +0x000 PointerCount     : 2
   +0x004 HandleCount      : 1
   +0x004 NextToFree       : 0x00000001 
   +0x008 Type             : 0x8679f040 
   +0x00c NameInfoOffset   : 0x10 ”
   +0x00d HandleInfoOffset : 0 ”
   +0x00e QuotaInfoOffset  : 0 ”
   +0x00f Flags            : 0x20 ‘ ‘
   +0x010 ObjectCreateInfo : 0x853e3678 
   +0x010 QuotaBlockCharged : 0x853e3678 
   +0x014 SecurityDescriptor : 0xe2c57b2c 
   +0x018 Body             : _QUAD

lkd> ?? 0xe2c57b2c & ~0x7
unsigned int 0xe2c57b28

lkd> !sd e2c57b28 1
->Revision: 0x1
->Sbz1    : 0x0
->Control : 0x8004
            SE_DACL_PRESENT
            SE_SELF_RELATIVE
->Owner   : S-1-5-32-544 (Alias: BUILTIN\Administrators)
->Group   : S-1-5-21-2127521184-1604012920-1887927527-513 (Group: REDMOND\Domain Users)
->Dacl    : 
->Dacl    : ->AclRevision: 0x2
->Dacl    : ->Sbz1       : 0x0
->Dacl    : ->AclSize    : 0x34
->Dacl    : ->AceCount   : 0x2
->Dacl    : ->Sbz2       : 0x0
->Dacl    : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[0]: ->AceFlags: 0x0
->Dacl    : ->Ace[0]: ->AceSize: 0x18
->Dacl    : ->Ace[0]: ->Mask : 0x001f0001
->Dacl    : ->Ace[0]: ->SID: S-1-5-32-544 (Alias: BUILTIN\Administrators)

->Dacl    : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[1]: ->AceFlags: 0x0
->Dacl    : ->Ace[1]: ->AceSize: 0x14
->Dacl    : ->Ace[1]: ->Mask : 0x001f0001
->Dacl    : ->Ace[1]: ->SID: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)

->Sacl    :  is NULL



 


That shows that the mutex is created with an ACL that prevents anyone who isn’t an administrator from owning it.  And although Windows does not provide a way to prevent non-administrators from creating this mutex, internally the CLR will not respect the existence of the named mutex if it is abandoned or not owned by the BUILTIN\Administrators group.  This prevents a squatting attack where a malicious user could turn off security simply by creating this mutex himself.


One of the more interesting effects to note of disabling security with this mutex is that the v2.0 CLR will no longer respect the registry key used by older versions of the runtime, and those versions will not have their security disabled by the new CasPol switch.


Although there still is the ability to turn off security, the ability to turn it off permanently has been removed.  The new switch is useful mostly for debugging purposes, to establish if a problem you’re diagnosing is related to the security system or not.  The recommendation is still to avoid using this mechanism if at all possible.

Comments (17)

  1. Nicole Calinoiu says:

    I’ve been wondering about some of the pickier details of this for a while and, since the beta docs still don’t seem to have been updated to reflect this change, perhaps you might be willing to answer a few questions…?

    1. Is it intended that "caspol -s on" still declare its own success despite the fact that it does nothing? If not, shouldn’t the option either be eliminated or its result message be altered?

    2. Since the setter for the SecurityManager.SecurityEnabled property no longer does anything, shouldn’t it be obsoleted and/or throw a NotSupportedException?

    3. The beta 2 behaviour appears to have the switch acting at the user level rather than the system level. While I’m quite happy to see the most restrictive possible behaviour, I’m guessing that folks who disable CAS for troubleshooting purposes might run into a few problems with a user-level switch, so I’m wondering if this is really the intended behaviour.

  2. Sure,

    1. CasPol -s on needed to be kept around for backwards compatibility. We didn’t want to break any scripts that relied on calling CasPol -s on.

    2. For the same reason, we could not cause SecurityEnabled to throw an exception. That would break anyone who tried to toggle the property in the first place. Unfortunately the ObsoleteAttribute cannot be applied directly to the setter, and the getter is useful so we don’t want to obsolete the property as a whole.

    3. The behavior should be per-system. For instance, on my Windows 2003 machine, I turned security off on the console session, then connected via terminal server to a second session as a second user. The second session respsected the settings of the first one.

    -Shawn

  3. Nicole Calinoiu says:

    1. I figured that was the reason for keeping it around. However, given that it doesn’t actually do anything, the "Success" result message is more than a little misleading.

    2. Code that relies on being able to set the switch will be broken anyway. Wouldn’t it be more considerate to callers to either throw or remove the setter so that the problem is obvious rather than leaving folks to track down the silent failure after the fact?

    3. Interesting… While running as a non-admin on Windows XP, I disabled CAS from a cmd instance run as the local Administrator account. While CAS was disabled under the admin instance, it showed as enabled under the interactive account context. Repeating the same scenario except with CAS disabled from a cmd instance run under the interactive account promoted to admin membership via Aaron Margolis’ MakeMeAdmin script (http://blogs.msdn.com/aaron_margosis/archive/2005/03/11/394244.aspx) allowed the disabled state to be detected by code run under the interactive account but outside the admin cmd instance. Maybe an XP vs 2003 difference?

  4. Great feedback — I’ve filed tracking issues on the first two points and we’ll make sure to look at them.

    You’re right about the Windows XP thing, when I follow your steps I reproduce the problem. The correct behavior is to be a per-machine switch, so I’ve also filed a bug on that issue.

    Thanks for all the feedback!

    -Shawn

  5. Kevin Westhead says:

    I agree with Nicole wrt SecurityManager.SecurityEnabled: if the setter simply does nothing then it will be more difficult to debug code that relied on this property doing something. Removing the setter altogether seems like the best option to me. I’ve used this property in the past in unit tests to check that SecurityException was thrown from sensitive code when CAS was disabled. I take it that any such code will have to execute "caspol -s" now, or is there some other method for turning off CAS in code?

  6. Turning Off Code Access Security in .NET 2.0

  7. Nicole Calinoiu says:

    Many thanks for filing the bug reports. Do you happen to know if there’s already a documentation revision in the works for this stuff? It doesn’t seem quite fair to impose upon you for intended behaviour confirmation just because you’re the only one actually describing the changed behaviour. It’s even worse when you then shoulder the grunt work of generating the bug reports… 😉

  8. Kevin — correct, as of now, CasPol is the only shipping way to toggle the security switch.

    Nicole — if the information didn’t make it to the MSDN docs that shipped with beta 2, then unfortunately it won’t get doced until we RTM. No problem confirming what you see and filing bugs though 🙂

    -Shawn

  9. Last time we looked at how the Whidbey version of CasPol uses a mutex to indicate the state of the security…

  10. I’ve got just a few loose ends to tie up about our new security off behavior, and then we’ll move on…

  11. Brien says:

    caspol -s off turned security checks into no-ops under 1.1. for severely performance critical applications that run in a controlled environment, what configuration gives you the most raw speed?

  12. Brien — you should not be using caspol -s off for performance reasons on any framework. This leaves your machine wide open to attack for little performance gain.

    In v2.0 we’ve done a lot of work to make sure the security subsystem is even faster, so using it for this reason is even more unnecessary.

    -Shawn

  13. Brien says:

    Shawn,

    I understand your statement for a general purpose machine, or a desktop, but how is caspol -s a risk for a dedicated server used only for internal server applications?

    Brien

  14. The rules of performance work are measure, measure, measure. [http://blogs.msdn.com/ricom]. It is extremely unlikely that you’re in a situation where security is causing your application ot slow down appreciably. Have you demonstrated that security is the perf problem with your app? In general, trading security for performance is a very bad idea.

    -Shawn

  15. Brien says:

    Shawn,

    For background, over the next few months I’ll be building a system that needs to operate in real time and will be sensitive to sub-millisecond delays. It will be built and deployed under 1.1 but eventually ported to Whidbey when it is released. Absolute speed is a requirement. Hopefully, I’ve convinced you that my requirements fall in the "extremely unlikely" bucket.

    So, assuming I do everything I can to make my application code fast, I’m trying to understand what I can do to the CLR to juice it. Every few percent counts.

    Your generalizations make sense, but for my specific circumstances, please assume that speed equates to money and there is a non-linear cost benefit the faster you go.

    Thanks,

    Brien

  16. There’s a ton of new and enhanced security features coming with the v2.0 release of the CLR.&amp;nbsp; However,…

  17. There’s a ton of new and enhanced security features coming with the v2.0 release of the CLR.&amp;nbsp; However,…