私は "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から返されたNULLポインタを操作しようとすると、分割エラーが発生します。
コマンドを実行するとうまくroot
いきます。変更を防ぐために、ファイルの拡張属性が変更されない限り、root ユーザーは常にファイルに書き込むことができます。これパス解像度(7)Linuxのマニュアルページは状況を非常によくまとめています。
既存のUNIXシステムでは、スーパーユーザー(root、userid 0)はすべての権限を持ち、ファイルにアクセスするときにすべての権限制限をバイパスできます。
Linuxでは、スーパーユーザー権限は機能で区切られています(機能(7)を参照)。ファイル権限の確認に関連する関数には、CAP_DAC_OVERRIDEとCAP_DAC_READ_SEARCHの2つがあります。 (fsuidが0の場合、プロセスはこれらの機能を持ちます。)
CAP_DAC_OVERRIDE 機能はすべての権限チェックを無視しますが、ファイルの 3 つの実行権限ビットのうち 1 つ以上が設定されている場合にのみ実行権限を付与します。
CAP_DAC_READ_SEARCH 関数は、ディレクトリに対する読み取りおよび検索権限、および一般ファイルに対する読み取り権限を付与します。
Linuxのrootユーザーは、これらの必須機能をすべて備えています。