UNIX/Linuxの部屋 用語集:setuid 特定の権限でコマンドを実行する仕組み (suid・s-bit・sbit)


※空白区切りで AND 検索 (例:「ファイル 削除」)

用語集 setuid 特定の権限でコマンドを実行する仕組み (suid・s-bit・sbit)

passwd・chpass などのコマンドを使うと、ユーザのログインシェルやパスワードなどの個人情報を変更できる。これらの情報は /etc/passwd や /etc/master.passwd などに保存されるわけである。

ここでよ〜く考えてみよう。つまり passwd や chpass は /etc/passwd や /etc/master.passwd などのファイルを更新するということだ。もちろんこれらのファイルは、一般ユーザが書き換えできないようにパーミッションが設定されている。
% ls -l /etc/passwd /etc/master.passwd
-rw------- 1 root wheel 994 Sep 26 20:00 /etc/master.passwd
-rw-r--r-- 1 root wheel 793 Sep 26 20:00 /etc/passwd
なぜコマンドを実行しているのは一般ユーザなのに、root しか書き換えられないはずのファイルを書き換えることができるのだろうか?

その秘密が setuid (suid・sbit) である。ls で passwd や chpass のバイナリのパーミッションを見てみよう。
% ls -l /usr/bin/{passwd,chpass}
-r-sr-xr-x 6 root bin 36864 Mar 14 1999 /usr/bin/chpass
-r-sr-xr-x 2 root bin 32768 Jul 22 1998 /usr/bin/passwd
パーミッションの最初の部分が「r-s」となっていることに注意してほしい。「s」という文字は
「そのコマンドが所有者の権限で実行される」
という意味である。/usr/bin/chpass・/usr/bin/passwd というファイルの所有者は root なので、一般ユーザが /usr/bin/chpass を実行すると、root の権限を得ることになる。そのコマンドが終了すると root 権限は失われる。

UNIX において、setuid という仕組みは、かなり広い範囲で使われている。
% ls -l /{,usr/,usr/local/}{,s}bin/ | grep 'r[-w]s'
としてみるとわかる通り、passwd・chpass に始まって、login・man・procmail・rcp・ping・traceroute・shutdown・crontab なども setuid されている。

例えば man には catman という仕組みがあり、一度参照されたマニュアルは /usr/share/man/cat? にプレインテキストの形で保存しておく必要がある。しかし /usr/share/man/cat? は
% ls -ld /usr/share/man/cat1/
drwxr-xr-x 2 man bin 1024 Oct 10 13:57 /usr/share/man/cat1/
と、一般ユーザが書き込めるようにはなっていない。そのため man コマンドは
% ls -l `which man`
-r-sr-xr-x 1 man bin 28672 Jul 22 1998 /usr/bin/man
と、ユーザ man の権限で動くようになっている。

また、ping・traceroute コマンドは raw socket という低レベルのネットワーク機能を使っているのだが、raw socket は root 権限がないと使うことができない。しかし一般ユーザにも ping・traceroute コマンドを使うことができるように、このように root に setuid されているわけだ。
% ls -l `which ping traceroute`
-r-sr-xr-x 1 root bin 139264 Jul 22 1998 /sbin/ping
-r-sr-xr-x 1 root bin 16384 Jul 22 1998 /usr/sbin/traceroute

setgid (sgid) も同様に、
「そのコマンドが所有グループの権限で実行される」
ことを意味する。例えば procmail は
% ls -l `which procmail`
-rwsr-sr-x 1 root mail 65536 Jun 30 1998 /usr/local/bin/procmail
と、「rwsr-s」となっている。これは、procmail コマンド実行時に、
「実効ユーザは root、実効グループは mail」
として動作する (つまり procmail は suid+sgid されているということ)。

では、実際に setuid なプログラムを作成してみよう。シャドウパスワードである /etc/master.passwd は一般ユーザでは見ることができないが、これを一般ユーザでも見られるようなコマンドを作る(シャドウパスワードは /etc/shadow となっている OS もある)。
#include <stdio.h>
#define shadow_passwd "/etc/master.passwd"
main(){
FILE *fp;
char buf[256];

fp = fopen(shadow_passwd,"r");
if ( fp == NULL ){
perror(shadow_passwd);
exit(1);
}
while (1){
if ( fgets(buf,sizeof(buf),fp) == NULL ) break;
printf("%s",buf);
}
}
という内容の cat-shadow.c というソースを作り、
% cc -o cat-shadow cat-shadow.c
でバイナリを作成する。では実行してみよう。
% ./cat-shadow
/etc/master.passwd: Permission denied
一般ユーザは /etc/master.passwd を見ることはできないのだから当然エラーになる。では、このプログラムを suid してみよう。現在は
% ls -l cat-shadow
-rwxr-xr-x 1 user group 8808 Oct 10 16:05 cat-shadow
というパーミッションになっている。root になって
% su (root になる)
# chown root cat-shadow (ファイルのオーナーを root に)
# chmod 4755 cat-shadow (sbit を立てる)
これで cat-shadow が root に suid された。
% ls -l cat-shadow
-rwsr-xr-x 1 root group 8808 Oct 10 16:05 cat-shadow
ちゃんと「rws」になっていることを確認してほしい。では再度実行。
% ./cat-shadow
root:$1$7.KA4$3NMQsk3vjh33yNm.GROmA0:0:0::0:0:Charlie &:/root:/bin/csh
toor:*:0:0::0:0:Bourne-again Superuser:/root:
daemon:*:1:1::0:0:Owner of many system processes:/root:/sbin/nologin
(略)
これで一般ユーザが、一時的に (コマンドを実行中の間だけ) 特別な権限を取得できたわけである。

では、スクリプトを suid できるのだろうか?
#!/bin/sh
/bin/cat /etc/master.passwd
というスクリプトを作って、
% su
# chown root cat-shadow.sh (ファイルのオーナーを root に)
# chmod 4755 cat-shadow.sh (sbit を立てる)
としても、
% ./cat-shadow.sh
cat: /etc/master.passwd: Permission denied
となる。つまりスクリプトの suid bit は無視されるわけである。これには深い理由があるのだが割愛。

しかし perl スクリプトだけは別である。perl は スクリプトが suid されているかどうかを調べ、suid されていたら suidperl を起動する。suidperl 自体が
% ls -l `which suidperl`
---s--x--x 2 root wheel 458752 Jun 30 1998 /usr/local/bin/suidperl
と root に suid されているので、誰のユーザ権限にでも移行できる。

最後に注意。suid はとても危険である。root に suid されたコマンドにセキュリティホールがあると、そのホストのセキュリティは無いも同然。例えば chpass コマンドは、環境変数 EDITOR で指定されているプログラムを実行する。しかし単純に EDITOR で指定されたプログラムを実行すると、悪意を持ったユーザが
% env EDITOR="rm -rf /" chpass
とすることで、root 権限で rm -rf / が実行されることになる。これを避けるために、実際の chpass では、/etc/master.passwd や /etc/passwd などを書き換えるときだけ root 権限になり、それ以外の部分では一般ユーザ権限で動作するようにプログラムされている。また、環境変数 PATH などにも気をつけなければならない。

sudo コマンドを使うと、指定したユーザが指定したコマンドを実行できるようにすることができる。


頑張って書いたおすすめコンテンツ!