UNIX/Linuxの部屋 用語集:setuid

TOP UNIX/Linuxの部屋 UNIX/Linuxコマンド一覧 用語集 新版 由来/読み方辞書 環境変数マニュアル Cシェル変数 システム設定ファイル システムコール・ライブラリ ネットワークプログラミングの基礎知識 クラウドサービス徹底比較・徹底解説




用語集 setuid 特定の権限でコマンドを実行する仕組み (suid・s-bit・sbit) このエントリーをはてなブックマークに追加

最終更新


setuid とは、UNIX/Linux において、root など特定の権限でプログラムやコマンドを実行する仕組みである。



setuid の基礎
UNIX/Linux において passwd コマンドでパスワードを変更したり、chsh コマンドでログイン時のシェルを変更したりすることができる。これらの情報は /etc/passwd や /etc/shadow (または /etc/master.passwd) などに保存されている。

ここでよ〜く考えてみよう。つまり passwd コマンドや chsh コマンドは、/etc/passwd・/etc/shadow などのファイルを更新するということだ。しかしながら、んこれらのファイルは、一般ユーザが書き換えできないようにパーミッションが設定されている。
% 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 や chsh のバイナリのパーミッションを見てみよう。
% ls -l /usr/bin/{passwd,chsh}
-r-sr-xr-x 6 root bin 36864 Mar 14 1999 /usr/bin/chsh
-r-sr-xr-x 2 root bin 32768 Jul 22 1998 /usr/bin/passwd
パーミッションの最初の部分が「r-s」となっていることに注意してほしい。「s」という文字は
「そのコマンドが所有者の権限で実行される」
という意味である。/usr/bin/chsh・/usr/bin/passwd というファイルの所有者は root なので、一般ユーザが /usr/bin/chsh を実行すると、root の権限を得ることになる。そのコマンドが終了すると root 権限は失われる。

setuid の使われ方
UNIX/Linux において、setuid という仕組みは、かなり広い範囲で使われている。
% ls -l /{,usr/,usr/local/}{,s}bin/ | grep 'r[-w]s'
としてみるとわかる通り、passwd・chsh に始まって、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 プログラムを作成
実際に 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
(略)
これで一般ユーザが、一時的に (コマンドを実行中の間だけ) 特別な権限を取得できたわけである。

スクリプトの setuid
バイナリは上記のとおり setuid することができた。ではスクリプトを 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 されているので、誰のユーザ権限にでも移行できる。

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

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