我花了好几天时间追踪由于调用:: CreateMutex()失败而导致未处理的异常导致的错误。请注意CreateMutex()
并未尝试锁定互斥锁,只是为了打开手柄。 即使互斥锁已经存在也不应该失败,至少只要我将bInitialOwner设置为FALSE,我就这样做了。
但是如果我调用::CreateMutexA(0, 0, "testtesttest123");
,则来自Windows服务产生的程序(w3wp.exe
是其父级,scvhost.exe
是其祖父级,它在IIS APPPOOL\Worker1
下运行user-account),如果已经由IIS APPPOOL\*
下运行的另一个进程创建了互斥锁,则失败并返回NULL。
我创建了一个重现此问题的最小示例:
void main()
{
HANDLE handle = CreateMutexA(0, 0, "testtesttest123");
std::string lastError = MyGetLastErrorAsText();
MyAppendToLog("%p %s\n", handle, lastError.c_str());
Sleep(INFINITE);
}
我通过双击资源管理器(普通用户帐户)运行可执行文件2次,然后使其由Windows服务生成,并再次从资源管理器运行它。
这将创建以下日志:
C:\Test\ReproduceMutexCrash.exe: 00000034 ERROR_SUCCESS C:\Test\ReproduceMutexCrash.exe: 00000034 ERROR_ALREADY_EXISTS c:\inetpub\wwwroot\Worker1\ReproduceMutexCrash.exe: 00000034 ERROR_SUCCESS c:\inetpub\wwwroot\Worker2\ReproduceMutexCrash.exe: 00000000 ERROR_ACCESS_DENIED C:\Test\ReproduceMutexCrash.exe: 00000034 ERROR_ALREADY_EXISTS
此处的Worker1在IIS APPPOOL\Worker1
下运行,而Worker2在IIS APPPOOL\Worker2
用户帐户下运行。
从日志中可以明显看出,如果互斥锁是由普通用户进程创建的,则不会阻止其他用户进程甚至Windows服务打开句柄。但是,如果Windows服务创建了一个互斥锁,那么::CreateMutex()
在被另一个Windows服务调用时会失败,尽管用户进程仍然可以毫不费力地打开句柄。
有谁知道为什么会这样?
编辑:当资源管理器生成进程时,我看到互斥对象为\Sessions\1\BaseNamedObjects\testtesttest123
,而当\BaseNamedObjects\testtesttest123
创建进程时,IIS
{1}},所有者为Worker1
(首先设法创建互斥锁的进程)。
答案 0 :(得分:5)
感谢评论的帮助,我终于弄明白了为什么会这样。这确实是因为权限,并且因为进程是从不同的用户帐户运行的。我通过运行2个单独的流程验证了这一点,但来自同一个用户帐户 - IIS APPPOOL\Worker1
,并且::CreateMutex()
工作并返回了有效的HANDLE。
只有当互斥锁被IIS APPPOOL\Worker1
下的进程锁定且IIS APPPOOL\Worker2
下的进程尝试访问它时,它才会失败。
另外,我尝试创建没有任何安全性的互斥锁by creating an empty DACL:
SECURITY_ATTRIBUTES sa = { sizeof(sa) };
SECURITY_DESCRIPTOR SD;
InitializeSecurityDescriptor(&SD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&SD, TRUE, NULL, FALSE);
sa.lpSecurityDescriptor = &SD;
HANDLE mutex = CreateMutexA(&sa, 0, "testtesttest123");
使用空的DACL,来自不同用户帐户的2个进程可以打开相同的互斥锁。
此外,由用户进程创建的互斥锁没有导致ERROR_ACCESS_DENIED的原因是因为它在不同的范围内创建了互斥锁 - \Sessions\1\BaseNamedObjects\testtesttest123
,因此没有权限冲突,因为网络服务流程正在\BaseNamedObjects\testtesttest123
创建一个新的互斥锁,因此他们无论如何都无法访问同一个对象。