write() 시스템 호출이 파일 권한을 무시합니다.

write() 시스템 호출이 파일 권한을 무시합니다.

나는 "file.txt"라는 파일에 "테스트 문자열"을 쓰는 매우 간단한 프로그램을 C로 작성했습니다.

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잘 작동합니다. 수정을 방지하기 위해 파일의 확장 속성이 변경되지 않는 한 루트 사용자는 항상 파일에 쓸 수 있습니다. 이것경로 해상도(7)Linux의 매뉴얼 페이지는 상황을 매우 잘 요약합니다.

기존 UNIX 시스템에서는 수퍼유저(루트, 사용자 ID 0)가 모든 권한을 가지며 파일에 액세스할 때 모든 권한 제한을 우회할 수 있습니다.

Linux에서는 수퍼유저 권한이 기능으로 구분됩니다(기능 (7) 참조). 파일 권한 확인과 관련된 함수는 CAP_DAC_OVERRIDE와 CAP_DAC_READ_SEARCH 두 가지가 있습니다. (fsuid가 0인 경우 프로세스는 이러한 기능을 갖습니다.)

CAP_DAC_OVERRIDE 기능은 모든 권한 검사를 무시하지만 파일의 세 가지 실행 권한 비트 중 하나 이상이 설정된 경우에만 실행 권한을 부여합니다.

CAP_DAC_READ_SEARCH 함수는 디렉터리에 대한 읽기 및 검색 권한과 일반 파일에 대한 읽기 권한을 부여합니다.

Linux의 루트 사용자는 이러한 필수 기능을 모두 갖추고 있습니다.

관련 정보