説明
権限のチェックを行う観点から見ると、伝統的な
UNIX の実装では
プロセスは二つのカテゴリーに分類できる:
特権 プロセス
(実効ユーザーID が 0
のプロセス。ユーザーID
0 は
スーパーユーザーや
root と呼ばれる) と
非特権 プロセス
(実効ユーザーID が 0
以外のプロセス)
である。
非特権プロセスでは、プロセスの資格情報
(通常は、実効UID
、実効GID
と追加のグループリスト)
に基づく権限チェックが行われるのに対し、
特権プロセスでは全てのカーネルの権限チェックがバイパスされる。
バージョン 2.2
以降の Linux では、
これまでスーパーユーザーに結び付けられてきた権限を、
いくつかのグループに分割している。これらのグループは
ケーパビリティ(capability)
と呼ばれ、グループ毎に独立に有効、無効を設定できる。
ケーパビリティはスレッド単位の属性である。
ケーパビリティのリスト
以下のリストは、
Linux
で実装されているケーパビリティと
各ケーパビリティが許可する操作と動作をまとめたものである。
- CAP_AUDIT_CONTROL
(Linux 2.6.11 以降)
- カーネル監査 (audit)
の有効無効の切り替え、
監査のフィルタルールの変更、
監査の状況やフィルタルールの取得ができる。
- CAP_AUDIT_READ
(Linux 3.16 以降)
- マルチキャスト netlink
ソケット経由で監査ログの読み出しができる。
- CAP_AUDIT_WRITE
(Linux 2.6.11 以降)
- カーネル監査のログにレコードを書き込む。
- CAP_BLOCK_SUSPEND
(Linux 3.5 以降)
- システムのサスペンドをブロックできる機能を使用する
(epoll(7) EPOLLWAKEUP,
/proc/sys/wake_lock)。
- CAP_CHOWN
- ファイルの UID とGID
を任意に変更する
(chown(2) 参照)。
- CAP_DAC_OVERRIDE
- ファイルの読み出し、書き込み、実行の権限チェックをバイパスする
(DAC は "discretionary access control
(任意のアクセス制御)"
の略である)。
- CAP_DAC_READ_SEARCH
- CAP_FOWNER
- 通常、プロセスのファイルシステム
UID がファイルの UID
に一致することが
要求される操作
(例えば chmod(2), utime(2))
における権限チェックをバイパスする。
但し、 CAP_DAC_OVERRIDE か
CAP_DAC_READ_SEARCH
によりチェックが行われる操作は除く。
- 任意のファイルに対して拡張ファイル属性を設定する
(chattr(1) 参照)。
- 任意のファイルに対してアクセス制御リスト
(ACL) を設定する。
- ファイルの削除の際にディレクトリのスティッキービットを無視する。
- open(2) や fcntl(2)
で任意のファイルに対して
O_NOATIME を指定する。
- CAP_FSETID
- ファイルが変更されたときに
set-user-ID とset-group-ID
の許可ビットをクリア
しない。呼び出し元プロセスのファイルシステム
GID と追加の GID
のいずれとも GID
が一致しないファイルに対して
set-group-ID
ビットを設定する。
- CAP_IPC_LOCK
- メモリーのロック
(mlock(2), mlockall(2), mmap(2), shmctl(2))
を行う。
- CAP_IPC_OWNER
- System V IPC
オブジェクトに対する操作に関して権限チェックをバイパスする。
- CAP_KILL
- シグナルを送信する際に権限チェックをバイパスする
(kill(2) 参照)。これには
ioctl(2) の KDSIGACCEPT
操作の使用も含まれる。
- CAP_LEASE
(Linux 2.4 以降)
- 任意のファイルに対して
ファイルリースを設定する
(fcntl(2) 参照)。
- CAP_LINUX_IMMUTABLE
- inode フラグ FS_APPEND_FL と
FS_IMMUTABLE_FL を設定する
(chattr(1) 参照)。
- CAP_MAC_ADMIN
(Linux 2.6.25 以降)
- 強制アクセス制御 (MAC)
を上書きする。 Smack Linux
Security Module (LSM)
用に実装されている。
- CAP_MAC_OVERRIDE
(Linux 2.6.25 以降)
- MAC
の設定や状態を変更する。
Smack LSM
用に実装されている。
- CAP_MKNOD
(Linux 2.4 以降)
- (Linux 2.4 以降) mknod(2)
を使用してスペシャルファイルを作成する。
- CAP_NET_ADMIN
- 各種のネットワーク関係の操作を実行する:
- インターフェースの設定
- IP
のファイアウォール、マスカレード、アカウンティング
- ルーティングテーブルの変更
- 透過的プロキシでの任意のアドレスの割り当て
(bind)
- サービス種別 (type-of-service; TOS)
のセット
- ドライバの統計情報のクリア
- promiscuous
モードをセットする
- マルチキャストを有効にする
- setsockopt(2)
を使って以下のソケットオプションを設定する:
SO_DEBUG, SO_MARK, SO_PRIORITY
(優先度を 0 から 6
以外に設定する場合),
SO_RCVBUFFORCE, and SO_SNDBUFFORCE
- CAP_NET_BIND_SERVICE
- インターネットドメインの特権ポート
(ポート番号が 1024
番未満)
をバインドできる。
- CAP_NET_BROADCAST
- (未使用)
ソケットのブロードキャストと、マルチキャストの待ち受けを行う。
- CAP_NET_RAW
- RAW ソケットと PACKET
ソケットを使用する。
- 透過的プロキシでの任意のアドレスの割り当て
(bind)
- CAP_SETGID
- プロセスの GID
と追加の GID
リストに対する任意の操作を行う。
UNIX
ドメインソケット経由でソケットの資格情報
(credential) を渡す際に 偽の GID
を渡すことができる。
ユーザー名前空間にグループ
ID
マッピングを書き込むことができる
(user_namespaces(7) 参照)。
- CAP_SETFCAP
(Linux 2.6.24 以降)
- ファイルケーパビリティを設定する。
- CAP_SETPCAP
- ファイルケーパビリティがサポートされていない場合:
呼び出し元が許可されているケーパビリティセットに含まれる任意のケーパビリティを、
他のプロセスに付与したり、削除したりできる。
(カーネルがファイルケーパビリティをサポートしている場合、
CAP_SETPCAP
はこの役割を持たない。
なぜなら、ファイルケーパビリティをサポートしているカーネルでは
CAP_SETPCAP
は全く別の意味を持つからである。)
ファイルケーパビリティがサポートされている場合:
呼び出し元スレッドのバウンディングセットの任意のケーパビリティを
自身の継承可能ケーパビリティセットに追加できる。
(prctl(2) PR_CAPBSET_DROP
を使って)
バウンディングセットからケーパビリティを削除できる。
securebits
フラグを変更できる。
- CAP_SETUID
- プロセスの UID
に対する任意の操作
(setuid(2), setreuid(2), setresuid(2),
setfsuid(2)) を行う。 UNIX
ドメインソケット経由でソケットの資格情報
(credential) を渡す際に 偽の UID
を渡すことができる。
ユーザー名前空間にユーザー
ID
マッピングを書き込むことができる
(user_namespaces(7) 参照)。
- CAP_SYS_ADMIN
- 以下のシステム管理用の操作を実行する:
quotactl(2), mount(2), umount(2), swapon(2),
swapoff(2), sethostname(2), setdomainname(2).
- 特権が必要な syslog(2)
の操作を実行する (Linux
2.6.37
以降では、このような操作を許可するには
CAP_SYSLOG
を使うべきである)
- VM86_REQUEST_IRQ vm86(2)
コマンドを実行する。
- 任意の System V IPC
オブジェクトに対する
IPC_SET と IPC_RMID
操作を実行する。
- RLIMIT_NPROC
リソース制限を上書きする。
- 拡張属性 trusted と security
に対する操作を実行する
(attr(5) 参照)。
- lookup_dcookie(2)
を呼び出す。
- ioprio_set(2) を使って I/O
スケジューリングクラス
IOPRIO_CLASS_RT, IOPRIO_CLASS_IDLE
を割り当てる (IOPRIO_CLASS_IDLE
は Linux 2.6.25
より前のバージョンのみ)。
- UNIX
ドメインソケットでソケットの資格情報
(credential) を渡す際に偽の UID
を渡す。
- ファイルをオープンするシステムコール
(例えば accept(2), execve(2),
open(2), pipe(2))
でシステム全体でオープンできるファイル数の上限
/proc/sys/fs/file-max
を超過する。
- clone(2) と unshare(2)
で新しい名前空間を作成する
CLONE_*
フラグを利用する
(ただし、 Linux 3.8
以降では、ユーザー名前空間の作成にどのケーパビリティも必要としない)。
- perf_event_open(2)
を呼び出す。
- 特権が必要な perf
イベントの情報にアクセスする。
- setns(2) を呼び出す (target
名前空間での CAP_SYS_ADMIN
が必要)。
- fanotify_init(2)
を呼び出す。
- keyctl(2) の KEYCTL_CHOWN と
KEYCTL_SETPERM
操作を実行する。
- madvise(2) の MADV_HWPOISON
操作を実行する。
- TIOCSTI ioctl(2) を使って、
呼び出し元の制御端末以外の端末の入力キューに文字を挿入する。
- 廃止予定の nfsservctl(2)
システムコールを使用する。
- 廃止予定の bdflush(2)
システムコールを使用する。
- 特権が必要なブロックデバイスに対する各種の
ioctl(2) 操作を
実行する。
- 特権が必要なファイルシステムに対する各種の
ioctl(2) 操作を
実行する。
- 多くのデバイスドライバに対する管理命令を実行する。
- CAP_SYS_BOOT
- reboot(2) と kexec_load(2)
を呼び出す。
- CAP_SYS_CHROOT
- chroot(2). を呼び出す。
- CAP_SYS_MODULE
- カーネルモジュールのロード、アンロードを行う
(init_module(2) と delete_module(2)
を参照のこと)。
バージョン 2.6.25
より前のカーネルで、
システム全体のケーパビリティバウンディングセット
(capability bounding set)
からケーパビリティを外す。
- CAP_SYS_NICE
- CAP_SYS_PACCT
- acct(2) を呼び出す。
- CAP_SYS_PTRACE
- CAP_SYS_RAWIO
- I/O
ポート操作を実行する
(iopl(2)、 ioperm(2))。
- /proc/kcore
にアクセスする。
- FIBMAP ioctl(2)
操作を使用する。
- x86
モデルに固有のレジスター
(MSR レジスター群、
msr(4) 参照)
にアクセスするためのデバイスをオープンする。
- /proc/sys/vm/mmap_min_addr
を更新する。
- /proc/sys/vm/mmap_min_addr
で指定された値よりも小さなアドレスにメモリーマッピングを作成する。
- /proc/bus/pci
にあるファイルをマップする。
- /dev/mem や /dev/kmem
をオープンする。
- 各種の SCSI
デバイスコマンドを実行する。
- hpsa(4) デバイスや cciss(4)
デバイスの特定の操作を実行する。
- 他のデバイスに対して各種のデバイス固有命令を実行する。
- CAP_SYS_RESOURCE
- ext2
ファイルシステム上の予約されている領域を使用する。
- ext3
のジャーナル機能を制御する
ioctl(2) を使用する。
- ディスク quota
の上限を上書きする。
- リソース上限を増やす
(setrlimit(2))。
- RLIMIT_NPROC
リソース制限を上書きする。
- コンソール割り当てにおいてコンソールの最大数を上書きする。
- キーマップの最大数を上書きする。
- リアルタイムクロックから秒間
64
回を越える回数の割り当てが許可する。
- メッセージキューに関する上限
msg_qbytes を /proc/sys/kernel/msgmnb
に指定されている上限よりも大きく設定する
(msgop(2) と msgctl(2) 参照)。
- F_SETPIPE_SZ fcntl(2)
を使ってパイプの容量を設定する際に
上限 /proc/sys/fs/pipe-size-max
を上書きする。
- /proc/sys/fs/pipe-max-size
に指定されている上限を超えてパイプの容量
を増やすのに F_SETPIPE_SZ
を使用する。
- POSIX
メッセージキューを作成する際に、
上限 /proc/sys/fs/mqueue/queues_max
を上書きする (mq_overview(7)
参照)。
- prctl(2) PR_SET_MM
操作を使用する。
- CAP_SYS_RESOURCE
を持ったプロセスによって最後に設定された値よりも小さな値を
/proc/PID/oom_score_adj
に設定する。
- CAP_SYS_TIME
- システムクロックを変更する
(settimeofday(2), stime(2), adjtimex(2))。
リアルタイム
(ハードウェア)
クロックを変更する。
- CAP_SYS_TTY_CONFIG
- vhangup(2) を使用する。
特権が必要な仮想端末に関する各種の
ioctl(2)
操作を利用できる。
- CAP_SYSLOG
(Linux 2.6.37 以降)
- 特権が必要な syslog(2)
操作を実行できる。
どの操作が特権が必要かについての情報は
syslog(2) を参照。
- /proc/sys/kernel/kptr_restrict の値が 1
の場合、 /proc
や他のインターフェース経由で公開されているカーネルアドレスを参照する
(proc(5) の kptr_restrict
の議論を参照)。
- CAP_WAKE_ALARM
(Linux 3.0 以降)
- システムを起こすトリガーを有効にする
(タイマー CLOCK_REALTIME_ALARM や
CLOCK_BOOTTIME_ALARM
を設定する)。
過去と現在の実装
完全な形のケーパビリティを実装するには、以下の要件を満たす必要がある:
- 1.
- 全ての特権操作について、カーネルはそのスレッドの実効ケーパビリティセットに
必要なケーパビリティがあるかを確認する。
- 2.
- カーネルで、あるスレッドのケーパビリティセットを変更したり、
取得したりできるシステムコールが提供される。
- 3.
- ファイルシステムが、実行可能ファイルにケーパビリティを付与でき、ファイル
実行時にそのケーパビリティをプロセスが取得できるような機能をサポートする。
カーネル 2.6.24
より前では、最初の
2つの要件のみが満たされている。
カーネル 2.6.24
以降では、3つの要件すべてが満たされている。
スレッドケーパビリティセット
各スレッドは以下の
3種類のケーパビリティセットを持つ。各々のケーパビリティセットは
上記のケーパビリティの組み合わせである
(全てのケーパビリティが無効でもよい)。
- 許可 (permitted):
- そのスレッドが持つことになっている実効ケーパビリティの
限定的なスーパーセットである。
これは、実効ケーパビリティセットに
CAP_SETPCAP
ケーパビリティを持っていないスレッドが継承可能ケーパビリティセットに
追加可能なケーパビリティの限定的なスーパーセットでもある。
許可ケーパビリティセットから削除してしまったケーパビリティは、
(set-user-ID-root
プログラムか、
そのケーパビリティをファイルケーパビリティで許可しているプログラムを
execve(2) しない限りは)
もう一度獲得することはできない。
- 継承可能 (inheritable):
- execve(2)
を前後で保持されるケーパビリティセットである。
この仕組みを使うことで、あるプロセスが
execve(2)
を行う際に新しいプログラムの許可ケーパビリティセットとして
割り当てるケーパビリティを指定することができる。
- 実効 (effective):
- カーネルがスレッドの権限
(permission)
をチェックするときに
使用するケーパビリティセットである。
fork(2)
で作成される子プロセスは、親のケーパビリティセットのコピーを継承する。
execve(2)
中のケーパビリティの扱いについては下記を参照のこと。
capset(2)
を使うと、プロセスは自分自身のケーパビリティセット
を操作することができる
(下記参照)。
Linux 3.2 以降では、
ファイル /proc/sys/kernel/cap_last_cap
で、
実行中のカーネルでサポートされているケーパビリティの最大値を参照できる。
この情報を使って、
ケーパビリティセットに設定される可能性がある最上位ビットを判定することができる。
ファイルケーパビリティ
カーネル 2.6.24
以降では、 setcap(8)
を使って実行ファイルにケーパビリティセットを対応付けることができる。
ファイルケーパビリティセットは
security.capability
という名前の拡張属性に保存される
(setxattr(2)
参照)。この拡張属性への書き込みには
CAP_SETFCAP
ケーパビリティが必要である。
ファイルケーパビリティセットとスレッドのケーパビリティセットの両方が
考慮され、 execve(2)
後のスレッドのケーパビリティセットが決定される。
3
つのファイルケーパビリティセットが定義されている。
- 許可 (Permitted)
(以前の強制 (Forced)):
- スレッドの継承可能ケーパビリティに関わらず、そのスレッドに自動的に
認められるケーパビリティ。
- 継承可能 (Inheritable)
(以前の 許容 (Allowed)):
- このセットと、スレッドの継承可能ケーパビリティセットとの
論理積 (AND) がとられ、
execve(2)
の後にそのスレッドの許可ケーパビリティセットで有効となる
継承可能ケーパビリティが決定される。
- 実効 (effective):
- これは集合ではなく、1
ビットの情報である。
このビットがセットされていると、
execve(2)
実行中に、そのスレッドの新しい許可ケーパビリティが全て
実効ケーパビリティ集合においてもセットされる。
このビットがセットされていない場合、
execve(2)
後には新しい許可ケーパビリティのどれも新しい実効ケーパビリティ集合
にセットされない。
ファイルの実効ケーパビリティビットを有効にするというのは、
execve(2)
実行時に、ファイルの許可ケーパビリティと継承ケーパビリティに対応するものが
スレッドの許可ケーパビリティセットとしてセットされるが、
これが実効ケーパビリティセットにもセットされるということである
(ケーパビリティの変換ルールは下記参照)。
したがって、ファイルにケーパビリティを割り当てる際
(setcap(8), cap_set_file(3), cap_set_fd(3))、
いずれかのケーパビリティに対して実効フラグを有効と指定する場合、
許可フラグや継承可能フラグを有効にした他の全てのケーパビリティ
についても実効フラグを有効と指定しなければならない。
execve(2)
実行時に、カーネルはプロセスの新しいケーパビリティを次の
アルゴリズムを用いて計算する:
P'(permitted) = (P(inheritable) & F(inheritable)) |
(F(permitted) & cap_bset)
P'(effective) = F(effective) ? P'(permitted) : 0
P'(inheritable) = P(inheritable) [つまり、変更されない]
各変数の意味は以下の通り:
ケーパビリティと、ルートによるプログラムの実行
execve(2)
時に、ケーパビリティセットを使って、全ての権限を持った
root
を実現するには、以下のようにする。
- 1.
- set-user-ID-root
プログラムが実行される場合、
またはプロセスの実ユーザー
ID が 0 (root) の場合、
ファイルの継承可能セットと許可セットを全て
1
(全てのケーパビリティが有効)
に定義する。
- 2.
- set-user-ID-root
プログラムが実行される場合、
ファイルの実効ケーパビリティビットを
1 (enabled) に定義する。
上記のルールにケーパビリティ変換を適用した結果をまとめると、
プロセスが set-user-ID-root
プログラムを execve(2)
する場合、または実効
UID が 0
のプロセスがプログラムを
execve(2)
する場合、許可と実効のケーパビリティセットの全ケーパビリティ
(正確には、ケーパビリティバウンディングセットによるマスクで除外されるもの
以外の全てのケーパビリティ)
を取得するということである。
これにより、伝統的な
UNIX
システムと同じ振る舞いができるようになっている。
ケーパビリティバウンディングセット
ケーパビリティバウンディングセット
(capability bounding set) は、 execve(2)
時に獲得できるケーパビリティを制限するために使われる
セキュリティ機構である。
バウンディングセットは以下のように使用される。
- execve(2)
実行時に、ケーパビリティバウンディングセットと
ファイルの許可ケーパビリティセットの論理積
(AND) を取ったものが、
そのスレッドの許可ケーパビリティセットに割り当てられる。
つまり、ケーパビリティバウンディングセットは、
実行ファイルが認めている許可ケーパビリティに対して
制限を課す働きをする。
- (Linux 2.6.25 以降)
ケーパビリティバウンディングセットは、スレッドが
capset(2)
により自身の継承可能セットに追加可能なケーパビリティの母集団を
制限する役割を持つ。
スレッドに許可されたケーパビリティであっても、バウンディングセットに
含まれていなければ、スレッドはそのケーパビリティは自身の継承可能セットに
追加できず、その結果、継承可能セットにそのケーパビリティを含むファイルを
execve(2)
する場合、そのケーパビリティを許可セットに持ち続けることができない、
ということである。
バウンディングセットがマスクを行うのは、継承可能ケーパビリティではなく、
ファイルの許可ケーパビリティのマスクを行う点に注意すること。
あるスレッドの継承可能セットにそのスレッドのバウンディングセットに
存在しないケーパビリティが含まれている場合、そのスレッドは、
継承可能セットに含まれるケーパビリティを持つファイルを実行することにより、
許可セットに含まれるケーパビリティも獲得できるということである。
カーネルのバージョンにより、ケーパビリティバウンディングセットは
システム共通の属性の場合と、プロセス単位の属性の場合がある。
Linux 2.6.25
より前のケーパビリティバウンディングセット
2.6.25
より前のカーネルでは、ケーパビリティバウンディングセットは
システム共通の属性で、システム上の全てのスレッドに適用される。
バウンディングセットは
/proc/sys/kernel/cap-bound
ファイル経由で参照できる。
(間違えやすいが、このビットマスク形式のパラメーターは、
/proc/sys/kernel/cap-bound
では符号付きの十進数で表現される。)
init
プロセスだけがケーパビリティバウンディングセットで
ケーパビリティをセットすることができる。
それ以外では、スーパーユーザー
(より正確には、
CAP_SYS_MODULE
ケーパビリティを持ったプログラム)
が、
ケーパビリティバウンディングセットのケーパビリティのクリアが
できるだけである。
通常のシステムでは、ケーパビリティバウンディングセットは、
CAP_SETPCAP
が無効になっている。
この制限を取り去るには
(取り去るのは危険!)、
include/linux/capability.h 内の CAP_INIT_EFF_SET
の定義を修正し、カーネルを再構築する必要がある。
システム共通のケーパビリティバウンディングセット機能は、
カーネル 2.2.11 以降で Linux
に追加された。
Linux 2.6.25
以降のケーパビリティバウンディングセット
Linux 2.6.25 以降では、
「ケーパビリティバウンディングセット」はスレッド単位の属性である
(システム共通のケーパビリティバウンディングセットはもはや存在しない)。
バウンディングセットは
fork(2)
時にはスレッドの親プロセスから継承され、
execve(2)
の前後では保持される。
スレッドが CAP_SETPCAP
ケーパビリティを持っている場合、そのスレッドは
prctl(2) の PR_CAPBSET_DROP
操作を使って自身のケーパビリティバウンディングセットから
ケーパビリティを削除することができる。
いったんケーパビリティをバウンディングセットから削除してしまうと、
スレッドはそのケーパビリティを再度セットすることはできない。
prctl(2) の PR_CAPBSET_READ
操作を使うことで、スレッドがあるケーパビリティが自身のバウンディングセット
に含まれているかを知ることができる。
バウンディングセットからのケーパビリティの削除がサポートされるのは、
カーネルのコンパイル時にファイルケーパビリティが有効になっている場合
だけである。Linux 2.6.33
より前のカーネルでは、ファイルケーパビリティは
設定オプション
CONFIG_SECURITY_FILE_CAPABILITIES
で切り替えられる追加の
機能であった。Linux 2.6.33
以降では、この設定オプションは削除され、
ファイルケーパビリティは常にカーネルに組込まれるようになった。
ファイルケーパビリティがカーネルにコンパイル時に組み込まれている場合、
(全てのプロセスの先祖である)
init
プロセスはバウンディングセットで
全てのケーパビリティが
セットされた状態で開始する。ファイルケーパビリティ
が有効になっていない場合には、
init
はバウンディングセットで
CAP_SETPCAP
以外の全てのケーパビリティがセットされた状態で開始する。
このようになっているのは、
CAP_SETPCAP
ケーパビリティがファイルケー
パビリティがサポートされていない場合には
違った意味を持つからである。
バウンディングセットからケーパビリティを削除しても、
スレッドの継承可能セットからはそのケーパビリティは削除されない。
しかしながら、バウンディングセットからの削除により、
この先そのケーパビリティをスレッドの継承可能セットに追加すること
はできなくなる。
ユーザー ID
変更のケーパビリティへの影響
ユーザー ID が 0 と 0
以外の間で変化する際の振る舞いを従来と同じにするため、
スレッドの実 UID、実効
UID、保存
set-user-ID、ファイルシステム
UID が (setuid(2), setresuid(2)
などを使って)
変更された際に、カーネルはそのスレッドのケーパビリティセットに
以下の変更を行う:
- 1.
- UID の変更前には実
UID、実効 UID、保存 set-user-ID
のうち
少なくとも一つが 0
で、変更後に実
UID、実効 UID、保存 set-user-ID
が すべて 0
以外の値になった場合、許可と実効のケーパビリティセットの
全ケーパビリティをクリアする。
- 2.
- 実効 UID が 0 から 0
以外に変更された場合、
実効ケーパビリティセットの全ケーパビリティをクリアする。
- 3.
- 実効 UID が 0 以外から 0
に変更された場合、
許可ケーパビリティセットの内容を実効ケーパビリティセットにコピーする。
- 4.
- ファイルシステム UID
が 0 から 0
以外に変更された場合
(setfsuid(2)
参照)、実効ケーパビリティセットの以下のケーパビリティがクリアされる:
CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH,
CAP_FOWNER, CAP_FSETID, CAP_LINUX_IMMUTABLE (Linux
2.6.30 以降), CAP_MAC_OVERRIDE, CAP_MKNOD (Linux
2.6.30 以降)。
ファイルシステム UID
が 0 以外から 0
に変更された場合、
上記のケーパビリティのうち許可ケーパビリティセットで有効になっているものが
実効ケーパビリティセットで有効にされる。
各種 UID
のうち少なくとも一つが
0 であるスレッドが、
その UID の全てが 0
以外になったときに許可ケーパビリティセットが
クリアされないようにしたい場合には、
prctl(2) の PR_SET_KEEPCAPS
操作を使えばよい。
プログラムでケーパビリティセットを調整する
各スレッドは、
capget(2) や capset(2)
を使って、自身のケーパビリティセットを取得したり変更したりできる。
ただし、これを行うには、
libcap
パッケージで提供されている
cap_get_proc(3) や cap_set_proc(3)
を使うのが望ましい。
スレッドのケーパビリティセットの変更には以下のルールが適用される。
- 1.
- 呼び出し側が CAP_SETPCAP
ケーパビリティを持っていない場合、新しい継承可能セットは、
既存の継承可能セットと許可セットの積集合
(AND) の部分集合で
なければならない。
- 2.
- (Linux 2.6.25 以降)
新しい継承可能セットは、既存の継承可能セットとケーパビリティ
バウンディングセットの積集合
(AND)
の部分集合でなければならない。
- 3.
- 新しい許可セットは、既存の許可セットの部分集合でなければならない
(つまり、そのスレッドが現在持っていない許可ケーパビリティを
獲得することはできない)。
- 4.
- 新しい実効ケーパビリティセットは新しい許可ケーパビリティセットの
部分集合になっていなければならない。
カーネル 2.6.26
以降で、
ファイルケーパビリティが有効になったカーネルでは、
スレッド単位の securebits
フラグが実装されており、このフラグを使うと
UID 0 (root)
に対するケーパビリティの特別扱いを無効することができる。
以下のようなフラグがある。
- SECBIT_KEEP_CAPS
- このフラグをセットされている場合、UID
が 0 のスレッドの UID が 0
以外の値に
切り替わる際に、そのスレッドはケーパビリティを維持することができる。
このフラグがセットされていない場合には、UID
が 0 から 0 以外の値に
切り替わると、そのスレッドは全てのケーパビリティを失う。
このフラグは execve(2)
時には全てクリアされる
(このフラグは、以前の
prctl(2) の PR_SET_KEEPCAPS
操作と同じ機能を提供するものである)。
- SECBIT_NO_SETUID_FIXUP
- このフラグをセットすると、スレッドの実効
UID
とファイルシステム
UID が 0 と 0
以外の間で切り替わった場合に、
カーネルはケーパビリティセットの調整を行わなくなる
(「ユーザー ID
変更のケーパビリティへの影響」の節を参照)。
- SECBIT_NOROOT
- このビットがセットされている場合、
set-user-ID-root
プログラムの実行時や、
実効 UID か 実 UID が 0
のプロセスが execve(2)
を呼び出した時に、カーネルはケーパビリティを許可しない
(「ケーパビリティと、ルートによるプログラムの実行」の節を参照)。
上記の "base"
フラグの各々には対応する
"locked"
フラグが存在する。
いずれの "locked"
フラグも一度セットされると戻すことはできず、
それ以降は対応する
"base"
フラグを変更することができなくなる。
"locked" フラグは
SECBIT_KEEP_CAPS_LOCKED, SECBIT_NO_SETUID_FIXUP_LOCKED,
SECBIT_NOROOT_LOCKED
という名前である。
securebits フラグは、
prctl(2) の操作 PR_SET_SECUREBITS や
PR_GET_SECUREBITS
を使うことで変更したり取得したりできる。
フラグを変更するには
CAP_SETPCAP
ケーパビリティが必要である。
securebits
フラグは子プロセスに継承される。
execve(2) においては、
SECBIT_KEEP_CAPS
が常にクリアされる以外は、全てのフラグが保持される。
アプリケーションは、以下の呼び出しを行うことにより、
自分自身および子孫となるプロセス全てに対して、
必要なファイルケーパビリティを持ったプログラムを実行しない限り、
対応するケーパビリティを獲得できないような状況に閉じこめることができる。
prctl(PR_SET_SECUREBITS,
SECBIT_KEEP_CAPS_LOCKED |
SECBIT_NO_SETUID_FIXUP |
SECBIT_NO_SETUID_FIXUP_LOCKED |
SECBIT_NOROOT |
SECBIT_NOROOT_LOCKED);
注意
カーネル 2.5.27
以降、ケーパビリティは選択式のカーネルコンポーネント
となっており、カーネル設定オプション
CONFIG_SECURITY_CAPABILITIES
により有効/無効を切り替えることができる。
/proc/PID/task/TID/status
ファイルを使うと、スレッドのケーパビリティセットを見ることができる。
/proc/PID/status
ファイルには、プロセスのメインスレッドのケーパビリティセットが表示される。
Linux 3.8 より前では、
これらのケーパビリティセットの表示で、
存在しないケーパビリティはすべて有効
(1) として表示される。
Linux 3.8 以降では、
存在しないケーパビリティはすべて無効
(0) として表示される。
(CAP_LAST_CAP
より大きい値を持つケーパビリティが存在しないケーパビリティである)。
libcap
パッケージは、ケーパビリティを設定・取得するための
ルーチン群を提供している。これらのインターフェースは、
capset(2) と capget(2)
が提供するインターフェースと比べて、より使いやすく、変更される可能性が少ない。
このパッケージでは、
setcap(8), getcap(8)
というプログラムも提供されている。
パッケージは以下で入手できる。
http://www.kernel.org/pub/linux/libs/security/linux-privs.
バージョン 2.6.24
より前、およびファイルケーパビリティが
有効になっていない2.6.24
以降のカーネルでは、
CAP_SETPCAP
ケーパビリティを持ったスレッドは自分以外のスレッドの
ケーパビリティを操作できる。
しかしながら、これは理論的に可能というだけである。
以下のいずれかの場合においても、どのスレッドも
CAP_SETPCAP
ケーパビリティを持つことはないからである。
- 2.6.25
より前の実装では、システム共通のケーパビリティバウンディングセット
/proc/sys/kernel/cap-bound
ではこのケーパビリティは常に無効になっており、
ソースを変更してカーネルを再コンパイルしない限り、
これを変更することはできない。
- 現在の実装ではファイルケーパビリティが無効になっている場合、
プロセス毎のバウンディングセットからこのケーパビリティを抜いて
init は開始され、
システム上で生成される他の全てのプロセスでこのバウンディングセットが
継承される。