SELinuxを独学したよ。

こんにちは。今回は誰得感の否めないSELinuxエントリです。しかも独学なのでかなり眉唾物です。

SELinuxのポリシーをスクラッチで書くのが目的です。既存のポリシーを運用する話ではないです。

環境はDebian squeezeです。

SELinuxとは

SELinuxは、Linuxにおいて詳細なセキュリティー制御を行うための仕組みです。一般的なデスクトップ用のLinuxではオフになっているようです。現在はLinuxのセキュリティー機構はLSMという仕組みで提供されていて、SELinuxやTOMOYO Linuxなどのなかから選べる仕組みのようです。

SELinuxは強制アクセス制御(MAC)といって、自分の所有物であっても管理者でなければ権限コントロールができない、みたいな仕組みらしいです。MACにすることの利点は馬鹿なユーザーが穴を開けてしまうのを防げることのようです。

インストール

SELinux/Setup - Debian Wikiに従ってインストールすればいいです。

ここではポリシーを作成したいので、上記URLより多めにインストールします。

有効化

SELinuxにはdisabled,permissive,enforcingの3つのモードがあります。

  • disabledはSELinuxが働いてない状態です。
  • permissiveではSELinuxは動作していますが、許可されていない操作があっても静観し、ログをとります。俗に言う「俺の荷物ちゃんと見といてね状態」です。
  • enforcingではSELinuxは動作しています。

permissiveとenforcingの切り替えは、setenforce (0|1)で行ないます。0ならpermissive、1ならenforcingです。

ブート時の設定は/etc/selinux/configにあるSELINUX=(permissive|enforcing)です。

一度permissiveで動かし、その時のログをもとに許可を行い、enforcingに設定する、という流れが想定されているようです。

permissiveにせよenforcingにせよ、dmesgで表示できるログに拒否記録があります。

audit2allow -d -l

とやると、拒否された操作を許可するのに必要なコードがわかります。

ポリシー

ポリシーは/etc/selinux//に入っています。バイナリらしいです。昔はこのSELINUXMODEは(targeted|strict)だったようですが、現在は(default|mls)です。defaultでいいでしょう。

普段はここを直接弄ることはなく、モジュールを作ってインストールします。

全く新しい設定を作りたい場合はポリシーモジュールを自分で定義するのがよいでしょう。他の場合は知りません。

SELinuxのポリシーはm4言語を用いてプリプロセスされます。

  • ほげ.if …マクロ定義。ここでマクロを定義すると他のポリシーモジュールから参照できる。
  • ほげ.te …ポリシーの本体。
  • ほげ.fc …ファイルコンテキスト(既存ファイルに対するコンテキストの割り当て方法)

適当な作業フォルダに上記のファイルをtouchして、/usr/share/doc/selinux-policy-dev/examples/Makefileを持ってきます。

makeをするとほげ.ppが生成されます。make reloadでインストールされます。

ただ、自作のファイルコンテキストは他の設定との順序のせいで上手く適用されないので、

make reload && cat ほげ.fc >> /etc/selinux/default/contexts/files/file_contexts.local

などとやっています。

コンテキスト

SELinuxのアクセス制御は、ファイルやプロセスをひっくるめて行います。これらに対してはコンテキストが割り当てられます。

  • コンテキスト = :<ロール>:<タイプ(ドメイン)>:<よくわからないもの(普通s0)>

本質的なのはタイプで、ロールはタイプに関連付けられ、SELinuxユーザーはロールに関連付けられるようです。SELinuxユーザーとロールについてはあまり触れていないのでわかりません。

  • ユーザー…unconfined_u, system_uなど。
  • ロール…unconfined_r, object_rなど。
  • タイプ…unconfined_t, bin_t, usr_t, init_tなど。

unconfinedってのはrootみたいなものだと認識しておけばいいと思います。

タイプによってそのプロセスが行えることが変わります。「typeA_tのプロセスはtypeB_tのファイルには書き込めない」のように、ルールのほとんどはタイプ同士の相関関係に対して定義されます。

プロセスに割り当てられるタイプのことはドメインと言うようです。

コンテキストの決定

コンテキストの決定ですが、基本的には継承されます。例えば、新しいプロセスが作られたときは、特に指定がなければ呼び出し元のプロセスのコンテキストと同じになります。

もともとあるファイルについては、このような決定方法は適用できません。元からあるファイルには、ファイルのフルパスに応じてコンテキストが決定されます。(ファイルコンテキスト)

TEファイルのよく使う書式

TEファイルはポリシーの主役となるファイルです。

冒頭
policy_module(モジュール名,モジュールのバージョン);
require {
  # 他の場所で定義されているtypeやroleなどを使いたい場合はここに書く
  # requireは別に途中で書かれてもよい
  role unconfined_r, system_r;
  type bin_t, usr_t;
  attribute domain;
};
attributeやtypeの宣言

attributeは複数のtypeをまとめて扱うのに便利です。

# attribute定義
attribute my_attribute;

# type定義
type typeA_t;

# type <新しいタイプ>, <そのタイプを修飾するattribute...>;
type typeB_t, my_attribute, domain;
type typeC_t, domain;

# 後からattributeを追加することもできる
typeattribute typeA_t, file_type;
type遷移
  • 特定のプロセスが特定のファイルを実行したときに特定のタイプを割り当てたり
  • 特定のプロセスが特定のディレクトリにファイルを作成したときに特定のタイプを割り当てたり

できます。

# typeB_tプロセスがtypeA_tファイルを実行したとき子プロセスはtype_Cになる
type_transition typeB_t typeA_t:process type_C;
許可

SELinuxはデフォルトで拒否、明示的に許可します。

# allow <タイプA> <タイプB>:<クラス> <操作>
allow procA_t fileB_t:dir search;
allow procA_t fileB_t:file { getattr read write setattr open };
allow {procA_t procC_t} {dirD_t dirE_t}:dir search;

ワイルドカード*とか除外-とかも使えるっぽいですけど使ったことないです。

ちなみに許可/拒否を設定できる一覧はObjectClassesPerms - SELinux Wikiにあります。

クラス

クラスのもつ意味はいまいちわかりませんが、制御したい各々の操作のグルーピングだと思います。

最もよく使うdir,fileとprocessの他に、fd,fifo-fileなどさまざまあるようです。

そもそもプロセスが起動できない!ってなったら

プロセスAがファイルBを実行したときにCとして実行したい!

type_transition A B:process C;

ってやるだけだと起動しなくてめっさ困る。

まず、タイプは起動したいロールに属していないと駄目らしい。

role object_r types C;

それから、transitionとかexecuteとかを確認して。

allow A C:process transition;
allow A B:file execute;

まああとは頑張ってください。

いろいろ頑張ると起動しますが、最初はなんか無限ループに陥り、カーネルのメッセージキューが凄い勢いで新陳代謝していきます。とりあえず、audit2allow -d -l > ~/a.txt とかやってrebootしましょう。(適当)

マクロを使おう

車輪の再発明は良くないのでマクロを使いましょう。


Security Enhanced Linux Reference Policy
にAPIリファレンスがあります。

また、/usr/src/selinux-policy-src.tar.gzにソースがあるので、この中の*.ifファイルをgrepして自分の必要なマクロがどれか検討しながら作業するといいでしょう。

例えばこんな感じです。

corecmd_exec_bin(domainA_t);
files_list_root(domainA_t);

簡単!

困ったら

広いWebのSELinuxソースに頼るのはやめて、「site:selinuxproject.org」を付けて検索するとよく引っかかり適切ですよ。

まとめ

骨折り損でした。

そんじゃーね!