1

I'm trying to create a MemoryMappedFile on a medium-integrity process, then open the same file on a low-integrity child process and use this shared memory for IPC. There's no real disk file (using MemoryMappedFile.CreateNew).

My problem is that the low-integrity process cannot open the shared memory, throwing this: "System.UnauthorizedAccessException: Access to the path is denied.". I'm not surprised that this is the case, given that I want write access from the low-integrity process, but how do you grant it access?

Here's my code:


Medium integrity process:

MemoryMappedFileSecurity security = new MemoryMappedFileSecurity();
var file = MemoryMappedFile.CreateNew("test", 4096, MemoryMappedFileAccess.ReadWrite, MemoryMappedFileOptions.None, security, HandleInheritability.Inheritable);

var view = file.CreateViewAccessor();
view.Write(0, true);

Low integrity process:

try
{
    MemoryMappedFile file = MemoryMappedFile.OpenExisting("test", MemoryMappedFileRights.ReadWrite);
    var view = file.CreateViewAccessor();
    var v = view.ReadBoolean(0);
    Log.Info("MAPPED: " + v);
}
catch (Exception e)
{
    Log.Info("Error: " + e);
}

Works fine if both processes work in medium integrity. After reading this, I tried setting the SDDL string on the medium integrity process like this:

security.SetSecurityDescriptorSddlForm("S:(ML;;NW;;;LW)");

But that gives me another exception, this time when the memory mapped file is created: "System.IO.IOException: A required privilege is not held by the client.". Not really sure this is the right way to do it anyway, I'm not really clear on how the Win32/C++ examples translates to C#...

Anyone know anything more about this?

Ollhak
  • 81
  • 7
  • You need SeRelabelPrivilege to change the mandatory integrity level for an existing object. If you are running with admin privilege, you should be able to enable SeRelabelPrivilege in order to make the change. If not, I think you'll need to specify the integrity level when the object is created. – Harry Johnston Jan 20 '16 at 01:31
  • ... or you could reverse the process and have the low-integrity process create the memory mapping and the medium-integrity process open it. – Harry Johnston Jan 20 '16 at 01:35
  • Ah, right - but running with admin privilege is not an option for me :( I thought I was specifying the integrity level at object creation (the security object goes into MemoryMappedFile.CreateNew in the medium integrity process). On the other hand, that second option you mentioned might work, I'll try it tonight. Thanks! – Ollhak Jan 20 '16 at 08:55
  • Setting the SDDL you're using works in native code, without admin rights. (That is, no error is returned and I can map a view of the file mapping from the process that created it. I didn't actually try accessing it from a low integrity process.) Perhaps there's a bug or design fault in the .NET class you're using. – Harry Johnston Jan 20 '16 at 20:16
  • Tried swapping it so the low-integrity process creates the shared memory. While it seemed like it was succesful, I actually couldn't read the memory back in the medium-integrity process this time (same error, "System.UnauthorizedAccessException: Access to the path is denied"). Actually, I get this even if I enable medium integrity on the child process... – Ollhak Jan 20 '16 at 21:39
  • Also: Don't think there's a bug in the .NET implementation, more probable that I'm simply not using it right. Might give a C++ implementation a go and try to use that as basis. – Ollhak Jan 20 '16 at 21:42

1 Answers1

2

Okay, got a working solution. There were two problems:

  1. Passing an empty MemoryMappedFileSecurity object to MemoryMappedFile.CreateNew() made the mapped memory inaccessible even to the same process. That explained my error in my comment ("System.UnauthorizedAccessException: Access to the path is denied").

  2. I couldn't actually get security.SetSecurityDescriptorSddlForm to work (and even though google reveals several other attempts at this, none of them worked for me). Instead, I used this solution: https://stackoverflow.com/a/14424623/5105846. As far as I can tell, it does the same thing, but using PInvoke instead. So I just called InterProcessSecurity.SetLowIntegrityLevel(file.SafeMemoryMappedFileHandle), and it made it accessible from the low-integrity child process. Success!

Not the perfect solution, but a working one is all I need for now. Thanks Harry for your help!

Community
  • 1
  • 1
Ollhak
  • 81
  • 7
  • Fascinating; that *doesn't* set the integrity level at creation time. You're passing a handle, so the object already exists, which means my original guess was mistaken. (I should have thought to try that in native code myself.) Darned if I can understand how the .NET class is generating a "required privilege" error! But so long as you've got a solution, I don't suppose it really matters. +1. :-) – Harry Johnston Jan 22 '16 at 22:41