Search code examples
cposixipcshared-memory

Why does the POSIX C shared memory IPC API requires permissions (read/write) in multiple places?


I'm trying to use the POSIX shared memory IPC API in C, which basically follows the pattern shm_open() -> ftruncate() -> mmap() -> use -> munmap() -> shm_unlink() (the latter two being optional IIUC). I noticed that the first two calls requires you different flags specifying permissions and options, but I can't figure out the difference. From the man pages:

int shm_open(const char *name, int oflag, mode_t mode);
                               ---------  -----------
                                 FIRST      SECOND

oflag is a bit mask created by ORing together exactly one of O_RDONLY or O_RDWR
       O_RDONLY
              Open the object for read access.  A shared memory object opened in this way can be mmap(2)ed only for read (PROT_READ) access.

       O_RDWR Open the object for read-write access.

       O_CREAT
              Create  the shared memory object if it does not exist.  The user and group ownership of the object are taken from the corresponding effec‐
              tive IDs of the calling process, and the object's permission bits are set according to the low-order 9 bits of  mode,  except  that  those
              bits set in the process file mode creation mask (see umask(2)) are cleared for the new object.  A set of macro constants which can be used
              to define mode is listed in open(2).  (Symbolic definitions of these constants can be obtained by including <sys/stat.h>.)

and then

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
                                      --------
                                       THIRD

 The prot argument describes the desired memory protection of the mapping (and must not conflict with the open mode of the file).   It  is  either
       PROT_NONE or the bitwise OR of one or more of the following flags:

       PROT_EXEC  Pages may be executed.

       PROT_READ  Pages may be read.

       PROT_WRITE Pages may be written.

       PROT_NONE  Pages may not be accessed.

My question is: what's the difference between the permissions given in the three highlighted places?

A few things I noticed:

  • you can specify O_RDONLY in shm_open(), but then to allocate some space in the virtual file with ftruncate() you need to have permissions to write anyway (O_RDWR), so what's the point?
  • why is this required, and in the same call I have to set the bitmask for file permissions (SECOND in the example)
  • a second question: then you specify access protection for mmap too, but it also said that After the mmap() call has returned, the file descriptor, fd, can be closed immediately without invalidating the mapping., so I guess if you want to create a read only file (because other processes may write to it) you have to first open it with write privileges, then map it in read only mode, then deallocate the fd?

Solution

  • A file system entry has access rights, at least three "groups" of "authorisations" (read, write, execute) for owner, group owner and others. These are used when a process request an access to that object; the requested accesses are tested against these autorisations.

    When you "open" something you request an intent, this is specified in the oflag parameter (I want to read RD_ONLY, or I want to write, or...). Sometimes you request to open something that does not exists and at the same time to create it if necessary (O_CREAT). In that case, you need to specify what will be the access rights through the mode parameter.

    Once you opened that object, you can use it as you declared in the opening. In the case of a shared memory object you need to map it into the process address space to be able to access it. This is the purpose of mmap, to map that object at some location in the memory of your process. Any chunk of memory of an address space is also protected; for example the code of your process is (by default) protected against writes, etc. Thus if you map a shared memory object you need to specify what will be the protection of that memory, that is the purpose of the prot parameter.