我的问题不是如何在 C++/C# 中读取/写入共享内存 (MemoryMappedFiles),而是更多关于如何在 C# 中正确设置 MemoryMappedFile 的安全选项(而且我对 C# 很陌生,如果有问题请见谅很傻)。
我有一个作为服务运行的进程(在 SYSTEM 帐户下),它设置了一个共享内存空间。然后我有另一个进程,也作为服务运行(在 SYSTEM 帐户下),它访问该共享内存空间。
它们的第一个版本都是用 C++ 编写的,服务器(“编写器”)主要执行(假设我想要一个 1024 字节的内存段,其名称为 Global\mySegment):
HANDLE m_memoryHandle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, "Global\\mySegment");
SetSecurityInfo(m_memoryHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, (PACL) NULL, NULL);
LPVOID m_pSharedMemorySegment = MapViewOfFile(m_memoryHandle, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
和读者:
HANDLE m_memoryHandle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, "Global\\mySegment");
LPVOID m_pSharedMemorySegment = MapViewOfFile(m_memoryHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
此代码运行良好,即编写器创建的共享内存空间在任何情况下都可供读者访问(即,如果编写器作为服务运行或在当前(登录)用户帐户(具有管理员权限)下运行)和如果阅读器作为服务运行或在相同的当前(登录)用户帐户下运行)。
现在,我将这段代码(仅限作者)翻译成 C#,主要是这样做的:
MemoryMappedFile mappedFile = MemoryMappedFile.CreateNew(@"Global\mySegment", 1024, MemoryMappedFileAccess.ReadWrite);
使用此编写器,它仅在编写器由当前用户运行时才有效。当它作为服务启动时(因此由“SYSTEM”用户运行),阅读器不再有权访问共享内存空间(“访问被拒绝”,在这两种情况下,当阅读器由当前用户运行或作为SYSTEM 的服务)。
所以我尝试翻译 C++ 行
SetSecurityInfo(m_memoryHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, (PACL) NULL, NULL);
到 C#。我发现最近的实现是:
var security = new MemoryMappedFileSecurity();
// Create a SecurityIdentifier object for "everyone".
SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
security.AddAccessRule(new AccessRule<MemoryMappedFileRights>(everyoneSid, MemoryMappedFileRights.FullControl, AccessControlType.Allow));
MemoryMappedFile mappedFile = MemoryMappedFile.CreateNew(_memoryRegionName, _memRegionSize, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, security, HandleInheritability.Inheritable);
但结果是现在读者根本无法访问共享内存空间,在前面提到的所有4种service-no service组合下
鉴于这种行为对于 C# 代码来说是完全违反直觉的,我有点迷茫......
有人对如何解决这个问题有很好的实施或想法?
非常感谢。