Windows 中的不同进程(服务)可以写入共享内存吗?
Can shared memory be written form different processes (services) in Windows?
我有两个 Windows 服务应该相互共享数据,我打算为此目的使用 SharedMemory (FileMapping)。用户 space 中的另一个进程 运行 也应该能够从该内存中读取。
好吧,FileMapping 是在一项服务中创建的,可以从 "other service" 和用户进程访问以进行读取。但是,如果 "other service" 也可以写入此内存(当然,同时通过互斥锁锁定)。但是,如果我仅尝试将 OpenFileMapping 与 "other service" 中的 FILE_MAP_WRITE 一起使用,则返回 ERROR_ACCESS_DENIED (5)(当然,FILE_MAP_READ 有效)。当我尝试获取互斥锁时,也会发生同样的情况。
我假设下面的 SSDL 字符串有问题,但我不知道我必须在其中输入什么。有人可以帮忙吗?
服务按如下方式创建 FileMapping(为了便于阅读,省略了错误检查;您可能已经看过其中一部分):
PSECURITY_DESCRIPTOR getSecurityDescriptor(const QString &sddl)
{
QString m_sddl = sddl;
PSECURITY_DESCRIPTOR m_pSecDesc;
if ((DWORD)(LOBYTE(LOWORD(GetVersion()))) >= 6)
{
// Found this - is this really required??
m_sddl += "S:(ML;;NW;;;ME)";
}
if(!ConvertStringSecurityDescriptorToSecurityDescriptorW(
(LPCWSTR)*m_sddl.utf16(), SDDL_REVISION_1, &m_pSecDesc, nullptr))
{
return nullptr;
}
return m_pSecDesc;
}
bool publishData(...)
{
PSECURITY_DESCRIPTOR m_pSecDesc = getSecurityDescriptor("D:(A;;GR;;;AU)(A;;GA;;;LS)");
if (!m_pSecDesc)
{
...
return false;
}
SECURITY_ATTRIBUTES secAttr;
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttr.lpSecurityDescriptor = m_pSecDesc;
secAttr.bInheritHandle = false;
// Ommitted: We also create a mutex "Global\MyMutex" here with the same SECURITY_ATTRIBUTES...
QString m_mapFileName = "Global\MySharedMemory";
m_hMapFile = CreateFileMappingW(INVALID_HANDLE_VALUE, &secAttr, PAGE_READWRITE,
0, data.size(), (LPCWSTR)(m_mapFileName.utf16()));
...
"other service" 尝试以这种方式打开它:
hMapFile = OpenFileMappingW(FILE_MAP_WRITE, false, L"Global\MySharedMemory");
如果我尝试通过以下方式获取上面提到的互斥锁,也会发生同样的情况:
hMutex = OpenMutexW(MUTEX_MODIFY_STATE, false, L"Global\MyMutex");
...
DWORD ret = WaitForSingleObject(hMutex, 1000); // -> ERROR_ACCESS_DENIED (5)
这里有两个问题。一是您授予了错误的帐户访问权限,LS(本地服务)而不是 SY(本地系统)。这适用于映射和互斥量。
第二个仅适用于互斥锁:您必须具有 SYNCHRONIZE 访问权限,并且 as discussed in this question 没有用于此的 SDDL 语法。您将需要使用十六进制掩码。
正如 discussed here and here 和您在评论中指出的那样,您确实需要对不同类型的对象使用不同的访问掩码,除非您坚持通用访问权限(或知道 正是你在做什么)。
有关这些对象的文档中描述了各种对象类型的访问权限。例如,Synchronization Object Security and Access Rights under the general heading About Synchronization 中描述了互斥对象的访问权限。 (如果需要转换为位掩码,可以使用SDK头文件来确定各个名称对应的位。)
我有两个 Windows 服务应该相互共享数据,我打算为此目的使用 SharedMemory (FileMapping)。用户 space 中的另一个进程 运行 也应该能够从该内存中读取。
好吧,FileMapping 是在一项服务中创建的,可以从 "other service" 和用户进程访问以进行读取。但是,如果 "other service" 也可以写入此内存(当然,同时通过互斥锁锁定)。但是,如果我仅尝试将 OpenFileMapping 与 "other service" 中的 FILE_MAP_WRITE 一起使用,则返回 ERROR_ACCESS_DENIED (5)(当然,FILE_MAP_READ 有效)。当我尝试获取互斥锁时,也会发生同样的情况。
我假设下面的 SSDL 字符串有问题,但我不知道我必须在其中输入什么。有人可以帮忙吗?
服务按如下方式创建 FileMapping(为了便于阅读,省略了错误检查;您可能已经看过其中一部分):
PSECURITY_DESCRIPTOR getSecurityDescriptor(const QString &sddl)
{
QString m_sddl = sddl;
PSECURITY_DESCRIPTOR m_pSecDesc;
if ((DWORD)(LOBYTE(LOWORD(GetVersion()))) >= 6)
{
// Found this - is this really required??
m_sddl += "S:(ML;;NW;;;ME)";
}
if(!ConvertStringSecurityDescriptorToSecurityDescriptorW(
(LPCWSTR)*m_sddl.utf16(), SDDL_REVISION_1, &m_pSecDesc, nullptr))
{
return nullptr;
}
return m_pSecDesc;
}
bool publishData(...)
{
PSECURITY_DESCRIPTOR m_pSecDesc = getSecurityDescriptor("D:(A;;GR;;;AU)(A;;GA;;;LS)");
if (!m_pSecDesc)
{
...
return false;
}
SECURITY_ATTRIBUTES secAttr;
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
secAttr.lpSecurityDescriptor = m_pSecDesc;
secAttr.bInheritHandle = false;
// Ommitted: We also create a mutex "Global\MyMutex" here with the same SECURITY_ATTRIBUTES...
QString m_mapFileName = "Global\MySharedMemory";
m_hMapFile = CreateFileMappingW(INVALID_HANDLE_VALUE, &secAttr, PAGE_READWRITE,
0, data.size(), (LPCWSTR)(m_mapFileName.utf16()));
...
"other service" 尝试以这种方式打开它:
hMapFile = OpenFileMappingW(FILE_MAP_WRITE, false, L"Global\MySharedMemory");
如果我尝试通过以下方式获取上面提到的互斥锁,也会发生同样的情况:
hMutex = OpenMutexW(MUTEX_MODIFY_STATE, false, L"Global\MyMutex");
...
DWORD ret = WaitForSingleObject(hMutex, 1000); // -> ERROR_ACCESS_DENIED (5)
这里有两个问题。一是您授予了错误的帐户访问权限,LS(本地服务)而不是 SY(本地系统)。这适用于映射和互斥量。
第二个仅适用于互斥锁:您必须具有 SYNCHRONIZE 访问权限,并且 as discussed in this question 没有用于此的 SDDL 语法。您将需要使用十六进制掩码。
正如 discussed here and here 和您在评论中指出的那样,您确实需要对不同类型的对象使用不同的访问掩码,除非您坚持通用访问权限(或知道 正是你在做什么)。
有关这些对象的文档中描述了各种对象类型的访问权限。例如,Synchronization Object Security and Access Rights under the general heading About Synchronization 中描述了互斥对象的访问权限。 (如果需要转换为位掩码,可以使用SDK头文件来确定各个名称对应的位。)