mod_selinux(その2)

前回のエントリで書いた mod_selinux について、以下のような問題があるようだ。
1.ビルド環境の selinux-policy が最新すぎて、Fedora 9に入らない。
2.SRPMをインストールすると以下のようなメッセージが表示される。

~]# rpm -ihv mod_selinux-0.1-r906.src.rpm 
1:mod_selinux 警告: ユーザ kaigai は存在しません - root を使用します
警告: ユーザ kaigai は存在しません - root を使用します
警告: ユーザ kaigai は存在しません - root を使用します
警告: ユーザ kaigai は存在しません - root を使用します
########################################### [100%]
[root@perl-devel ~]#


ちょっっっっっwwwwwww

というワケで、rootになってパッケージを作り直した。
Fedora9のselinux-policy-3.3.1以上でインストールOKのハズ。
http://sepgsql.googlecode.com/files/mod_selinux-0.2-r926.i386.rpm
http://sepgsql.googlecode.com/files/mod_selinux-0.2-r926.src.rpm

Apacheのバックエンドでリクエストを処理するプロセス(スレッド)は、一度リクエストを処理した後、再び次のリクエストを処理する(ために待機する)。
したがって、setexeccon()を設定した後、この設定をクリアしないと、無関係の処理で fork() + execve() した時に変なコンテキストが付与されるという問題がある。
コメントでPANDAさんが質問を書いていたので、詳しく言及する事にする。

Apacheには、ローダブルモジュールが利用する事のできる各種のフックが存在し、クライアントからのリクエストを処理する過程で、各種の処理を行う事ができるようになっている。
mod_selinuxモジュールは、全てのリクエストに対して、(PHPやCGIやHTML等の)コンテンツハンドラが起動される直前に呼び出される fixups フックを利用している。
(このフックが呼び出される時には、既にHTTP認証は完了済みであることに留意されたい。)

このフックの延長で mod_selinux は、HTTPユーザ名に対応するセキュリティコンテキストを setexeccon() を使って設定するが、仮に、当該ディレクトリに何も設定されていない場合や、マッチするユーザが居なかった場合には setexeccon(NULL) を使って、設定をクリアする。

これに関して言及している記事:
http://d.hatena.ne.jp/kgbu/20080630/1214801923 に、

ところで、コメント欄のやり取りで気になったのだが、
setexecconのrevertはどのタイミングで行われるのだろう?
起動してすぐ元に戻すなら、race conditionは起きないよね?

とあるが、正解は「バックエンドが次のリクエストを処理する直前」である。
ただし、動的/静的コンテンツを問わず、このフックは常に呼び出され、明示的なsetexeccon()の必要のない場合は設定をクリアするので問題は生じない。
要は、次のリクエストを処理する前にクリアすれば良いのである。

(追記)
まっちゃだいふくさんの所でも紹介されていた:
http://d.hatena.ne.jp/ripjyr/20080630/1214768722

mod_selunuxで、ApacheSELinuxのセキュリティコンテキストでの動作制限が出来るソフトだそうです
これって、SQLインジェクションに効果どころでなくて、システム全体として面白いと思うけどなぁ
BASIC認証からフォーム認証も出来るようになったらもっと面白いなぁ。
PerlモジュールとかJavaのServeletとかPHP(何 モジュールとかw
さすが鋭い。
コレの意味するところは、LAPPスタックの最上位(Webアプリ)から最下位(OS)までを、同じセキュリティ属性/同じセキュリティポリシー一気通貫にアクセス制御できるようになる事。

ただ、Apacheモジュールとして実装されているperlPHP、JServletをこの枠組みに組み込む事は、2つの技術的課題があり、まだ上手く行っていない。

■その1:スレッドの扱い
SELinuxはプロセスに一個のセキュリティコンテキストを割り当てる。複数のスレッドが、それぞれに異なるリクエストを処理するような場合でも、個々のスレッドが別々のセキュリティコンテキストを持つ事を認めていない。
これは、Linuxカーネルがプロセスメモリ空間を通じたデータ交換を捕捉できないための制限事項と思われる。

■その2:誰が権限を戻すのか?
Apacheは、ユーザからのリクエストを受け付けるバックエンドプロセスを繰り返し使用するため、一度セキュリティコンテキストを設定したとしても、リクエストを処理した後、次のリクエストを受け付けるために元のセキュリティコンテキストに戻さねばならない。
しかし、setexeccon()の場合と違い、元に戻すのは自分自身。つまち、これを許すことはWebアプリの脆弱性を突いて権限昇格を許す事と同義である。ああ、困った困った。