Write-only mapping a O_WRONLY opened file supposed to work?

2.5k views Asked by At

Is mmap() supposed to be able to create a write-only mapping of a O_WRONLY opened file?

I am asking because following fails on a Linux 4.0.4 x86-64 system (strace log):

mkdir("test", 0700)          = 0
open("test/foo", O_WRONLY|O_CREAT, 0666) = 3
ftruncate(3, 11)                        = 0
mmap(NULL, 11, PROT_WRITE, MAP_SHARED, 3, 0) = -1 EACCES (Permission denied)

The errno equals EACCESS.

Replacing the open-flag O_WRONLY with O_RDWR yields a successful mapping.

The Linux mmap man page documents the errno as:

   EACCES A  file descriptor refers to a non-regular file.  Or a file map‐
          ping was  requested,  but  fd  is  not  open  for  reading.   Or
          MAP_SHARED  was  requested  and PROT_WRITE is set, but fd is not
          open in read/write (O_RDWR) mode.  Or PROT_WRITE is set, but the
          file is append-only.

Thus, that behaviour is documented with the second sentence.

But what is the reason behind it?

Is it allowed by POSIX?

Is it a kernel or a library limitation? (On a quick glance, I couldn't find anything obvious in Linux/mm/mmap.c)

2

There are 2 answers

0
Iwillnotexist Idonotexist On BEST ANSWER

The IEEE Std 1003.1, 2004 Edition (POSIX.1 2004) appears to forbid it.

An implementation may permit accesses other than those specified by prot; however, if the Memory Protection option is supported, the implementation shall not permit a write to succeed where PROT_WRITE has not been set or shall not permit any access where PROT_NONE alone has been set. The implementation shall support at least the following values of prot: PROT_NONE, PROT_READ, PROT_WRITE, and the bitwise-inclusive OR of PROT_READ and PROT_WRITE. If the Memory Protection option is not supported, the result of any access that conflicts with the specified protection is undefined. The file descriptor fildes shall have been opened with read permission, regardless of the protection options specified. If PROT_WRITE is specified, the application shall ensure that it has opened the file descriptor fildes with write permission unless MAP_PRIVATE is specified in the flags parameter as described below.

(emphasis added)

Also, on x86, it is not possible to have write-only memory, and this is a limitation of the page table entries. Pages may be marked read-only or read-write and independently may be executable or non-executable, but cannot be write-only. Moreover the man-page for mprotect() says:

Whether PROT_EXEC has any effect different from PROT_READ is architecture- and kernel version-dependent. On some hardware architectures (e.g., i386), PROT_WRITE implies PROT_READ.

This being the case, you've opened a file descriptor without read access, but mmap() would be bypassing the O_WRONLY by giving you PROT_READ rights. Instead, it will refuse outright with EACCESS.

0
Toby Speight On

I don't think the x86 hardware supports write-only pages, so write access implies read. But it seems to be a more general requirement than just x86 - mm/mmap.c contains this code in do_mmap_pgoff():

    case MAP_SHARED:
        if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE))
            return -EACCES;
        ....
        /* fall through */
    case MAP_PRIVATE:
        if (!(file->f_mode & FMODE_READ))
            return -EACCES;

I think that explains what you're seeing.