setsuid で実行ユーザが固定できるってのはどこまで?
シェルスクリプトってsuidできなかったよね。ということを確認してみる。
suidを試してみる。
まずは、suid を素直に試してみることにする。 実行可能なバイナリを準備する。
#include <pwd.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> int main ( char** args, int argc ){ printf("user is %s\n", getlogin()); struct passwd* pw = getpwuid(geteuid()); printf("euid is %s\n", pw->pw_name ); }
これをコンパイルして実行してみる。
takuya@:~$ gcc test.c -o out takuya@:~$ ./out user is takuya euid is takuya
ちゃんと、実行ユーザ(euid)と現在のログインユーザ(user)が表示される。
setsuid してみる。
takuya@:~$ sudo chown www-data:www-data out takuya@:~$ sudo chmod u+s out takuya@:~$ ./out user is takuya euid is www-data takuya@:~$
今度は、実行ユーザ(euid)がwww-data になり、ちゃんと別ユーザーで実行されていることがわかる。
シェルスクリプトならどうだ? できないね。そうだね。
#!/usr/bin/env bash whoami who | awk '{ print $1 }'
sudo ならユーザIDが変化するけど。
takuya@:~$ sudo -u www-data ./sample.sh www-data takuya takuya@:~$ sudo ./sample.sh root takuya
chmod でsuidをやってみると。
takuya@:~$ sudo chown www-data sample.sh takuya@:~$ sudo chmod u+s sample.sh takuya@:~$ ll sample.sh -rwsrwxr-x 1 www-data www-data 56 11月 9 13:34 sample.sh* takuya@:~$ ./sample.sh takuya takuya
なぜなら、シェルスクリプトを実行したら、 shebang指定されたbashが起動し、ボディ文字列が標準入力(的なナニカ)としてbashへ渡されるだけである。
そのためsetsuidで実行できるわけがない。
代替手段
sudo を使う場合
これで、rootとして実行される。
#!/usr/bin/env bash [ "root" != "$USER" ] && exec sudo $0 "$@" whoami who | awk '{ print $1 }'
これで、www-dataとして実行される。
#!/usr/bin/env bash [ "www-data" != "$USER" ] && exec sudo sudo -u www-data $0 "$@" whoami who | awk '{ print $1 }'
suid は難しい問題。
set suid の設定これは、すごく不思議な問題で、トラブルが多いので、とても慎重に考える必要がある。いちばん簡単で安全なのは、set suid したコマンドを ~/.bin に設定しておいておくことである。たとえば、bashをコピーしset suid して別の場所に設置するが考えられるが、セキュリティ・ホールを生み出してしまう。だからSUIDDでShebangを使うのは難しい。どうしても必要ならコマンドを実行(execv)するコマンドをCやRUST/Goで記述して、バイナリ実行する必要がある。
とりあえず、suid はシェルスクリプトは対象外。と覚えておくことにする。
この話は掘り下げると「沼」だとわかったのでここまで。