UnauthorizedAccessException when trying to open a mutex

旧城冷巷雨未停 提交于 2019-12-18 12:27:22

问题


I'm getting this exception when trying to open a mutex (it happens only sometimes; the most of calls is successful):

System.UnauthorizedAccessException: Access to the path 'Global\4c7cddf7-e729-43b6-a75c-43f54a0ac6ac' is denied.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.Threading.Mutex.OpenExisting(String name, MutexRights rights)

The code I'm using to work with mutex:

public class MutexLocker : IDisposable
{
    public MutexLocker(string id)
    {
        var doesNotExist = false;
        var unauthorized = false;

        try
        {
            _mutex = Mutex.OpenExisting(id, MutexRights.Synchronize | MutexRights.Modify);
        }
        catch (WaitHandleCannotBeOpenedException)
        {
            doesNotExist = true;
        }
        catch (UnauthorizedAccessException ex)
        {
            unauthorized = true;
        }

        if (doesNotExist)
        {
            _mutex = new Mutex(false, id);

            var allowEveryoneRule = new MutexAccessRule(
                new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
            var securitySettings = new MutexSecurity();
            securitySettings.AddAccessRule(allowEveryoneRule);
            _mutex.SetAccessControl(securitySettings);
        }
        else if (unauthorized)
        {
            var tempMutex = Mutex.OpenExisting(id, MutexRights.ReadPermissions | MutexRights.ChangePermissions);
            var securitySettings = tempMutex.GetAccessControl();

            var user = Environment.UserDomainName + "\\" + Environment.UserName;

            // the rule that denied the current user the right to enter and release the mutex must be removed
            var rule = new MutexAccessRule(user, MutexRights.Synchronize | MutexRights.Modify, AccessControlType.Deny);
            securitySettings.RemoveAccessRule(rule);

            // Now grant the correct rights
            var allowEveryoneRule = new MutexAccessRule(
                new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
            securitySettings.AddAccessRule(allowEveryoneRule);
            tempMutex.SetAccessControl(securitySettings);

            _mutex = Mutex.OpenExisting(id, MutexRights.Synchronize | MutexRights.Modify);
        }

        var success = _mutex.WaitOne(TimeSpan.FromSeconds(10), false);
        if (success == false)
        {
            _mutex.Dispose();
            _mutex = null;
            throw new ApplicationException(string.Format("Can't lock mutex (timed out): {0}", id));
        }
    }

    public void Dispose()
    {
        if (_mutex != null)
        {
            try
            {
                _mutex.ReleaseMutex();
            }
            catch (Exception exc)
            {
                Trace.WriteLine(exc);
            }

            _mutex.Dispose();
        }
    }

    private readonly Mutex _mutex;
}

The mutex "id" is a guid and name conflicts are impossible.
This is the only code that can create that mutex, and it grants full access to it for all users (my processes can be run under different user credentials).

Any ideas, why this unauthorized access error might happen?


回答1:


This class should solve your problem:

    public class MutexLocker: IDisposable
    {
        private Mutex _mutex;

        public MutexLocker ( string id )
        {
            bool createdNew;
            MutexSecurity mutexSecurity = new MutexSecurity();
            mutexSecurity.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), 
                                                            MutexRights.Synchronize | MutexRights.Modify, AccessControlType.Allow));

            try
            {
                // attempt to create the mutex, with the desired DACL..
                _mutex = new Mutex(false, id, out createdNew, mutexSecurity);
            }
            catch (WaitHandleCannotBeOpenedException)
            {
                // the mutex cannot be opened, probably because a Win32 object of a different
                // type with the same name already exists.
                throw;
            }
            catch (UnauthorizedAccessException)
            {
                // the mutex exists, but the current process or thread token does not
                // have permission to open the mutex with SYNCHRONIZE | MUTEX_MODIFY rights.
                throw;
            }
        }

        public void Dispose ()
        {
            if (_mutex != null)
            {
                _mutex.ReleaseMutex();
                _mutex.Dispose();
            }

            _mutex = null;
        }
    }

The only pieces of note is the Mutex constructor, which will attempt to create the mutex (by calling Win32's CreateMutex()) immediately assigning the provided security descriptor to the named object. If the CreateMutex call fails, the framework will attempt to use OpenMutex to open the named mutex requesting SYNCHRONIZE and MUTEX_MODIFY rights.

The problem that you are seeing is a simple race condition between the creation of the mutex and assignment of the security descriptor (at least as far as I noticed). Making the creation and security descriptor assignment atomic will solve that problem.



来源:https://stackoverflow.com/questions/19536697/unauthorizedaccessexception-when-trying-to-open-a-mutex

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!