[tomoyo-users 716] プログラムの実行を伴わないドメイン遷移について

Back to archive index

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 



tomoyo-users メーリングリストの案内
Back to archive index