はじめに (対象読者・この記事でわかること)

この記事は、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つを守ります。

  1. ログイン可能なUID=0アカウントを複数作らない
    デフォルトの「root」以外にUID=0のユーザーを作ると、ログイン記録が分散し追跡が困難になります。

  2. 必要なコマンドだけをsudoで許可する
    /etc/sudoersusername ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx のように限定して記述し、汎用コマンドは許可しない。

  3. 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権限のサンドボックス化について掘り下げていきます。

参考資料