読み書き禁止ファイルを変更できてしまう謎

これは30日チャレンジの9日目(2019/09/17)に書かれた文章です

Linuxで開発したことがあるエンジニアならpasswdコマンドを知っているだろう。 コマンド名が示すとおり、ログインパスワードを変更するコマンドだ。

ではパスワードを記したファイルは一体どこにあるのだろうか。 これも知ってるエンジニアは多いだろう。 /etc/passwd にはユーザー名、(暗号化された)パスワード、ログインシェルなどログイン時に必要な情報が一行ごとに保存されている。 また最近のLinuxディストリビューションでは、もはやパスワードは/etc/passwdに保存せずに/etc/shadowに移すことで安全性を高めているようだ。

無論、上記ファイルが一般ユーザから不要に読み書きされるようなことがあってはならない。 パーミッション設定によれば、/etc/passwd/etc/shadowともにrootのみ読み書きが許され、 /etc/shadowに至っては一般ユーザは読み込みさえ禁止されている。

root@be281876e6b0:/app# ls -al /etc/shadow /etc/passwd
-rw-r--r-- 1 root root   1236 Sep  4  2018 /etc/passwd
-rw-r----- 1 root shadow  652 Sep  4  2018 /etc/shadow

しかしここでひとつ疑問が浮かんでくる。 読み込みできないはずの/etc/shadowがどうして一般ユーザが実行したpasswdコマンド(/usr/bin/passwd)によって変更されるのだろうか。

一般に、ユーザが実行したプロセスは実行ユーザの権限をもってファイル読み書きを行う。 したがって、例えば読み込み権限のないファイルを表示しようとしても当然エラーが発生する。 それにもかかわらずpasswdコマンドで/etc/shadowの書き換えが可能なのだとしたら、なにか全く別の機構が隠れているのかもしれない。

sat0yu@b61abff74dc3:/$ ls -al hoge 
-rw------- 1 root root 0 Sep 17 14:19 hoge 
sat0yu@b61abff74dc3:/$ cat hoge 
cat: hoge: Permission denied

じつはこの隠れた機構こそが、本文を書くに至った今日の学びである。 答えから先に記すと、それは「セットユーザID (SUID)」と呼ばれる機構だ。

SUIDは読み/書き/実行と並ぶ特殊なアクセス権である。 このアクセス権をもつ実行ファイルは、実行ユーザではなく所有ユーザのアクセス権限で処理を行う。 すなわち、まさに我々がpasswdで抱えていた疑問に対する回答となる。

実際にpasswdコマンドのアクセス権限を確認してみると、通常は実行権限「x」が埋まる箇所(passwdコマンドの所有者権限)には代わりに「s」が記されている。

sat0yu@b61abff74dc3:/$ ls -al /usr/bin/passwd 
-rwsr-xr-x 1 root root 59680 May 17 2017 /usr/bin/passwd

SUIDはpasswdコマンドが代表格としてあげられるが、その他にもWebサーバーのような常時稼働する実行形式にも利用されることがある。 すなわち「起動時にポート80をListenするにはrootが必要だが、一度起動してしまえば権限を降格しても構わない」といったユースケースにも有用なのだ。

ちなみにSUIDは下記コマンドで設定することができる。 あまり頻繁に使うことはないかもしれないが、知識として持っておくと便利だろう。

chmod u+s file

ちなみに、本文を書くきっかけとなった今日の学びは「詳解UNIXプログラミング」から得た。 Webエンジニアとして普段からアプリケーションコードを書いていると、自ずと学びの範囲が狭まってきてしまう。 「詳解UNIXプログラミング」のような色褪せない名著は、知識の外縁を広げて新しい学びを得るための格好の材料となるだろう。