Restrict child process access to shared memory and message queues

1.1k views Asked by At

I am writing a server that will accept untrusted Dynamic Library Modules (DLL,SO/DSO) loaded at runtime using Boost.DLL.

I would like to run the untrusted module in a separate process that only has access to the relevant shared memory (sometimes read only) and interprocess queues.

Process layout

Boost does allow for a permissions object to be associated with the shared memory.

It seems like there might be a way to create a process on windows and Linux and then adjust the permissions.

How can a process be created that

  • has no permissions to start with (e.g. using AdjustTokenPrivileges on windows perhaps?), but
  • is then granted read access to shared memory mapped file (e.g. by setting permissions when constructing the shared memory segment?)

Or perhaps this is inherently too risky?

1

There are 1 answers

2
sehe On BEST ANSWER

First, from the docs:

Named resources offered by Boost.Interprocess must cope with platform-dependant permission issues also present when creating files. If a programmer wants to shared shared memory, memory mapped files or named synchronization mechanisms (mutexes, semaphores, etc...) between users, it's necessary to specify those permissions. Sadly, traditional UNIX and Windows permissions are very different and Boost.Interprocess does not try to standardize permissions, but does not ignore them.

All named resource creation functions take an optional permissions object that can be configured with platform-dependant permissions.

Beware, if you do so, then you immediately have to know about platform specific required permissiong:

Since each mechanism can be emulated through different mechanisms (a semaphore might be implement using mapped files or native semaphores) permissions types could vary when the implementation of a named resource changes (eg.: in Windows mutexes require synchronize permissions, but that's not the case of files). To avoid this, Boost.Interprocess [usually¹, red.] relies on file-like permissions, requiring file read-write-delete permissions to open named synchronization mechanisms (mutex, semaphores, etc.) and appropriate read or read-write-delete permissions for shared memory. This approach has two advantages: it's similar to the UNIX philosophy and the programmer does not need to know how the named resource is implemented.

¹ when not passing the permissions object


Your other question:

  • has no permissions to start with (e.g. using AdjustTokenPrivileges on windows perhaps?), but
  • is then granted read access to shared memory mapped file (e.g. by setting permissions when constructing the shared memory segment?)

No. The permissions object does not give permissions to the invoking process. The permissions object restricts access for other processes. I wager that as such, it only makes sense to specify permissions on create_only or open_or_create.

What I imagine is the usual route on Windows/Linux:

  • you start the server running as a specific user account
  • you start the clients using the same account
  • you create the IPC objects to be accessible only from the account that created them (the owner)

I wager that Windows will allow more fine-grained control due to its Access Control Lists (not tested this): they should allow you to specify additional/different accounts that have access.

On linux, it is highly likely that to achieve such control, additional system calls are necessary (e.g. to change the owner/group of the shared object and/or add such a group the client user account as primary/secondary group).

Summarizing: _I would focus on granting access to a specific recipient, instead of "starting a recipient without any permissions". The latter is impractical (processes might not even function "without any permissions") and elevating privileges during runtime is a lot more difficult than using statically assigned/administered permissions. Not to mention it's inherently less secure to add permissions on the fly.