selinux上のCGIでjavaを動かせるようにする方法

これまで使ってたCGIを移設したら動かなくなって、その理由がselinuxのポリシーだった。 ポリシーの作り方と書き換え方をメモ。

環境はCentOS6.6で、kernel 2.6.32、apache2.2.15 この上でブラウザからjavaを実行しようとしたら

Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00007fcf589ac000, 2555904, 1) failed; error='Permission denied' (errno=13)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (malloc) failed to allocate 2555904 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /tmp/jvm-21000/hs_error.log

こんな感じのエラーが出力された。

コマンドラインで該当するjavaを動かすと正常に動作する。

とりあえずPermission deniedなことはわかったけど、なんのパーミッションがないのか分からず、検索したところ

In case anyone else is looking for a way to resolve this without explicitly disabling SELinux, the wiki page at centos.org helped me understand what was going on.
 
By default, the security context that Java is running in when called from Apache does not allow things like reading a file, allocating memory, accessing the network etc. The easiest way to resolve these errors is by using the semodule and audit2allow applications. Essentially, check the SELinux audit log (could be /var/logs/audit/audit.log, but I used /var/log/messages and extracted the avc errors). In the log you should see things like
linux - Run java in php apache2 - Super User

ということでどうやらselinuxだからメモリアロケーションの権限が無いらしい。ここに書いてあるwiki HowTos/SELinux - CentOS Wiki に解決法があった。

audit.logというログファイルをもとに追加するポリシーを作成するらしい。 まず作成・登録するためのツール群が入ってなかったのでインストール

$ sudo yum install policycoreutils-python

あとはcentos wikiと同じだけど、javaなので

$ sudo grep java_t /var/log/audit/audit.log | audit2allow -m javalocal > javalocal.te

としてjavalocal.teの中身を確認。

module javalocal 1.0;

require {
        type httpd_sys_script_t;
        class process execmem;
}

#============= httpd_sys_script_t ==============

#!!!! This avc is allowed in the current policy
allow httpd_sys_script_t self:process execmem;

関係ありそうなことが書いてあるか確認する。

上のようにcentos wikiに書いてあるとおりやったけど、下のように後から全部を読み込ませても同じ結果になることを確認した。audit2allowが良きに計らってくれるらしい。

$ sudo cat /var/log/audit/audit.log | audit2allow -m javalocal > javalocal.te

確認したら、実際に登録するppファイルを作成する

$ sudo grep java_t /var/log/audit/audit.log | audit2allow -M javalocal

これでjavalocal.ppができているので

$ sudo semodule -i javalocal.pp

で登録。

これで無事にCGIJavaを動かせるようになった。