Tetsuo Handa
from-****@I-lov*****
2010年 2月 2日 (火) 21:22:38 JST
熊猫です。 Apache では高速化のためにスレッドを複数のリクエスト間で使いまわすようになって います。そのため、プログラムの実行(つまり execve() システムコール)を伴わないで 行われる処理(静的なコンテンツの配信や mod_perl などで処理されるCGIプログラム など)に対しては、全て同じ権限で動作するようになっています。 セキュリティを高めるために、リクエスト毎に異なる権限を割り当てて処理しようとした 場合、あるリクエストを処理するために権限を切り替えた後で、次のリクエストを処理 する前に権限を元に戻す処理が必要になります。しかし、自由に権限を元に戻すことが できるようになっていると、そこを攻撃されて権限が不正に元に戻されてしまうことが あるため、それを防ぐための工夫が必要です。 NECの海外さんが mod_selinux という、 Apache でリクエストを異なる権限で動作 させるためのモジュールを開発し、 Fedora 11 以降で利用可能になっています。この モジュールでは、1リクエスト毎に使い捨てのスレッドを作成し、使い捨てスレッドの 中で権限を変更してからリクエストを処理することにより、権限を元に戻すという処理が 不要になるように実装されているという点が特徴です。 TOMOYO Linux においては、権限の切り替えはドメイン遷移という形で実現されて います。権限を元に戻すという処理が不要であるということは、「現在のドメイン名に 要求されたプログラムのパス名を連結したものを遷移先ドメイン名とする」という TOMOYO Linux のドメイン遷移のルールをそのまま適用できるということです。 そのため、 mod_selinux がやっていることは、そのまま TOMOYO Linux においても 適用できます。違いはプログラムの実行(つまり execve() システムコール)を伴うか どうかだけです。 ということで、さっそく TOMOYO Linux 用のモジュールを試作してみました。 添付画像では /etc/httpd/conf/httpd.conf に NameVirtualHost *:80 <VirtualHost *:80> DocumentRoot /var/www/html/ ServerName dog.example.com </VirtualHost> <VirtualHost *:80> DocumentRoot /var/www/html/ ServerName cat.example.com </VirtualHost> という内容を追加し、バーチャルホスト単位で異なるアクセス許可を与えられるように しています。また、要求されたファイル名に基づいて、パス名単位でも異なるアクセス 許可を与えられるようにしています。 この「プログラムの実行を伴わないドメイン遷移」は様々な可能性を秘めています。 例えば Android では、 UID=0 で動作しているプロセス( zygote )が特定の UID に 変化してから動作(例えば com.android.browser )するようになっています。 ( http://sourceforge.jp/projects/tomoyo/docs/JLS_tomoyo_tutorial.pdf の P32とP34を参照ください。)もし、 fork() 後に //com.android.browser ドメインに遷移するように zygote を修正することができれば、 zygote を <kernel> /init /system/bin/app_process ドメインで、 com.android.browser を <kernel> /init /system/bin/app_process //com.android.browser ドメインで 動作させることができるようになります。 ということで、以下の点についてコメント募集です。 (1)ドメイン遷移をするためのインタフェース 現在のプロトタイプでは、 /proc/ccs/self_domain にドメイン名を write() する ことによりドメイン遷移するようになっています。ただし、 /proc/ccs/ は バッファリングのためにカーネルメモリを割り当てているので、デフォルトでは root ユーザだけにしか開放していません。 Apache は一般ユーザ権限で動作するので、 /proc/ccs/self_domain を全てのユーザに開放する必要が生じます。すると、悪意ある ユーザが fork() と open() を繰り返して全てのカーネルメモリを消費してしまうという 攻撃が成立してしまうのではないかと心配しています。 sysctl() のように1回の read() や write() でドメイン名全体を渡すという制約を設ければ、バッファリングが 不要になるのでカーネルメモリを消費しつくす攻撃を防げるので好ましいかも しれませんね。 (2)ドメイン名の表記規則 TOMOYO Linux におけるドメイン名は、「 <kernel> +0回以上のパス名の繰り返し」 として定義されています。このパス名は / で始まり、 \? や \* などを含まず、 / では終わりません。 セキュリティ上の理由から、 execve() を伴うドメイン遷移と execve() を伴わない ドメイン遷移とを区別できるようにしておく必要があると考えています。もし、区別 できない場合、あるドメインに所属するプロセスは、制御権を保持したまま、その ドメインの任意の子ドメインに自由に遷移できてしまいます。すると、例えば <kernel> /usr/sbin/sshd /bin/bash ドメインに属している /bin/bash が <kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd ドメインに属している /usr/bin/passwd に対して許可されている資源(例えば /etc/shadow )にも アクセスできるようになってしまいます。 現在のプロトタイプでは、 execve() を伴わないドメイン遷移の場合には自動的に / が 付与されるようになっています。例えば <kernel> /usr/sbin/sshd /bin/bash ドメイン に属している /bin/bash が /usr/bin/passwd という( execve() を伴わない)ドメイン 遷移を要求すると、 <kernel> /usr/sbin/sshd /bin/bash //usr/bin/passwd ドメインに 遷移するようになっています。 他の方法としては、 allow_execute のように明示的に許可が無いと遷移できないように する方法が考えられます。例えば、 <kernel> /usr/sbin/sshd /bin/bash allow_transit /bin/true という許可が与えられている場合に限り <kernel> /usr/sbin/sshd /bin/bash ドメインから <kernel> /usr/sbin/sshd /bin/bash /bin/true ドメインへ ( execve() を伴わないで)ドメイン遷移することを許可するという方法です。 将来、(要望が出た場合には)親ドメインへ遷移する <kernel> /usr/sbin/sshd /bin/bash allow_transit .. とか特定のドメインへ遷移する <kernel> /usr/sbin/sshd /bin/bash allow_transit <kernel> /sbin/mingetty /bin/bash みたいな拡張も可能であることから、こちらの方が好ましいかもしれませんね。 -------------- next part -------------- テキスト形式以外の添付ファイルを保管しました... ファイル名: apache.png 型: image/png サイズ: 15598 バイト 説明: 無し Download