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
)
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 wherePROT_WRITE
has not been set or shall not permit any access wherePROT_NONE
alone has been set. The implementation shall support at least the following values ofprot
:PROT_NONE
,PROT_READ
,PROT_WRITE
, and the bitwise-inclusive OR ofPROT_READ
andPROT_WRITE
. If the Memory Protection option is not supported, the result of any access that conflicts with the specified protection is undefined. The file descriptorfildes
shall have been opened with read permission, regardless of the protection options specified. IfPROT_WRITE
is specified, the application shall ensure that it has opened the file descriptorfildes
with write permission unlessMAP_PRIVATE
is specified in theflags
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 fromPROT_READ
is architecture- and kernel version-dependent. On some hardware architectures (e.g., i386),PROT_WRITE
impliesPROT_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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With