Security Off Wrap Up


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


System.Security.SecurityManager.SecurityEnabled


As part of the work to move to the new security off model, we’ve removed the ability to turn off security pragmatically through the SecurityEnabled property of the SecurityManager object.  The getter will still tell you the current state of the security system, however the setter was turned into a no-op.


By making the decision to make the property setter into a no-op, the symptom that a broken application will see is that a SecurityException will be thrown in a location that was likely not built with handling that exception in mind.  As a temporary fix, while running the application, you can also run CasPol in the background to create the environment that the application expects to run in.  Of course, as a long term solution, the application should be modified to work with the security system on.  We could have chosen to throw a NotImplementedException whenever the setter was accessed, but breaking in that way prevents the caspol workaround since the application will still throw an unhandled exception. 


Security On For Win9x


Last time I showed how you could use Windows NT security to prevent security from ever being turned off.  Of course using Windows NT’s security model requires, well, Windows NT.  To achieve the same effect on Windows 98 or Windows ME we’ll have to take a different route.


The goal is still the same — prevent CasPol from acquiring the security off mutex while keeping that object in a state that the CLR doesn’t recognize it as valid for turning off security.  Since we can’t acquire an ACL on the mutex, we’ll need to come up with another way to prevent it from being acquired in the first place.  One way falls out from the fact that in Windows mutexes, events, semaphores, waitable timers, job, and file mapping objects all share the same namespace.  This means that no two of those types of objects can have the same name.  So, if we pick one of those available on Win9x … say an event, we can prevent CasPol from creating a mutex with the same name.  And since we won’t be holding a mutex with the security off name, the CLR won’t disable security.



int _tmain()
{
    // create a security off event
    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, _T(“CLR_CASOFF_MUTEX”));
    if(hEvent == NULL)
    {
        std::cout << “Could not acquire event, security may already be off.” << std::endl;
        return 0;
    }
    
    // wait to unlock
    std::cout << “Security is locked on.  Press any key to unlock.” << std::endl;
    _getch();

    CloseHandle(hEvent);
    return 0;
}

Comments (4)

  1. Nicole Calinoiu says:

    On the topic of the no-op SecurityManager.SecurityEnabled setter…

    Probably not a big surprise, but I still don’t like the silent failure approach. Perhaps the following would be an acceptable compromise: throw an exception from the setter iff the target state is not the same as the current state. For example, when attempting to disable CAS via the setter, it would effectively be a no-op if CAS is already disabled, but it would throw if the mutex doesn’t already exist. This would allow early detection of the operation failure as well as allowing folks to avoid code changes by ensuring that the mutex is created before their applications attempt to disable CAS via SecurityManager.SecurityEnabled.

  2. shawnfa says:

    Not a surprise at all 🙂

    Your solution is another alternative we can take a look at. Its main problem is that the exception can be thrown or not depending on system state at the time the property was set. And there’s an inherent race condition between when we check the state and decide to throw / not throw the exception. Debuggability becomes a problem, since a repro might be difficult to get.

    The state we’re in now is probably not the state we’ll ship in; the problem is finding a good solution to a difficult to solve properly problem.

    -Shawn

  3. Nicole Calinoiu says:

    Good to know that the implementation isn’t yet frozen. While you guys are mulling things over, here are a couple of the scenarios that got me to point of preferring the throw over the silent failure despite the potential race condition…

    The most common "acceptable" CAS-toggling scenario that is likely to be affected by this change is disabling of CAS by "high performance" applications. Since this should only be done on an appropriately isolated system, it is not unreasonable to assume that all code in most applications of this sort would be locally installed and run with full trust under default policy. Therefore, in most such situations, the silent failure to disable CAS would not cause security exceptions to start appearing. Instead, the main symptoms would be related to performance (unless the the new "full trust scenario" performance optimizations provide equivalent performance gains to disabling CAS ;)), and these would likely manifest very differently between applications and systems. Attempting to track down the source of such problems would likely be incredibly time-consuming for all parties, including end-clients who have no idea that CAS was ever disabled in the first place. This scenario might also cause some bad press for v.2 performance if folks start complaining about such problems before discovering the changed behaviour (assuming they ever do).

    Then there’s the other side of things: applications that disable CAS inappropriately. This scenario (which may be quite a bit more frequent than any of us might like to believe) has another set of interesting problems. The application that disables CAS is likely to be fully trusted since the required SecurityPermissionControlPolicy permission in only granted to fully trusted code under default policy. This means that the failure to disable CAS likely won’t affect the application that attempted to disable CAS. Instead, it will cause security and policy exceptions to start showing up in other applications that ran without such "problems" under v.1. Given that the original failure in the CAS-toggling application was silent, imagine the pain of trying to identify the problem from exceptions in other applications…

    (BTW, there might also have potential race condition problems in v.1 if enabling CAS via the setter had actually worked as expected. 😉 As things stand, it looks like there might still be some potential race condition problems in the persistence code.)

  4. shawnfa says:

    Well, the thinking is that our perf work has paid off, and that performance is not a valid reason to disable security any more. I’ll forward your post to the rest of the security team though, and we’ll definately use it as a data point when coming up with our final decision. Thanks again for all the feedback.

    -Shawn