第12章 パーミッション応用とリンク

LPIC-1 104.5〜104.7 相当

初級第6章のrwx権限に加えて、より高度な権限設定と、リンクの仕組みを扱います。

特殊な権限ビット: SUID・SGID・スティッキービット

特殊ビット数値ファイルへの効果
SUID4000実行時に、実行したユーザーではなく「所有者」の権限で動作する(例: passwdコマンド)
SGID2000ディレクトリに設定すると、その中に作成されたファイルの所有グループが親ディレクトリと同じになる
スティッキービット1000ディレクトリに設定すると、他人が作成したファイルを自分は削除できなくなる(例: /tmp)
$ chmod 4755 /usr/bin/passwd   # SUIDを設定(先頭の4)
$ chmod 1777 /tmp              # スティッキービットを設定(先頭の1)
$ chmod 2755 /srv/shared       # SGIDを設定(先頭の2)
$ ls -l /usr/bin/passwd
-rwsr-xr-x  root root  ...  /usr/bin/passwd   # xの位置がsになっている
$ chmod u+s script.sh          # シンボルモードでSUIDを付与することもできる

特殊ビットは4桁目の数字(4000・2000・1000)として表現するほかに、シンボルモードでは所有者に対するs(SUID)、グループに対するs(SGID)、その他に対するt(スティッキービット)として表示されます。もし本来 x 権限がない箇所に特殊ビットが設定されていると、小文字ではなく大文字のSやTで表示され、「実行権限がないのに特殊ビットだけ設定されている」という不自然な状態を示します。

注意: SUIDはセキュリティ上のリスクにもなり得ます。もしSUIDが設定された実行ファイルに脆弱性があると、実行しただけで所有者(多くはroot)の権限が奪われる可能性があります。むやみに一般の実行ファイルへSUIDを設定するのは避け、本当に必要なファイルだけに限定するのが安全な運用です。

umask — 新規作成時の既定権限

新しくファイルやディレクトリを作成したとき、既定でどの権限を「与えないか」を決めるのが umask です。ファイルの最大権限は666(実行ビットを含まない)、ディレクトリの最大権限は777であり、そこからumaskで指定した値を差し引いた(正確にはビット単位でマスクした)値が、実際の既定権限になります。

$ umask
0022
$ touch newfile.txt
$ ls -l newfile.txt
-rw-r--r--  ...  newfile.txt   # ファイルの既定666からumask 022を引いた644になる
$ mkdir newdir
$ ls -ld newdir
drwxr-xr-x  ...  newdir        # ディレクトリの既定777からumask 022を引いた755になる
$ umask 077                  # より厳しい既定値に変更(自分以外はアクセス不可に。設定自体は無出力)
$ umask
0077

この行のこの値に注目: umask 077の実行自体は何も表示しませんが、直後に引数なしのumaskを実行すると、設定した値(0077)が反映されていることを確認できます。この状態で新規作成したファイルは所有者以外アクセスできない600・700になります。

umaskの値はシェルの設定として持続するため、/etc/profileや~/.bashrcなどにumask 022のように記述しておくと、ログインするたびに同じ既定値が適用されます。共有サーバーで機密性の高い作業をするユーザーには、umaskを077のように厳しく設定して、他人からファイルを読み書きされないようにする運用もよく行われます。

ハードリンクとシンボリックリンク

種類特徴
ハードリンク同じ実体(inode)を指す別名。元ファイルを消してもリンク先は残る。ディレクトリやファイルシステムをまたいでは作成不可。
シンボリックリンク(symlink)パスを指す「ショートカット」のようなもの。元ファイルを消すとリンク切れになる。ディレクトリやファイルシステムをまたいで作成可能。
$ ln original.txt hardlink.txt      # ハードリンク作成
$ ln -s original.txt symlink.txt    # シンボリックリンク作成(-s)
$ ls -l symlink.txt
lrwxrwxrwx  ...  symlink.txt -> original.txt
$ ls -li original.txt hardlink.txt
1234567 -rw-r--r--  2  ...  original.txt
1234567 -rw-r--r--  2  ...  hardlink.txt   # -i でinode番号を表示。両者が同じinode番号を共有している

ls -lの2列目に表示される数字は「リンクカウント」で、そのinodeに対して何個の名前(ハードリンク)が存在するかを示します。上の例では2になっており、original.txtとhardlink.txtという2つの名前が同じ実体を指していることが分かります。ファイルを完全に削除する(実体のデータが解放される)のは、このリンクカウントが0になったときです。そのためrm original.txtを実行しても、hardlink.txtからは引き続き同じ内容を参照できます。

試験対策: ハードリンクはディレクトリに対しては(一部の特殊なケースを除き)作成できません。これはディレクトリ構造の循環参照を防ぐための制限です。ディレクトリへのリンクが必要な場合はシンボリックリンクを使います。
original.txt hardlink.txt inode 1234567 リンクカウント: 2 同じ実体を指す名前が2つ データブロック (実際のファイル内容) symlink.txt inode 9988776 内容: "original.txt" 名前解決 (毎回パスを辿る)
inode・ディレクトリエントリ・データブロックの関係。original.txtとhardlink.txtはどちらも同じinode(実体)を指しているため、片方を消してももう片方から中身にアクセスできます。一方symlink.txtは自分専用のinodeを持ち、その中身は"original.txt"というパス文字列にすぎないため、参照先を消すとリンク切れになります。

ファイルの所有者・所有グループの変更

権限(rwx)はそのままに、「誰の」ものかを変更するコマンドがchown・chgrpです。

$ sudo chown alice file.txt         # 所有者をaliceに変更
$ sudo chown alice:staff file.txt   # 所有者をalice、所有グループをstaffに変更
$ sudo chown :staff file.txt        # 所有グループだけをstaffに変更
$ sudo chgrp staff file.txt         # 所有グループだけを変更(chownの:staffと同じ結果)
$ sudo chown -R alice:staff /srv/app # -R でディレクトリ配下を再帰的に変更
注意: 一般ユーザーは自分が所有するファイルであっても、所有者を他人に変更する(chownで明け渡す)ことはできません。所有者の変更にはroot権限が必要です。

FHS(Filesystem Hierarchy Standard)とファイルの配置

Linuxのディレクトリ構成は、FHSという標準でおおまかな役割が決められています。適切な場所にファイルを置くことは、システム管理の基本です。

ディレクトリ役割
/etcシステム全体の設定ファイル
/varログやキャッシュなど、内容が変化し続けるデータ
/usrユーザーが利用するプログラムやライブラリ(起動に必須ではないもの)
/optパッケージ管理システムの管理外で追加された、独立したアプリケーション一式
/srvそのシステムが提供するサービス用のデータ(Webサイトのコンテンツなど)
/tmp一時ファイル。再起動時に消去されることがある
/home一般ユーザーのホームディレクトリ
/rootrootユーザーのホームディレクトリ(/homeの下ではなく直下にある点に注意)

FHSに沿った配置を守ることで、パッケージ管理システムが「どこに何を置くべきか」を機械的に判断できるようになり、複数のディストリビューション間でもある程度共通したディレクトリ構成が保たれます。自作のスクリプトやアプリケーションを配置する際も、/optや/usr/localのような「システムのパッケージ管理と衝突しない場所」を選ぶのがマナーとされています。

/ /etc — システム全体の設定ファイル /var — ログやキャッシュなど変化し続けるデータ /usr — アプリ本体・ライブラリ(起動に必須ではない) /opt — パッケージ管理の管理外にある独立アプリ一式 /srv — このシステムが提供するサービス用データ /tmp — 一時ファイル(再起動時に消えることがある) /home — 一般ユーザーのホームディレクトリ /root — rootユーザーのホームディレクトリ(/homeの外)
FHS(Filesystem Hierarchy Standard)の主要ディレクトリ。いずれもルート「/」直下に置かれ、役割ごとに置き場所が決められています。/rootだけは/homeの中ではなくルート直下にある点に注意してください。

find コマンドとパーミッションの組み合わせ

この章で扱った特殊ビットやリンクは、findコマンドの検索条件としてもよく利用されます。

$ find / -perm -4000 -type f 2>/dev/null   # SUIDが設定されたファイルを検索
$ find /var/log -type l                     # シンボリックリンクだけを検索
$ find / -nogroup 2>/dev/null                # 所有グループが存在しない(削除済みグループの)ファイルを検索
補足コラム: セキュリティ監査では「不必要にSUID/SGIDが設定されたファイルがないか」「所有者不明のファイルが残っていないか」を定期的に棚卸しすることが推奨されます。この節で紹介したfindコマンドの条件は、そうした点検作業でそのまま活用できます。

ACL(アクセス制御リスト)による、より柔軟な権限設定

ここまで扱ってきた「所有者・グループ・その他」の3種類の権限指定では、「特定の1人にだけ追加で権限を与えたい」といった細かい制御はできません。この限界を超えるために用意されているのがACL(Access Control List)です。setfaclで特定のユーザー・グループ単位の権限を追加し、getfaclで現在の設定を確認します。

$ setfacl -m u:bob:rw file.txt      # 所有者はaliceのままだが、bobにも読み書き権限を追加
$ getfacl file.txt                  # 設定されているACLを一覧表示

ACLが設定されているファイルは、ls -lの権限表記の末尾に+記号が付くので見分けられます。プロジェクトの共有ディレクトリで「基本は所有者のみアクセス可、ただし特定のメンバーだけ追加で書き込みを許可したい」といった細かい要件に対応する際に使われる、一歩進んだ権限管理の手段です。

デフォルトACLで新規ファイルの権限を自動化する

共有ディレクトリでは、新しく作られるファイルにも自動的にACLを引き継がせたい場面があります。setfacl -d(default)オプションでディレクトリにデフォルトACLを設定しておくと、そのディレクトリ内に新しく作成されるファイル・サブディレクトリに同じACLが自動的に適用されます。

$ setfacl -d -m u:bob:rw /srv/shared    # /srv/sharedに作られる新規ファイルへ自動でbobの権限を継承

これを設定しておかないと、共有ディレクトリの中に新しいファイルが作られるたびに毎回setfaclを打ち直す必要があり、運用上の手間とヒューマンエラーの原因になります。継続的にファイルが追加される共有領域を運用する際は、デフォルトACLの設定を忘れないようにしましょう。

確認クイズ

Q1. SUIDビットが設定された実行ファイルの動作として正しいものはどれですか?

解説: SUIDが設定されたファイルは、実行したユーザーに関わらず、そのファイルの所有者の権限で動作します。passwdコマンドなどで使われています。

Q2. 共有ディレクトリの/tmp によく設定されている、他人が作成したファイルを自分では削除できなくする特殊ビットはどれですか?

解説: スティッキービット(数値1000)が設定されたディレクトリでは、自分が所有するファイルしか削除できなくなります。/tmpに標準で設定されています。

Q3. ハードリンクとシンボリックリンクの違いとして正しいものはどれですか?

解説: ハードリンクは同じ実体(inode)を指すため、元ファイル(片方の名前)を消してもリンク先は有効です。シンボリックリンクはパスを参照するだけなので、元ファイルを消すとリンク切れになります。

Q4. umaskの役割として正しいものはどれですか?

解説: umaskは新規作成時の既定権限(ファイル666、ディレクトリ777)から、指定した分の権限を差し引く役割を持ちます。