只写映射 O_WRONLY 打开的文件应该有效吗?
Write-only mapping a O_WRONLY opened file supposed to work?
mmap()
是否应该能够为 O_WRONLY
打开的文件创建只写映射?
我问是因为以下在 Linux 4.0.4 x86-64 系统上失败(strace
日志):
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)
errno
等于EACCESS
。
将打开标志 O_WRONLY
替换为 O_RDWR
会生成成功的映射。
Linux mmap
手册页将 errno 记录为:
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.
因此,第二句话记录了该行为。
但这背后的原因是什么?
POSIX允许吗?
是内核还是库限制? (快速浏览一下,我在 Linux/mm/mmap.c
中找不到任何明显的内容)
编辑
IEEE Std 1003.1, 2004 Edition (POSIX.1 2004) 似乎禁止这样做。
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.
(强调)
此外,在 x86 上,不可能有只写内存,这是页面 table 条目的限制。页面可以被标记为只读或读写,并且独立地可以是 executable 或非 executable,但不能是只写的。此外 mprotect()
的手册页说:
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
.
在这种情况下,您打开了一个没有读取权限的文件描述符,但是 mmap()
会通过授予您 PROT_READ
权限来绕过 O_WRONLY
。相反,它会直接拒绝 EACCESS
.
我认为 x86 硬件不支持只写页面,因此写入访问意味着读取。但这似乎是一个比 x86 更普遍的要求 - mm/mmap.c
在 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;
我认为这可以解释您所看到的情况。
mmap()
是否应该能够为 O_WRONLY
打开的文件创建只写映射?
我问是因为以下在 Linux 4.0.4 x86-64 系统上失败(strace
日志):
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)
errno
等于EACCESS
。
将打开标志 O_WRONLY
替换为 O_RDWR
会生成成功的映射。
Linux mmap
手册页将 errno 记录为:
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.
因此,第二句话记录了该行为。
但这背后的原因是什么?
POSIX允许吗?
是内核还是库限制? (快速浏览一下,我在 Linux/mm/mmap.c
中找不到任何明显的内容)
编辑
IEEE Std 1003.1, 2004 Edition (POSIX.1 2004) 似乎禁止这样做。
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.
(强调)
此外,在 x86 上,不可能有只写内存,这是页面 table 条目的限制。页面可以被标记为只读或读写,并且独立地可以是 executable 或非 executable,但不能是只写的。此外 mprotect()
的手册页说:
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
.
在这种情况下,您打开了一个没有读取权限的文件描述符,但是 mmap()
会通过授予您 PROT_READ
权限来绕过 O_WRONLY
。相反,它会直接拒绝 EACCESS
.
我认为 x86 硬件不支持只写页面,因此写入访问意味着读取。但这似乎是一个比 x86 更普遍的要求 - mm/mmap.c
在 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;
我认为这可以解释您所看到的情况。