【Kernel Documentation 和訳】No New Privileges Flag

No New Privileges Flag(和訳)

execveシステムコールでは新しく開始されたプログラムの特権として親プロセスが持っていなかった特権を与えることが出来ます。この最も分かりやすい例としては、setuid\setgidプログラムとファイルケーパビリティでしょう。親プロセスがこれらの特権を取得するのを防ぐために、Kernelとユーザのコードは、親プロセスが子を破壊するかもしれない行為を行うのを防ぐために注意する必要があります。例えば:

  • プログラムがsetuidされている際には、動的なローダがLD_*環境変数の取扱を変えます。
  • chrootを継承したプロセスからは/etc/passwdが置き換え可能なため、chrootは非特権プロセスを許可しません。
  • execコードはptraceに対して特別な扱いをします。

これらは全てアドホックな修正です。(Linux 3.5から含まれる) no_new_privsビットは新しい、execveによるプロセスの実行環境を変更する際に安全で一貫的な、汎用的なメカニズムです。このビットがセットされると、これはfork/clone/execveの際に継承され外すことが出来ません。”no_new_privs”をセットすると、execveはexecveコールなしでは実行できなかった事を行うための特権を付与しないことを約束します。例えば、setuidとsetgidビットはもはやuidやgidを変更することが出来なくなり、ファイルケーパビリティは許可されたセットを追加することが出来なくなり、LSMはexecve以後に制限を緩める事が出来なくなります。

no_new_privsをセットするには、prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)を使います。

気をつけて欲しいことは、従ってLSMはno_new_privs_modeではexecの制限を厳しくすることが出来ないかもしれないということです。(これは、デーモンを実行する前にno_new_privsをセットするように一般的なサービスランチャーを設定すると、LSMベースのサンドボックスを邪魔する可能性があるということです。)

no_new_privsはexecveがかかわらない場合には特権の変更を防止しない事に注意して下さい。適切に特権を与えられたtaskは依然としてsetuid(2)を呼ぶことが出来ますし、SCM_RIGHTSデータグラムを受け取ることも出来ます。

no_new_privsには、今の所2つの主要なユースケースがあります。

  • seccomp mode 2サンドボックス用にインストールされたフィルタはexecveをまたいで継続し、新しく実行されたプログラムの動作を変更することが出来ます。そのため、特権のないユーザは、そのようなフィルタをno_new_privsがセットされているときのみインストールすることが出来ます。
  • それ自信では、no_new_privsは非特権ユーザに対するアタックサーフェースを減らす為に使われます。仮に指定されたuidで、全てがno_new_privsがセットされている状態で実行されている場合、そのuidはsetuid/setgid/fcapが使われているバイナリへの直接の攻撃でその特権を昇格させることは出来ません。最初にno_new_privsビットを設定せずに侵害する必要があります。

いずれは、no_new_privsがセットされていない場合に潜在的に危険なカーネルの機能が、非特権のtaskに与えられるかもしれません。原理的に、no_new_privsがセットされている場合には、unshare(2)とclone(2)のいくつかのオプションが安全で、no_new_privs + chrootはchrootよりもはるかに危険が少ないと言えます。