C# · 12月 25, 2021

c# – 尝试打开互斥体时UnauthorizedAccessException

当尝试打开互斥体时,我会收到这个异常(仅有时会发生这种情况;大多数调用成功): 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)

我用于使用互斥体的代码:

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,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;}

互斥体“id”是一个guid,名称冲突是不可能的.
这是唯一可以创建互斥体的代码,并且它为所有用户授予了完全访问权限(我的进程可以在不同的用户凭据下运行).

任何想法,为什么这种未经授权的访问错误可能发生

@H_404_14@解决方法 这个课程应该解决你的问题: 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,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; } }

唯一的注意事项是Mutex构造函数,它将尝试创建互斥(通过调用Win32的CreateMutex()),将所提供的安全描述符立即分配给命名对象.如果CreateMutex调用失败,框架将尝试使用OpenMutex打开请求SYNCHRONIZE和MUTEX_MODIFY权限的命名互斥体.

您所看到的问题是创建互斥体和分配安全描述符之间的简单竞争条件(至少在我注意到的情况下).使创建和安全描述符赋值为原子将解决该问题.