SELinuxのポリシー・モジュールを自作する

 audit2allowコマンドを使えば自動生成されるけど、いくつかの問題があるときに何度も実行してマージするのが面倒臭くて、audit.logを見ながらポリシー・モジュールを手書きしてたら、きもいって言われたけど、きもくないのを主張するために書きます。

 環境は次の通り。

 muninの mysql_ はinnodbの状態とかを収集してくれるプラグインで、実態は mysqladmin extended-status で取得できる情報を収集するものです。これをSELinuxを有効にしてると、次のようなエラーメッセージがログ ( /var/log/munin-node/munin-node.log ) に表示されます(一部のみ)。

2013/05/01-23:40:11 [60227] Error output from mysql_qcache_mem:
2013/05/01-23:40:11 [60227]     Couldn't instantiate IPC::ShareLite: Permission denied at /usr/share/perl5/Cache/SharedMemoryBackend.pm line 85.
2013/05/01-23:40:11 [60227] Service 'mysql_qcache_mem' exited with status 13/0.

 これはSELinuxがアクセスを不許可にしてるようで、 /var/log/audit/audit.log ファイルにdeniedで出力されています(一部のみ)。

type=AVC msg=audit(1367418934.828:49833): avc:  denied  { unix_read unix_write } for  pid=59897 comm="mysql_innodb_bp" key=1667461225  scontext=unconfined_u:system_r:munin_services_plugin_t:s0 tcontext=system_u:system_r:munin_services_plugin_t:s0 tclass=shm setroubleshoot-serverパッケージがインストールされていれば、/var/log/messages ファイルに ..... run sealert -l xxxxxx みたいなメッセージが出力されてて、sealertコマンドを実行すると、
grep xxxx /var/log/audit/audit.log | audit2allow -M mypol
semodule -i mypol.pp

を実行してねってメッセージが表示されるので、実行すると、ポリシー・ソースファイルのmypol.teファイルとコンパイルされたmypol.ppファイルが作成されて、semodule -i mypol.pp を実行するとSELinuxに新しいポリシーが登録されます。

 けれど、上記に貼りつけたログのように、たくさんあるときは一つづつ確認するのが面倒だし、場合によっては、このポリシーをクリアした後、別のポリシーを要求されることもあります。なので、最初からポリシー・ファイルを作成したほうが楽な場合があるのです。

 以下、muninのmysql_プラグインが動くためのポリシーを作成します。

 

 ポリシー名はmypolで作成します。

touch mypol.te

 ファイルにポリシー名とバージョンを記述します。

module mypol 1.0;

 今回はドメインで設定するので、audit.logに書かれたscontextとtcontextの転んで区切った三番目のもの (ドメイン属性) を記述します。上記のログだと munin_services_plugin_tだけなので、これを記述します。

require {
type munin_services_plugin_t;
}

 さらにこのrequireのブロック内に、audit.logに書かれたtclassと、denied { xxxx } の括弧内の内容を次の書式で記述します。

class shm { unix_read unix_write };

 その後、scontext, tcontextの先ほどの三番目のものとtclassとdenied { xxxx } の括弧内のものを次のように記述します。

allow munin_services_plugin_t munin_services_plugin_t:shm { unix_read unix_write };

 今回はscontextとtcontextのものが同じなので、selfで置き換えられます。

allow munin_services_plugin_t self:shm { unix_read unix_write };

 結果的に、こうなります。

module mypol 1.0;
require {
type munin_services_plugin_t;
class shm { unix_read unix_write };
}
allow munin_services_plugin_t self:shm { unix_read unix_write };

 これは、audit.ogが、アクセス・ドメインが munin_services_plugin_t (scontextに書かれたもの) のプロセスmysql_innodb_bpなど (commに書かれたもの) が munin_services_plugin_t (tcontextに書かれたもの)に対して shmクラス (tclassに書かれたもの) でunix_read, unix_write (deniedの後の括弧に書かれたもの) を実行しようとしたが許可されていない、と言っているのに対する設定です。requireで必要なリソースを列挙し、allowでscontextがtcontextに{xxxx}を実行することを許可する、と定義します。

  ポリシー・ファイルを作成したので、これをコンパイルします。

 make -f /usr/share/selinux/devel/Makefile

 実行すると、mypol.fc, mypol.if, mypol.ppを作成しますが、fc, ifファイルは今のところ不要です。ppファイルがコンパイルされたポリシー・モジュールです。これをSELinuxに適用します。

semodule -i mypol.pp

  ここで、私の環境では期待通りに別のSELinuxに却下されたメッセージが出力されました。/var/log/audit/audit.log に次のようなメッセージが出力されてます (全部同じなので、1つだけ)。

type=AVC msg=audit(1367422400.503:58827): avc:  denied  { associate } for  pid=65203 comm="mysql_innodb_bp" key=1667461225  scontext=unconfined_u:system_r:munin_services_plugin_t:s0 tcontext=system_u:system_r:munin_services_plugin_t:s0 tclass=shm

 これを見る限り、scontextがtcontextにshmでassociateを実行する許可が必要なようです。そこで、require内のshmにassociateを追加して、allowにassociateを追加します。すなわち、こうなります。

module mypol 1.0;
require {
type munin_services_plugin_t;
class shm { unix_read unix_write associate };
}
allow munin_services_plugin_t self:shm { unix_read unix_write associate };

 これをコンパイルして、SELinuxに適用します。同じ名前のものを最適用するときは、

semodule -r mypol
semodule -i mypol.pp

で削除・登録をするか、

semodule -i mypol.pp
semodule -R

で再登録して、リロードします。すると、また別のメッセージが出力されます。

type=AVC msg=audit(1367423040.036:60463): avc:  denied  { read write } for  pid=1188 comm="mysql_innodb_bp" key=1667461225  scontext=unconfined_u:system_r:munin_services_plugin_t:s0 tcontext=system_u:system_r:munin_services_plugin_t:s0 tclass=shm

 今度は read, write が許可されていないと言っているので、先ほどと同じように、requireのclassとallowに追加します。

module mypol 1.0;
require {
type munin_services_plugin_t;
class shm { unix_read unix_write associate read write };
}
allow munin_services_plugin_t self:shm { unix_read unix_write associate read write };

  これをコンパイルして再登録すると、更に別のメッセージが出力されました。

type=AVC msg=audit(1367423459.872:62107): avc:  denied  { read write } for  pid=2367 comm="mysql_innodb_io" path=2F535953563633363337303639202864656C6574656429 dev=tmpfs ino=229383 scontext=unconfined_u:system_r:munin_services_plugin_t:s0 tcontext=system_u:object_r:tmpfs_t:s0 tclass=file

  今度は今までと違うものがtcontextとtclassに出力されました。tmpfs_t が登場したので、require内にtypeを追加します。また、fileのread, writeが却下されてるので、classを追加します。

type tmpfs_t;
class file { read write };

 そして、munin_services_plugin_tからこれらに対するアクセスを許可します。

allow munin_services_plugin_t tmpfs_t:file { read write };

 結果として、次のようになります。

module mypol 1.0;
require {
type munin_services_plugin_t;
type tmpfs_t;
class shm { unix_read unix_write associate read write };
class file { read write };
}
allow munin_services_plugin_t self:shm { unix_read unix_write associate read write };
allow munin_services_plugin_t tmpfs_t:file { read write };

   これをコンパイルして再登録すると、また別のメッセージが出力されました。

type=AVC msg=audit(1367424118.516:63758): avc:  denied  { getattr } for  pid=3842 comm="mysql_innodb_bp" key=1667461225  scontext=unconfined_u:system_r:munin_services_plugin_t:s0 tcontext=system_u:system_r:munin_services_plugin_t:s0 tclass=shm

  今回は munin_services_plugin_t 自身に getattr するのを許可するだけなので、class shm とallow ... self:shm にgetattr を追加するだけです。

module mypol 1.0;
require {
type munin_services_plugin_t;
type tmpfs_t;
class shm { unix_read unix_write associate read write getattr };
class file { read write };
}
allow munin_services_plugin_t self:shm { unix_read unix_write associate read write getattr };
allow munin_services_plugin_t tmpfs_t:file { read write };

  これをコンパイルして再登録した所、ようやくメッセージがでなくなり、muninがmysql_ プラグインから値を収集できるようになりました。

  このあと、それぞれのファイルのラベル付が正しいかとかをチェックして、不要な設定を極力なくしていく作業がありますが、それは私のSELinux力がもう少し付いてから。

 

 ちなみに、これをするまでに学ばせてもらったのは、こちらの資料です。

http://www.slideshare.net/ishikawa84g/hbstudy-28-selinuxhandson

 60-61ページ:/var/log/messages の見方

 83-85, 96ページ:/var/log/audit/audit.log の見方

 106-110ページ:ポリシーの作成方法

 

追記

 munin_ のラベルを munin_services_plugin_t って書いたけど、最初からそうだったのか、自分でchconしたのか覚えてません。。。