はじめに (対象読者・この記事でわかること)
この記事は、Linuxシステムの管理・運用に携わるエンジニアや、サーバー構築・保守を学び始めた方向けに書いています。
読み終えることで、rootユーザーがなぜUID・GIDともに「0」で定義されているのか、その歴史的・技術的背景がわかります。また、root権限を悪用されるリスクや、最小権限の原則に基づいた運用方法、setuid/setuidビットの仕組みまで網羅的に理解できます。日々の運用で「とりあえずsudo」で済ませず、セキュリティを意識した設計・運用が行えるようになることを目指します。
前提知識
この記事を読み進める上で、以下の知識があるとスムーズです。 - Linuxの基本的なコマンド操作(ls, chmod, chownなど) - プロセス・ファイルの所有権・パーミッションの概念 - /etc/passwd, /etc/group の役割と書式
rootとは何か、なぜUID=0なのか
Unix系OSが誕生した1970年代、当時のシステムは今日と比べてはるかにシンプルでした。ユーザーを区別するための識別子として「数値」が採用され、0番は「スーパーユーザー」として特別扱いされました。0はプログラム的に最も簡単に判定できる値であり、カーネル内部での分岐処理を高速にするための選択でした。以後、System V、BSD、Linuxへと受け継がれ、今でもroot=0という仕様は揺るがれることがありません。カーネルソースの kernel/sys.c における current_uid() の比較処理を見ても、単純に uid == 0 というチェックがベタ打ちされていることがわかります。これは速度だけでなく、誤って一般ユーザーに高い権限が与えられるリスクを排除するためでもあります。
UID・GID=0の挙動とセキュリティリスク
ステップ1:実際にUID=0のプロセスを観察する
まず、root権限で任意のコマンドを実行したとき、プロセスのUID/GIDがどうなるか確認しましょう。
Bash# 対話的にrootシェルを起動 $ sudo -s # whoami コマンドで名前を、id コマンドで数値を確認 # whoami root # id uid=0(root) gid=0(root) groups=0(root)
/proc/self/status を見れば、カーネルが保持している情報が丸見えです。
Bash# cat /proc/self/status | grep -E 'Uid|Gid' Uid: 0 0 0 0 Gid: 0 0 0 0
4列の数字はそれぞれ「実UID」「実GID」「効果的UID」「効果的GID」を表しており、rootでは全て0に収まっていることがわかります。
ステップ2:setuidビットで一般ユーザーから権限昇降する
次に、setuidビットを付与した自作バイナリを使って、一般ユーザーが一時的にUID=0の権限を得る流れを見てみましょう。
C// save_root.c #include <unistd.h> #include <stdio.h> int main(){ setuid(0); // 実UIDを0に setgid(0); // 実GIDを0に system("/bin/bash"); return 0; }
コンパイルし、所有権をrootにしてsetuidビットを付与します。
Bash$ gcc save_root.c -o save_root $ sudo chown root:root save_root $ sudo chmod 4755 save_root # 4xxx が setuid ビット
一般ユーザーで実行すると、bashプロンプトが # になり、idコマンドでもUID=0が確認できます。
この仕組みは passwd コマンドなどで広く使われていますが、悪用されると「バックドア」となります。setuidバイナリの監視は find / -perm -4000 -type f 2>/dev/null で可能です。定期的にリスト化しておき、不審なファイルが出現していないかを確認しましょう。
ハマった点:「rootぽい」UIDを作っても権限が通じない
セキュリティ研修で「UID=0でないけどrootっぽい名前を付けたユーザー」を作り、権限が昇格するか試してみたことがあります。
Bash# useradd -u 1000 -g 0 fake_root # passwd fake_root # su - fake_root $ id uid=1000(fake_root) gid=0(root) groups=0(root)
GIDは0でも、UIDが0でなければカーネルは特権を認めません。つまり「GID=0」は単に「rootグループに属している」に過ぎず、特権プロセス化には繋がらないのです。勘違いして「rootグループに入れておけば何でもできる」と運用してしまうと、後々大きな事故につながります。
解決策:最小権限の原則とsudoの活用
rootのUID=0を前提にした運用を避けるには、以下の3つを守ります。
-
ログイン可能なUID=0アカウントを複数作らない
デフォルトの「root」以外にUID=0のユーザーを作ると、ログイン記録が分散し追跡が困難になります。 -
必要なコマンドだけをsudoで許可する
/etc/sudoersにusername ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginxのように限定して記述し、汎用コマンドは許可しない。 -
setuidビットの付与を禁止するポリシーを敷く
開発環境ではmount -o remount,nosuid /homeのように、setuidビットが無効なファイルシステムオプションを使うと、意図せぬバイナリの作成を防げます。
まとめ
本記事では、rootユーザーのUID・GIDが0に固定されている歴史的・技術的背景と、それを悪用されないための運用方法を解説しました。
- Unix誕生当初から「0 = スーパーユーザー」として特別扱いされ、今日に至るまで変更されていない
- setuidビットを付与されたバイナリは、一時的にUID=0となり任意の権限でコードを実行できる
- UID=0でない限り、GIDを0にしてもカーネルは特権を認めない
- 最小権限の原則に基づき、sudoでコマンド単位の制限を行い、setuidビットの監視を習慣化する
rootのUID=0という仕様は、Linuxカーネルの根幹をなす設計であり、今後も変わる可能性は低いです。だからこそ、正しく理解してリスクを最小化する運用を心がけましょう。次回は、capabilities(7)を使った「root以外の部分特権」や、namespace隔離によるroot権限のサンドボックス化について掘り下げていきます。
参考資料
- Linuxカーネルソース
kernel/sys.ckernel/user.c man 7 credentialsman 2 setuid- Linuxのsetuidビットとセキュリティリスクまとめ
- NIST Special Publication 800-53 AC-6 (Least Privilege)
