Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mutex creation hangs while using impersonation

While testing an application, I ran a into strange behaviour. Some of the tests use impersonation to run code as a different user, but they would always hang, never complete.

After some investigation, the problem was narrowed down to the use of mutexes. Originally, we used our own impersonation code based on the MSDN documentation, but even when using the SimpleImpersonation library the problem still remains. Here is a minimal example to reproduce the problem:

using (Impersonation.LogonUser(DOMAIN, USER, PASSWORD, LogonType.Interactive))
{
    Console.WriteLine("Impersonated");
    bool mine;
    using (new Mutex(true, "Mutex", out mine))
    {
        if (!mine)
            throw new Exception("Couldn't get mutex");
        Console.WriteLine("Got mutex");
    }
}

Console.WriteLine("Finished");

This never finishes, it's stuck on the line with the mutex creation. The documentation states that it should either throw an exception or return something, but does not mention blocking.

Some other observations, which might or might not be related:

  • if we "impersonate" the current user, it returns immediately
  • if we run the actual application and start another instance as a different user, everything works as intended

Probably there's something going on with underlying system resources, but we couldn't figure it out. How to make this work?

UPDATE: As per Hans' comment, I tried disabling Windows Defender, it didn't help. Here's a stacktrace of the place where it's hanging:

    ntdll.dll!_NtWaitForSingleObject@12()
    KernelBase.dll!_WaitForSingleObjectEx@12()
    mscorlib.ni.dll!719c1867()
    [Frames below may be incorrect and/or missing, native debugger attempting to walk managed call stack]   
    mscorlib.ni.dll!719c1852()
    [Managed to Native Transition]  
    mscorlib.dll!System.Threading.Mutex.CreateMutexHandle(bool initiallyOwned, string name, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES securityAttribute, out Microsoft.Win32.SafeHandles.SafeWaitHandle mutexHandle)
        mscorlib.dll!System.Threading.Mutex.MutexTryCodeHelper.MutexTryCode(object userData)
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    mscorlib.dll!System.Threading.Mutex.CreateMutexWithGuaranteedCleanup(bool initiallyOwned, string name, out bool createdNew, Microsoft.Win32.Win32Native.SECURITY_ATTRIBUTES secAttrs)   
    mscorlib.dll!System.Threading.Mutex.Mutex(bool initiallyOwned, string name, out bool createdNew, System.Security.AccessControl.MutexSecurity mutexSecurity) 
    mscorlib.dll!System.Threading.Mutex.Mutex(bool initiallyOwned, string name, out bool createdNew)    
    MutexImpersonationTest.exe!MutexImpersonationTest.Program.Main(string[] args) Line 16   
like image 225
molnarm Avatar asked Apr 13 '16 07:04

molnarm


1 Answers

It looks like the code to acquire a Mutex is getting stuck in an infinite loop, and in my tests, it's pegging one core at 100% within the call to new Mutex(...).

The reason for this seems to be that the framework code first tries calling the Win32 CreateMutex, if that fails with an "Access Denied" error, tries calling OpenMutex instead. If the OpenMutex call fails with an error indicating the mutex doesn't exist, it repeats the whole process again, and hence gets stuck in an infinite loop if the mutex doesn't exist.

According to the CreateMutex documentation, this is essentially the correct approach, but doesn't seem to account for the case when the initial CreateMutex fails with an Access Denied that's not due to permissions on an existing mutex.

One thing that did seem to work when I tried it was to prefix the mutex name with "Global\", hopefully this is a suitable workaround for you.

like image 98
Iridium Avatar answered Oct 10 '22 02:10

Iridium