无法从另一个进程打开信号量

时间:2012-02-09 15:48:39

标签: c winapi semaphore

我正在这样的过程中创建一个全局信号量对象:

CreateSemaphore(NULL, 1, 1, "Global\\bitmap");

现在,当我试图在子进程中打开它时(这是“另一个进程”的特殊情况,它不会是一个打开所创建的信号量的子代),如下所示:

bitmapSem = OpenSemaphore(NULL, TRUE, "Global\\bitmap");

bitmapSem变量等于NULL,我从GetLastError()收到错误5(ERROR_ACCESS_DENIED)。

有什么想法吗?

3 个答案:

答案 0 :(得分:7)

OpenSemaphore()的第一个参数记录为:

  

dwDesiredAccess [in]

     

访问信号量对象。如果指定对象的安全描述符不允许对调用进程请求访问,则该函数将失败。有关访问权限的列表,请参阅同步对象安全性和访问权限。

在已发布的代码NULL中指定:未记录为具有特殊含义。更改为Synchronization Object Security and Access Rights中记录的访问权限之一:

bitmapSem = OpenSemaphore(SYNCHRONIZE, TRUE, "Global\\bitmap");

编辑:

要创建一个可以授予Everyone访问权限的安全描述符,请尝试以下(未经测试的)代码:

/* Create a security descriptor that has an an empty DACL, to
   grant access to 'Everyone'. */
SECURITY_DESCRIPTOR sd;
if (0 == InitializeSecurityDescriptor(&sd,
                                      SECURITY_DESCRIPTOR_REVISION) ||
    0 == SetSecurityDescriptorDacl(&sd,
                                   TRUE,
                                   (PACL)0,
                                   FALSE))
{
    /* Failed to create security descriptor. */
}
else
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength              = sizeof(sa);
    sa.lpSecurityDescriptor = &sd;
    sa.bInheritHandle       = FALSE;

    HANDLE sh = CreateSemaphore(&sa, 1, 1, "Global\\bitmap");
}

答案 1 :(得分:7)

我必须在其他答案和安全警告中加上澄清。

首先,将NULL作为lpSemaphoreAttributes参数传递给::CreateSemaphore() 意味着无法访问任何人;相反,它意味着将分配默认访问控制。 MSDN is crystal clear on that如果此参数为NULL,则信号量将获取默认安全描述符。信号量的默认安全描述符中的ACL来自创建者的主要或模拟令牌。

通常,信号量可以由相同的用户身份打开和使用。因此,如果信号量由在同一交互式会话中运行的进程共享,或者在相同的服务标识下共享,则即使使用默认安全描述符创建,也可以由另一个进程打开信号量。正如@hmjd已经指出的那样,你必须始终明确地调出你想要在信号量上断言的权利:SYNCHRONIZE|SEMAPHORE_MODIFY_STATE允许等待和释放它。

其次,要小心谨慎。通过授予Everyone对信号量的完全访问权限,如上所述,可能会创建DoS攻击的安全漏洞。您应该考虑是否希望任意进程能够获取和释放信号量。它是否适用于不受限制的公共用途?将最小的,允许范围很小的ACL分配给对象始终是一种好习惯。使用SDDL可能是编码安全描述符的最简单方法,尽管脚本本身不是很易读。

答案 2 :(得分:0)

  

lpSemaphoreAttributes [in,optional]
  指向a的指针   SECURITY_ATTRIBUTES结构。如果此参数为NULL,则为句柄   不能被子进程继承。

使用空的DACL传递LPSECURITY_ATTRIBUTES并将bInheritHandle成员设置为第一个参数。

VB中的一个例子是:

'Setup the security descriptor
InitializeSecurityDescriptor SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION
SetSecurityDescriptorDacl SecurityDescriptor, 1, ByVal 0, 0 'Dacl is present and empty

'Setup the security attributes
SecurityAttributes.nLength = Len(SecurityAttributes)
SecurityAttributes.lpSecurityDescriptor = VarPtr(SecurityDescriptor)
SecurityAttributes.bInheritHandle = False