4

My problem is NOT how to read/write to shared memory (MemoryMappedFiles) in C++/C#, but more on how to correctly set security option of the MemoryMappedFile in C# (and I'm quite new to C#, so forgive me if the question is silly).

I have a process running as a service (under SYSTEM account) that sets up a shared memory space. Then I have another process, running as a service (under SYSTEM account) too, that accesses that shared memory space.

The first version of both of them is written in C++, the server (the "writer") mainly does (let assume I want a 1024 bytes memory segment whose name is 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);

And the reader:

HANDLE m_memoryHandle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, "Global\\mySegment");
LPVOID m_pSharedMemorySegment = MapViewOfFile(m_memoryHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);

This code works well, i.e. the shared memory space created by the writer is accessible to the reader under any circumstance (i.e. if the writer is run as a service or under the current (logged-in) user account (who has administrator rights) and if the reader is run as a service or under the same current (logged-in) user account).

Now, I translated this code (the writer only) to C#, mainly doing this:

MemoryMappedFile mappedFile = MemoryMappedFile.CreateNew(@"Global\mySegment", 1024, MemoryMappedFileAccess.ReadWrite);

With this writer, it works only if the writer is run by the current user. When it is launched as a service (and thus run by "SYSTEM" user), the reader has no access to the shared memory space anymore ("Access denied", in both cases, when the reader is run by the current user or as a service by SYSTEM).

So I tried to translate the C++ line

SetSecurityInfo(m_memoryHandle, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, (PACL) NULL, NULL);

to C#. The nearest implementation I've found is:

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

But the result is that now the reader can't access the shared memory space at all, under all of the 4 aforementioned combinations of service-no service

Given that this behavior is completely counter-intuitive with respect to the C# code, I'm a bit lost...

Someone has a good implementation or ideas on how to solve this problem ?

Thanks a lot.

  • Is the reader using OpenExisting with the same MemoryMappedFileRights data http://msdn.microsoft.com/en-us/library/dd267590.aspx – Preet Sangha Aug 30 '12 at 10:34
  • No, the reader is still the old C++ code reported in my question. I would like to avoid to modify it only for the purpose of making it compatible with the C# writer (except if I find a way to keep it compatible with both my C++ writer and my C# writer) – Alberto Avanzi Aug 30 '12 at 11:13

1 Answers1

0

Try adding Global\ to the start of the name used for the memory mapped file. I had exactly the same issue as you described, however with a service that was running under the NETWORK account, and this solved it.

mpeac
  • 720
  • 8
  • 27
  • 1
    Except if I missed another spot where I need to do this, it's already done by this line, right? `MemoryMappedFile mappedFile = MemoryMappedFile.CreateNew(@"Global\mySegment", 1024, MemoryMappedFileAccess.ReadWrite);` – Alberto Avanzi May 06 '17 at 07:22