Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C++/CLI

A security neutral mutex class for the managed platform

3.93/5 (6 votes)
5 May 20064 min read 1   174  
An article on a security neutral mutex class that can be used on any managed platform.

Introduction

This article intends to introduce you to a new managed Mutex class, MutexSecurityNeutral. The existing .NET framework provided System.Threading.Mutex class has the limitation of using only one security context, the one under which it is created. Once it is created under a specific security context, it can’t be opened/created under a different user/security context. Here is a workaround for this problem - the MutexSecurityNeutral class.

The basic idea is to create a Win32 Kernel mutex object by specifying the security descriptor with a null DACL. A null DACL in the security descriptor means “Everyone all access”. Well, I admit the fact that creating a Kernel object with a null DACL is a possible entry point for a DoS (Denial of Service) attack. It is solely up to you and the security criticality of your system to decide upon this.

Background

A short time ago, one of my friends came across an issue of getting an access-denied error while creating a mutex object in a web application. This ASP.NET – C# web application was on Windows authentication and Impersonation set to true. The same code worked well if Impersonation was set to false.

Rationale behind the issue

When an ASP.NET application runs under Windows authentication with Impersonation set to true, the ASP.NET worker process, aspnet_wp.exe, will be running under the user context of the logged on user. But if Impersonation is set to false, then the user context impersonated will always be the system user ASPNET.

So in a Windows authentication scenario with Impersonation set to true, when the first request comes from a user, say, domain1\user1, the mutex object will get created under the context of domain1\user1. If the next request (to inetinfo.exe, and then to aspnet_wp.exe) is from the same user, then there is no problem as the context is the same. But if the request is from a different user, say, domain1\user2, then the issue elevates. In this case, the .aspx page will be running under the context of domain1\user2. Then, the mutex object creation will fail as the security descriptor associated with the already existing mutex object is of domain\user1. A detailed elucidation of IIS, ASP.NET, and the Windows security model is outside the scope of this document. There are many articles available on CP on this topic. Also, I am in the processes of compiling a series of articles on the Windows security model and the Internet. Will keep this area updated, once it is done.

Even though .NET 2.0 comes with a set of new Win32 security model wrapper classes like System.Security.AccessControl.MutexSecurity, the object model does not allow to add a null ACE into the DACL. One of the design goals was to prevent users from creating a security vulnerable Kernel object. Here comes the solution for this, a security neutral managed type, MutexSecurityNeutral. This can be created under any user context as the security descriptor is initialized with a null DACL.

As an alternative, we can use the .NET lock block as well, if there is no inter-process synchronization required.

Using the code

The class MutexSecurityNeutral can be used just like the .NET Mutex class. Give a reference to the MutexSecurityNeutral.dll in your project. Given below is a C# sample code which synchronizes a shared resource:

C#
SecUtil.MutexSecurityNeutral mutexsecurityneutral =
         new SecUtil.MutexSecurityNeutral("yourmutexname");

mutexsecurityneutral.WaitOne();
nSharedResource++;
mutexsecurityneutral.Done();

The MutexSecurityNeutral implementation is shown below:

MC++
namespace SecUtil
{
    public __gc class MutexSecurityNeutral
    {

    private:

        CMutexSecurityNeutralUnmanaged* 
               m_CMutexSecurityNeutralUnmanaged;
        String __gc* m_MutexName;

    public:

        MutexSecurityNeutral(String __gc* MutexName): 
                              m_MutexName(MutexName){    
            m_CMutexSecurityNeutralUnmanaged = NULL;
        }
        ~MutexSecurityNeutral(){
            delete m_CMutexSecurityNeutralUnmanaged;
        }

        bool WaitOne(){                
            char __nogc* szMutexname = 
               static_cast<CHAR *>(Marshal::StringToHGlobalAnsi(
               m_MutexName).ToPointer());
            m_CMutexSecurityNeutralUnmanaged =  new                
              CMutexSecurityNeutralUnmanaged(szMutexname);
            bool  bRtn= m_CMutexSecurityNeutralUnmanaged->WaitOne();
            Marshal::FreeHGlobal( IntPtr((void*)szMutexname));
            return bRtn;        

        } bool
            Done(){ returnm_CMutexSecurityNeutralUnmanaged->Done(); 
        }
    };
}

The SecurityNeutralUnmanaged has two methods:

  • WaitOne()

    In the wait() method, it creates an object of CMutexSecurityNeutralUnmanaged, and passes the mutex name to the unmanaged wait() method.

  • Done()

    Makes a call to the unmanaged CMutexSecurityNeutralUnmanaged->Done() method. This CMutexSecurityNeutralUnmanaged is declared in MutexSecurityNeutral.h.

MC++
class CMutexSecurityNeutralUnmanaged
{

private:
    const char* m_szMutexName;
    HANDLE m_hMutex;

public:
    CMutexSecurityNeutralUnmanaged(const char*  
              szMutexName):m_szMutexName(szMutexName){
        m_hMutex = NULL;
    }

    ~CMutexSecurityNeutralUnmanaged(){
    }

     bool WaitOne(){
        bool rtn = false;
        SECURITY_DESCRIPTOR sd;
        SECURITY_ATTRIBUTES sa;
        try{
            if (!InitializeSecurityDescriptor(&sd, 
                         SECURITY_DESCRIPTOR_REVISION))
                return FALSE;            
            if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE))
                return FALSE;

            sa.nLength = sizeof(sa);
            sa.lpSecurityDescriptor = &sd;
            sa.bInheritHandle = FALSE;
            m_hMutex = CreateMutex(&sa, true, m_szMutexName);
            WaitForSingleObject( m_hMutex, 10000L);
            
            rtn = true;
        }
        catch(...){
            rtn = false;
        }
        return rtn;
     }

     bool Done(){
         bool rtn = false;
         try{
            ReleaseMutex(m_hMutex);
            CloseHandle(m_hMutex);
            rtn = true;
        }
        catch(...){
            rtn = false;
        }
        return rtn;
     }

};

The SecurityNeutralUnmanaged class has two methods:

  • WaitOne()

    This method creates the SECURITY_DESCRIPTOR variable and associates a null DACL to it by calling SetSecurityDescriptorDacl. Then, it calls CreateMutex to create the mutex object, and WaitForSingleObject waits on the mutex handle.

  • Done()

    This method just releases the mutex and closes the handle.

Summary

All Win32 Kernel objects are associated with a particular user/security context. Thus, in the case of a Win32 mutex object which is created under a particular user security context, it can’t be recreated/opened under a different user context. If I rephrase it, these Kernel objects have a user affinity. In a desktop application scenario, it may not be a concern as all programs generally run under the logged on user context unless otherwise it is impersonated programmatically. But if we are using mutex like Kernel objects in a web application scenario, with Impersonation set to true, things are different. This does make trouble.

So, as a web developer, what is the impact on you because of this Kernel object user affinity? .NET provides (both 1.1 and 2.0) the System.Threading.Mutex class, but it can not be used under a web application with Windows Authentication and Impersonation set to true. The object creation will fail with an Access-denied error. As an alternative, you can use this MutexSecurityNeutral class, but it has the security vulnerability loop hole of using a null DACL. I repeat, it is solely up to you to decide whether to use this class or not.

Revision History

  • May 05, 2006 - Version 1.0 - first release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here