Memory Mapped File Security

22 Dec 2005

How does the operating system load my process and libraries into memory? It maps the executable and library file contents into the address space of the process. If many programs only need read-access to the same file (e.g. /bin/bash, the C library) then the same physical memory can be shared between.

MemoryMappedCache is a small project can be used to host a proactive loaded cache using a Windows Service.
What is file security

Memory Mapped File Security

Introduction

MemoryMappedCache is a small project can be used to host a proactive loaded cache using a Windows Service. This cache uses Memory Mapped Files internally. Other applications on the same computer can then also use MemoryMappedCache to access information stored in this cache. This is done much quicker than using .NET Remoting. A significant amount of time was spent to ensure that this cache can be accessed from within ASP.NET if the cache is hosted by a Windows Service.

Background

Memory

Before I describe how, let’s explain why: people often develop a three-tiered application containing a

As you may have learned so far, there are three obstacles to overcome if you want to use Memory Mapped Files in an architecture described above:

  • You need to use P/Invoke to create and access any Memory Mapped Files. This makes the code more complex and more difficult to write.
  • You can't create the Memory Mapped Files using default security because you're preventing access from ASP.NET.
  • You can't create any mutexes using default security because you're also preventing access from ASP.NET. Fortunately, the .NET Framework has native support for mutexes using the System.Threading.Mutex-class. Unfortunately, that class appears to be creating its mutexes using default security so we can't use it. That's why I've developed my own Mutex-class in this project. This class creates mutexes using a NULL DACL. This is easy because it gives everyone full control but it's better to use the approach described in Mutex Madness of Ask Dr. GUI #49 in a production environment.

The MemoryMappedCache-project is currently designed with proactive content loading in mind. This means that the service is supposed to read all the information to be cached in memory when it starts and all the other applications (the clients so to speak) have read-only access to the cached information. If you want to, it should not be too difficult to change this project to a more reactive loading approach.

Using the code

When you open the MemoryMappedCache-solution you'll notice that it contains 4 small projects:

  • Client is a sample Console Client-application that retrieves information from the cache created by the Server- or the Service-applications
  • Server is a sample Console Server-application that stores information in the cache when it is started and then waits for user-input. While it is waiting, you can start the Client-application to retrieve information stored in the cache. Simply press Enter to quit the application.
  • MemoryMappedCache is the Class Library that contains all the intelligence. This file contains the code necessary to manage the cache using Memory Mapped Files and it also contains code to create mutexes.
  • The Service-application does exactly the same thing as the Server-application. The only difference is that this is a real Windows Service whereas Server is only a Console-application. Once you've compiled the service, you can install it using installutil service.exe and start it using the Service Control Manager. It's called MemoryMapService.

Once you've been able to get the Client-application to work, you'll notice that it is very easy to develop an ASP.NET-solution that does the same thing.

Here's some sample code that shows you what happens when the server starts (I've replaced the Windows Service with a Console Application to make the code more readable):

The first thing that happens is that an instance is made of the MemoryMappedCache.Cache-object. The name specified in the constructor (MyCompany.MyApplication.Cache_) can be any string and is used to uniquely identify this cache on this computer. The client-application should always use the same name as the server-application and two different server-applications should never use the same name. That's why I suggest using the MyCompany.MyApplication-convention. This should normally prevent you or anybody else from using the same name for another application.

After the server has created an instance of the Cache-object, it should fill it with data. This is done using the Assign-method. This method accepts a string as the key and any serializable object as its value. Here's what it will do:

Boost Memory Mapped Files

  • It will serialize the value to be stored in the cache. This is necessary because a Memory Mapped File is nothing more than a big chunk of memory which doesn't contain any structure.
  • Calculate the number of bytes necessary to store this value. This will be the size of the serialized stream + 4 bytes. These 4 additional bytes are used as the first 4 bytes of the Memory Mapped File and contain the length of thes best to have only a few large objects.

    Once all the data has been loaded in the cache, the server is running. If you want to stop the server, make sure that you call the Dispose-method. This method will close all handles opened by the Cache-object. You'll have memory-leaks if you don't do that!

    We can now start our client-application and see if we can retrieve any of the information stored in the cache using the server. The sample Client Console-application is written in C# (it could be any other .NET compliant language):

    You can see that the cache can be used very easily. Simply create an instance of the MemoryMappedCache.Cache-object using the same name as you used for your server and retrieve any values from the cache using the Contents-function. Here's what this function will do:

    • Create a mutex that ensures exclusive access to this item
    • Open the Memory Mapped File containing the value
    • Read the length of the data stored in the Memory Mapped File.
    • Once the length has been determined, reading the remaining bytes of the Memory Mapped File. These bytes contain the serialized value.
    • Deserialize the value
    • Return the value
    • Release the mutex

    I've documented all important areas in the code. Please read the documentation in the source for more information on the inner-workings. The entire MemoryMappedCache-library has only 3 classes and contains less than 700 lines of code so it should be easy to read.

    Points of Interest

    All mutexes and Memory Mapped Files are created using a NULL DACL. Make sure to use a more secure design before using in a production environment.

    History

    • V1.1: A bug has been fixed that caused a memory leak. Thanks to Derek Wade for reporting the bug and the fix.

Memory Mapped Files Java