write() 系统调用忽略文件权限

write() 系统调用忽略文件权限

我用 C 语言编写了一个非常简单的程序,它将“测试字符串”写入名为“file.txt”的文件中:

root@3:~# cat test.c
#include "unistd.h"
#include "string.h"
#include "stdio.h"

main()
{
  FILE *fp;
  int fd;

  fp = fopen("file.txt", "w");
  fd = fileno(fp);
  write(fd, "Test string\n", strlen("Test string\n"));
}
root@3:~#

在执行以下命令之前,我创建了一个名为“file.txt”的文件test

root@3:~# ls -l file.txt 
-r-------- 1 root root 0 sept  21 22:28 file.txt
root@3:~#

如上所示,file.txt只有读取权限。但是,如果我执行test,“测试字符串”将被写入“file.txt”:

root@3:~# strace ./test
execve("./test", ["./test"], [/* 22 vars */]) = 0
brk(0)                                  = 0x188d000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc03a44e000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=30251, ...}) = 0
mmap(NULL, 30251, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fc03a446000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\357\1\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1599504, ...}) = 0
mmap(NULL, 3713112, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc039ea6000
mprotect(0x7fc03a028000, 2093056, PROT_NONE) = 0
mmap(0x7fc03a227000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x181000) = 0x7fc03a227000
mmap(0x7fc03a22c000, 18520, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fc03a22c000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc03a445000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc03a444000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc03a443000
arch_prctl(ARCH_SET_FS, 0x7fc03a444700) = 0
mprotect(0x7fc03a227000, 16384, PROT_READ) = 0
mprotect(0x7fc03a450000, 4096, PROT_READ) = 0
munmap(0x7fc03a446000, 30251)           = 0
brk(0)                                  = 0x188d000
brk(0x18ae000)                          = 0x18ae000
open("file.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
write(3, "Test string\n", 12)           = 12
exit_group(12)                          = ?
root@3:~# cat file.txt
Test string
root@3:~# 

怎么会发生这种事呢?

答案1

您可以写入该文件,因为您是用户root。考虑以下:

> cat file.txt
> ls -al file.txt
-r--------  1 sdanna  staff  0 Sep 21 20:43 file.txt
> ./a.out
Segmentation fault: 11
> sudo ./a.out
> cat file.txt
Test string 

这里 ./a.out 是您提供的程序。正如您所看到的,当我以普通用户身份运行该命令时,当我尝试对失败的 fopen 返回的空指针进行操作时,我收到了分段错误。

如果我运行该命令,root它工作正常。 root 用户始终可以写入文件,除非更改文件的扩展属性以防止修改。这路径分辨率(7)Linux 上的手册页很好地总结了情况:

在传统的UNIX系统上,超级用户(root,用户ID 0)拥有一切权力,在访问文件时可以绕过所有权限限制。

在 Linux 上,超级用户权限分为功能(请参阅功能(7))。有两个功能与文件权限检查相关:CAP_DAC_OVERRIDE 和 CAP_DAC_READ_SEARCH。 (如果进程的 fsuid 为 0,则该进程具有这些功能。)

CAP_DAC_OVERRIDE 功能会覆盖所有权限检查,但仅当设置了文件的三个执行权限位中的至少一个时才授予执行权限。

CAP_DAC_READ_SEARCH 功能授予对目录的读取和搜索权限以及对普通文件的读取权限。

Linux 上的 root 用户具有这两种所需的功能。

相关内容