write () chamada do sistema ignora as permissões do arquivo

3

Eu fiz um programa muito simples em C que escreve "Test string" no arquivo chamado "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:~#

Eu criei um arquivo chamado "file.txt" antes de executar o test :

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

Como visto acima, file.txt tem apenas permissões de leitura. No entanto, se eu executar o test , a "string de teste" será gravada em "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, "7ELF
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:~#
root@3:~# ls -l file.txt 
-r-------- 1 root root 0 sept  21 22:28 file.txt
root@3:~#
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, "7ELF%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%>%pre%%pre%%pre%%pre%07%pre%%pre%%pre%%pre%%pre%"..., 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:~# 
%pre%%pre%%pre%%pre%%pre%%pre%%pre%>%pre%%pre%%pre%%pre%07%pre%%pre%%pre%%pre%%pre%"..., 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:~#

Como isso pode acontecer?

    
por Martin 21.09.2014 / 21:35

1 resposta

6

Você pode gravar no arquivo porque é o usuário root . Considere o seguinte:

> 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 

Aqui ./a.out é o seu programa apresentado. Como você pode ver, quando executo o comando como um usuário normal, recebo uma falha de segmentação quando tento operar no ponteiro nulo retornado pelo fopen com falha.

Se eu executar o comando como root , tudo funcionará bem. O usuário root sempre pode gravar no arquivo, a menos que os atributos estendidos do arquivo sejam alterados para impedir a modificação. A página do manual path_resolution (7) no linux, resume bem a situação:

On a traditional UNIX system, the superuser (root, user ID 0) is all- powerful, and bypasses all permissions restrictions when accessing files.

On Linux, superuser privileges are divided into capabilities (see capabilities(7)). Two capabilities are relevant for file permissions checks: CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH. (A process has these capabilities if its fsuid is 0.)

The CAP_DAC_OVERRIDE capability overrides all permission checking, but grants execute permission only when at least one of the file's three execute permission bits is set.

The CAP_DAC_READ_SEARCH capability grants read and search permission on directories, and read permission on ordinary files.

O usuário root no Linux possui os dois recursos necessários.

    
por 21.09.2014 / 21:49