SELinuxの速度チューニング
昨日宣言した、「衝撃のデータ」話。
NSAのMLに投げたネタ
http://marc.info/?l=selinux&m=118845327521551&w=2
色々とSELinuxのパフォーマンスを
測ってみたが、組込み向けアーキテクチャだと
Pen4と比較してオーバーヘッドが大きいことに気付いてしまった。。
lmbenchの結果の比較
x86, ARM, SHでベンチマークをとった。
SELinux無効と比べてどれくらいオーバーヘッドがあるか測定。
simple read/writeの結果を抜粋
simple read/writeってのは、/dev/zero,/dev/nullに
1バイト読み込み/書き込みする時間を測っている。
openの時間は含めていない。純粋にread/writeの時間のみ。
1) Result for x86(Pentium 4 2.6Ghz), kernel 2.6.22
Base SELinux Overhead(%)
Simple read 1.1034 1.2387 12.3
Simple write 0.9989 1.139 14.0
Base: kernel compiled without SELinux support
2) Result for ARM(Intel XScale (PXA270 416MHz)), kernel 2.6.17
Base SELinux Overhead(%)
Simple read 1.7945 3.1279 74.3
Simple write 1.4706 2.9228 98.7
3) Result for SH(SH4, SH7751R), kernel 2.6.22
Base SELinux Overhead(%)
Simple read 2.6781 6.4671 141.5
Simple write 2.0781 5.3181 155.9
Pen4だと、オーバーヘッドは10%ちょっと。
しかし、
SHだと、なんと150%ぐらい(2.5倍遅い)。
これはさすがに心理的に微妙だと思う。
どこかで、「組込みSELinuxのオーバーヘッドはたいしたことない」
と言った気がするのですが、超勘違いしてましたorz
チューニング
ハッシュのチューニングとか色々と試行錯誤したのだが、
結局、「関数呼び出し」が利いているような気がした。
余計な関数呼び出しを削減する単純なパッチを作った。
チューニング後のパフォーマンス
1) Result for x86
Base SELinux Overhead(%)
Simple read 1.1034 1.1939 8.2(before 12.3)
Simple write 0.9989 1.1039 10.5(before 14.0)
2) Result for ARM
Base SELinux Overhead(%)
Simple read 1.7945 2.7555 53.6(before 74.3)
Simple write 1.4706 2.5347 72.4(before 98.7)
3) Result for SH
Base SELinux Overhead(%)
Simple read 2.6781 3.6538 36.43(before 141.5)
Simple write 2.0781 3.321 59.80(before 155.9)
ちょっとしたことだが、だいぶ改善されている。
ARMよりSHのほうが効果が大きい。不思議だ。。
SHの関数呼び出しは重いのだろうか。
詳しい人教えてください。
さらに改善するには、
TOMOYO Linuxばりに、openだけチェックして、
read/writeのチェックを無くすという荒業もあるが、
コミュニティに受け入れられる気がしない。
反応
おっと、今メール見たら早速反応が。
この遅さは意外で、どうも信じられないようだ。
私も信じられなかったが、今週、何回測ってもほぼ同じ結果が得られた。
私がとんでもない思い違いをしているのかもしれないので、
他の人の追試を希望なのだけど。
クロスコンパイルの際に、とんでもない誤りをしているのかもしれないし。
read/writeのチェックは無駄か?
Stephenが、色々とアイデアを出してくれたが、その中には、
なんと、read/writeのチェック無くす可能性まで示唆された。
ΩΩ<な、なんだってー!
聞いてみるものだ。
1) Make selinux_file_permission optional, e.g. depend on separate config
option, so people can build kernels without it. Revalidation on
read/write is nice for revocation on file relabels and policy changes,
but it is known to be incomplete (e.g. mmap'd files), it isn't required
for evaluation/certification, and it carries a high cost.
open以外にread/writeのチェックをしてる理由が分からなかったのだけど、
open後に,relabel・reloadが生じた場合に意味があるそうだ。
ただ,それでも完璧ではないんだとか。
反応をまとめると、以下のようだ
- 手作業で、関数を展開するのは、たとえ速くなるとしてもいいことではない
- 遅いのはなんとかせねばなるまい
- 別の方法を探るべき(read/writeのチェック可能性を限りなく無くすなど)
なので、Stephenが教えてくれたアイデアを検討して、よさそうなやつを
採用してみよう。
relabel,reloadが生じた場合のみ,
read/writeのチェックとかするのが完璧っぽいけど、
なんか、SMPの場合とかに今度は問題が出てきそうな予感。よく分からんけど。
KaiGaiさんのやったRCU関係の仕事をパァにしないように気を使う必要があるっぽい。
色々と勉強になりそうだ。
また反応が。
On second thought, making selinux_file_permission optional may lead to
insecurity for policies and/or applications that depend on it, and there
is presently no mechanism for a policy or application to check what set
of hooks/permissions are applied by a given kernel.
やっぱり、read/write時のチェックを消しちゃうのは危ないということか。
So let's focus for now on improving selinux_file_permission. I'm not
opposed to inlining if it truly helps that much, but I think we should
also look at the recheck-only-if-something-changed approach.
ということで、
relabel,reloadが生じた時だけ,
read/writeをチェックするアプローチを考えることになった。
うーむ、どうすりゃいいのか、全然分からんぞ(汗
勉強ですな。
対応策
さて、どうすりゃいいんだ。対応策をメモ。
カーネル内のデータ構造もよく分かってないが。。
Stephenのメールを見ると、
open後に、read/writeのチェックが必要なのは以下か。
1) プロセスのsidがopen後に変わった場合
2) ファイルのsidがopen後に変わった場合
3) ポリシがリロードされた場合
これらの変化を検出すればいいのか。
1)については、
- プロセスがオープンしてるファイル識別子の構造体に、フラグを追加する。
- sidを変えるシステムコールを呼んだ場合(execもしくはsetcon)
- 上記フラグを一斉に立てる。
- selinux_file_permission(read/writeで呼ばれる)で、フラグをチェック。フラグが立ってる時だけ呼ぶ
- read/writeをチェックし、アクセス許可ならフラグをクリア
でいいのか?
このとき、何か排他制御しないと、問題が生じるか??
2)については、、
- グローバル変数で通し番号を用意する(sid_serial)
- ファイルのsidを変える可能性があるシステムコール(setxattr等)を呼んだら、sid_serialをインクリメント
- open時に,その時のsid_serialを覚えておく(struct fileのf_security構造体か何かで)
- read/write時に、sid_serialが変わってたら、パーミッションチェック
- 許可されたら、open時に覚えたsid_serialをアップデート
排他制御とか、通し番号が一周したらどうなるかは知らない(汗
ファイルのsidを変える可能性があるシステムコールはそんなに頻繁に呼ばれないハズなので、パーミッションチェックが発生する場合も少ないと期待。
3)も、load_policyするごとに、2)の通し番号を増やせば、同じロジックでいける。
1)も、プロセスのsidを変えるシステムコールがそんなに頻繁に呼ばれなければ、同じロジックでいける?
通し番号が一周した場合は重要そうだ。