[unix] スティッキーなビット?

2017年3月21日火曜日

linux unix

Unixのファイル権限

Unixのファイル権限は読み/書き/実行が4/2/1のビットで表されていて、ファイルの"オーナー/グループに所属するユーザ/それ以外"がそれぞれが8進数の1桁に割り当てられている。
例えば、あるファイルが
  • オーナーは読み書き実行OK
  • グループに所属するユーザは読み実行のみOK
  • それ以外は読み実行のみOK
であれば、"755"ということになる。

でも、もう一つ上の桁がある。

SUID,SGID

もう一つ上の桁はSUID,SGID,スティッキービットと呼ばれているものを指定する。
読み/書き/実行が4/2/1のビットで表されているようにSUID,SGIDにもビットが割り当てられており、SUID/SGID/スティッキービットがそれぞれ4/2/1となっている。

SUID(Set User ID)をオンにすると、そのファイルの実行時にプロセスの実効ユーザがプロセスを起動したユーザではなく、ファイルのオーナーになる。
例えば、以下のようなプログラムでプロセスの実ユーザ(real user ID)と実効ユーザ(effective user ID)を表示させてみよう。

uid.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void) {
    uid_t uid = getuid();
    uid_t euid = geteuid();
    printf("uid: %d, euid: %d\n", uid, euid);

    return 0;
}
これをuidとeuidというファイルにコピーして、euidにのみSUIDをセットすると

$ ls -l
合計 32
-rwxr-xr-x 1 user users 12651  2月 18 21:43 euid
-rwxr-xr-x 1 user users 12651  2月 18 21:43 uid
$ chmod u+s euid
$ ls -l
合計 32
-rwsr-xr-x 1 user users 12651  2月 18 21:43 euid
-rwxr-xr-x 1 user users 12651  2月 18 21:43 uid
$ sudo ./euid
uid: 0, euid: 1000
$ sudo ./uid
uid: 0, euid: 0

euidは実ユーザと実効ユーザのユーザIDが異なっていることがわかる。
この場合、sudoを使ってrootで実行しているので、実ユーザのユーザIDは0になっている。
また、SUIDがセットされるとファイルのオーナー実行権限が"s"で表示される。

実際にsuidが役に立つ身近な例としてはpasswdコマンドがある。

$ ls -l /usr/bin/passwd 
-rwsr-xr-x 1 root shadow 51200  9月 28  2013 /usr/bin/passwd

なので、passwdは通常ユーザが実行してもrootで実行される。

ユーザではなく、実行時のグループを切り替えるのはSGID(Set Group ID)。こちらは"chmod g+s"でセットする。

スティッキービット

Linuxではスティッキービットはディレクトリに対して指定する。セットは"chmod o+t"で行う。
スティッキービットがセットされるとそのディレクトリにあるファイルはファイルオーナーでなければ削除や移動ができなくなる。
スティッキービットがセットされているディレクトリとしては"/tmp"がある。

$ ls -ld /tmp
drwxrwxrwt 28 root root 12288  2月 18 21:53 /tmp

なので、ファイルの削除に対して、厳格なルールを適用したい場合に使う。

それにしても、なんでスティッキー(sticky)なんて奇妙な用語で呼ばれてるんだろうか?
Linuxではディレクトリ内のファイルに対しての権限を設定するけど、その昔のUnixではこのビットは別の用途に使われていた。

https://linuxjm.osdn.jp/html/gnumaniak/man1/chmod.1.html
によると

POSIX では `sticky bit' について記述していない。 その名前は本来の意味から来ている: プログラムコードをスワップ上に維持する。

スティッキービットがセットされているとプロセスが終了しても、スワップ領域に命令コードを保持するようにしていた。 なんでこんなことをしていたかと言うと、よく使うプログラムを少しでも速く起動するためだったみたい。
メモリ容量が大きくなって、よく使うプログラムはメモリ上にキャッシュされるようになったので、こういう特別な動作は必要なくなったんだね。

ともかくプロセスが終了してもへばりつく(sticky)ようになるといったことから、スティッキービットという名前がついて、それが今でも残っているということのようだ。