前回からだいぶ間隔が空いてしまいました。前回の最後に案内したudzuraさんのCRIUに関する記事はもう少し時間がかかるようですので,
今回から数回は,
setuid
一般的にはUNIX系のOSでは,
一般ユーザは,pingコマンドは特権が必要で,setuidされており,
cmd
$ ls -l $(which ping)
-rwsr-xr-x 1 root root 64424 Jun 28 20:05 /bin/ping
↑(このsがsetuidされている印)ケーパビリティ
先に紹介したpingコマンドは,setuidされており,
逆に言うとRawソケットを使うのに必要な権限のみが必要なのに,pingコマンドに渡していることになります。これはセキュリティ上の観点から望ましいことではありません。
Linuxにはこのような場合に使える,
例えば,CAP_というケーパビリティがあればRawソケットを使用できます。Linuxカーネルでは,/usr/で定義されています。
$ grep "#define CAP_" /usr/include/linux/capability.h
#define CAP_CHOWN 0
#define CAP_DAC_OVERRIDE 1
#define CAP_DAC_READ_SEARCH 2
#define CAP_FOWNER 3
#define CAP_FSETID 4
#define CAP_KILL 5
:(略)ケーパビリティの実装は結構古くて,capabilities(7)に載っています。
プロセスのケーパビリティ
プロセス
- Permitted
- EffectiveとInheritableで持つことを許されるケーパビリティセット
- Inheritable
execve(2)した際に継承できるケーパビリティセット- Effective
- 実際にカーネルがスレッドの実行権限を判定するのに使うケーパビリティセット
- Ambient
- 特権のない
(setuid/ setgidされていない) プログラムを execve(2)した際に子プロセスに継承されるケーパビリティセット(Linux 4. 3以降で使用可能)
さらに,
実際にカーネルがプロセスが持つ権限をチェックする時は,
そして,
capset(2):システムコールでケーパビリティを設定するexecve(2):システムコールの前後でケーパビリティが変化するprctl(2):システムコールでAmbientケーパビリティやバウンディングセットを設定する
execve(2)システムコールはプログラムを実行するためのシステムコールです。このシステムコールとケーパビリティの関係については次回で説明します。
実行中のプロセスが持つケーパビリティを確認する
では実際にプロセスでケーパビリティがどのように設定されているかを見てみましょう。
プロセス/proc/<PID>/statusファイルで確認できます。例えばPIDが1であるinitのPermittedCapPrm),CapEff),CapBnd)
$ grep Cap /proc/1/status CapInh: 0000000000000000 CapPrm: 0000003fffffffff CapEff: 0000003fffffffff CapBnd: 0000003fffffffff CapAmb: 0000000000000000
特定のケーパビリティだけが設定されている,ntpdは次のようになっています。
$ grep Cap /proc/$(pgrep ntpd)/status CapInh: 0000000000000000 CapPrm: 0000000002000400 CapEff: 0000000002000400 CapBnd: 0000003fffffffff CapAmb: 0000000000000000
上記の例のように status ファイルでケーパビリティを確認できます。しかし,
もう少しわかりやすくプロセスのケーパビリティセットを確認したい場合はlibcapに含まれるgetpcapsコマンドが使えますlibcap2-binパッケージに含まれています)。
$ getpcaps $(pgrep ntpd) Capabilities for `21935': = cap_net_bind_service,cap_sys_time+ep
ポート番号1024番未満を使うには特権が必要です。しかし,ntpdは一般ユーザであるntpユーザ権限で動作しており,ntpdで使うポートである123番ポートは使えないはずです。しかし,cap_を持っているので123番ポートを使えます。
また,cap_を持っていますので,
つまりntpdは必要最低限のケーパビリティのみを持った状態で実行されているということです。不要な特権を持たずにデーモンが実行されていますので,