【问题标题】:Can't open semaphore from another process无法从另一个进程打开信号量
【发布时间】:2012-03-02 02:42:50
【问题描述】:

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

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

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

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

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

有什么想法吗?

【问题讨论】:

  • 你是fork() -ed 孩子吗?
  • 创建使用Global\\bitmap,而打开只使用bitmap。是否应该打开也不是Global\\bitmap,因为默认命名空间可能不是Global
  • 啊,抱歉,两个都试了 - 现在编辑。
  • @Adrian 你可以说,我用了CreateProcess()(因为它赢了)

标签: c winapi semaphore


【解决方案1】:

我必须对其他答案进行澄清,并发出安全警告。

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

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

其次,请注意。如上所述,通过授予每个人对信号量的完全访问权限,可能会创建 DoS 攻击的安全漏洞。您应该考虑是否希望任意进程能够获取和释放信号量。它是为不受限制的公共使用而设计的吗?将最小的、严格允许的 ACL 分配给对象始终是一个好习惯。使用SDDL 可能是编码安全描述符的最简单方法,尽管脚本本身的可读性不高。

【讨论】:

  • 谢谢一百万! hmjd 的答案几乎就在那里,但使它起作用的是添加的权利SEMAPHORE_MODIFY_STATE(我认为需要启用一个进程来释放信号量)。所以我实际上需要两种权利:SYNCHRONIZE|SEMAPHORE_MODIFY_STATE.
【解决方案2】:

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");
}

【讨论】:

  • 谢谢,我已阅读文档 - 但遗憾的是没有示例,它们会导致其他文档 :(。我应该是结构的示例或至少一个 sn-p通过以使信号量可访问将不胜感激。
  • OpenSemaphore() 的第一个参数不是结构,而是选项的位掩码。用示例更新了答案。
  • 请注意,除非您希望 由其他用户运行 的进程能够打开信号量,否则您不需要弄乱安全描述符。 Windows 安全性(大部分)以用户为中心,而不是以进程为中心,因此以某个用户身份运行的进程创建的任何资源都可以被以同一用户身份运行的任何其他进程访问(假设其他进程与该资源位于同一位置- 例如,在同一台机器、会话等上)。
  • @BrendanMcK,我同意。从 OP 的问题来看,他确实说明了子进程,您会假设这是同一个用户,尽管他可能正在使用 CreateProcessAsUser(),并且子进程被描述为 special,无论这意味着什么,所以我不确定是否是同一用户。
  • 感谢详细的示例。今天去试试。
【解决方案3】:

lpSemaphoreAttributes [输入,可选]
一个指针 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

【讨论】:

  • 感谢您的回答。不过,它不会每次都是子进程。我需要一个通用的解决方案。无论如何,为什么全局信号量不会对所有人都可用?
  • 几乎,您需要创建一个没有 ACL 的有效安全描述符,这实际上意味着没有限制。 NULL SA 结构意味着没有访问权限。
  • @Deanna 谢谢,不过我似乎找不到有效的代码示例:(
  • 我已经用 (VB6) 示例更新了 Alex 的答案,但它很容易转换为任何其他语言。
猜你喜欢
  • 2022-01-21
  • 1970-01-01
  • 2018-10-10
  • 2016-08-17
  • 2016-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多