著者:コーリー・ミニヤード、モンタビスタ・ソフトウェア
第2章:政策の実施
前章では、SELinuxプロジェクトの要件と初期段階の進め方について説明しました。今回は、実際の実装について見ていきましょう。
SELinuxの紹介
SELinux をまだ使ったことがない場合は、 「The SELinux Notebook」または「SELinux By Example」を参照してください。これらは古い SELinux カーネル言語を使用していますが、基本的な概念は共通しています。新しい言語である CIL 言語のリファレンスは、CIL ( Common Intermediate Language ) です。SELinux の基本を要約してみますが、このポリシーを実際に適切に実装するには不十分かもしれません。完全に理解するには、上記のリンク先のドキュメントをお読みください。
SELinuxは強制アクセス制御(MAC)を提供します。「強制」とは、強制という意味ではなく、集中管理という意味です。MACシステムでは、通常、各ユーザーが自分のファイルに対して個別に設定するポリシーではなく、集中管理されたアクセス制御ポリシーが1つだけ存在します。この用語はセキュリティ用語に由来しており、SELinuxはセキュリティシステムの専門家によって設計されたため、一部の用語はソフトウェアの概念ではなく、古いセキュリティの概念に基づいています。
SELinuxは、デフォルトでは権限なしのモデルで動作します。デフォルトでは何も許可されていません。操作を許可するには権限を追加する必要があり、そのため非常に詳細な設定が求められます。権限は、主体とオブジェクトのコンテキストを介して提供されます。主体とは、オブジェクトにアクセスしようとするものです。主体は一般的にプログラムであり、オブジェクトは一般的にそれ以外のすべて(ファイル、ソケット、パイプ、機能など)です。
コンテキストは、少なくともユーザー、ロール、タイプの 3 つの要素で構成されます。マルチレベルセキュリティ (MLS) を扱う要素を追加することもできますが、これは軍事レベルのポリシーであり、このポリシーでは使用されていません。このポリシーでは、ユーザーとロールはそれぞれ 1 つずつしかないため、すべてのコンテキストで ` <tt>u</tt>と ` rに設定された単一のユーザーとロールのみが存在します。つまり、タイプのみが使用されます。
この型はさまざまな方法で使用されます。デバイスにはオブジェクトコンテキストがあります。たとえば、 /dev/nullには一意のコンテキストu:r:null.nodedevがあります。
# ls -Z /dev/null<br /> u:r:null.nodedev /dev/null
ファイルシステム内のファイルのコンテキストはラベルと呼ばれ、これらのコンテキストを設定するプロセスはラベリングと呼ばれます。ファイル(およびディレクトリ)のラベリングはポリシーで指定され、ファイルシステム上の静的ファイルと動的に作成されるファイルの両方に適用されます。
プログラムが/dev/nullを使用する必要がある場合は、アクセスを許可するルールを追加する必要があります。すべてのルールはコンテキストに基づいています。したがって、プログラムのサブジェクトコンテキストが特定のコンテキストで許可されている必要があります。たとえば、コンテキストu:r:lxc.subjでlxcとして実行されているプログラム ( lxc-createなど) が/dev/nullに書き込む必要がある場合、次のルールが必要になります。
(allow lxc.subj null.nodedev (chr_file (open write)))
あるプログラムが異なるコンテキストで実行される別のプログラムを実行する必要がある場合、それはトランジションと呼ばれます。サブジェクトトランジションは通常、ルールによって許可され、タイプトランジションステートメントで指定する必要があります。これには、ファイルへのread 、 execute 、およびmmapアクセス、共有ライブラリをロードするための同様のアクセス、子プロセスからのSIGCHLDの取得、その他同様の事項を許可する必要があります。
OpenWRTポリシーの基本
しかし、ポリシーを使用する際に、通常はそこまで低いレベルで作業することはありません。OpenWRTポリシーには、これらの参照を簡素化し、メンテナンスを容易にするためのマクロや定型文が多数用意されています。たとえば、 /dev/nullへのアクセスの場合、実際に行うのはsrc/agent/lxc.cilのlxcブロックに以下を追加することです。
(call .null.write_nodedev_chr_files (subj))
もう少し詳しく見ていきましょう。src src/dev/nodedev/nullnodev.cilを見ると、 /dev/null /dev/nullへの参照が見つかります。/dev/null を参照する filecon および macro ステートメントの後に、次のステートメントがあります。
(blockinherit .dev.node.obj_template)
blockinherit 、ブロックdev内のブロックnodeにあるobj_templateという名前のブロックの内容を取得することを意味します。そのブロック (「 block node 」を grep で検索) はsrc/dev/nodedev.cilで見つかります。
(in .dev
(block node
ここでの「 inステートメントは、「devブロックの最後に何かを追加する」という意味です。そして、このファイルの最後に:
(block obj_template<br /> (blockabstract obj_template)
(blockinherit .dev.node.obj_base_template)<br /> (blockinherit .dev.node.obj_macro_template))))
obj_base_templateはこのファイルにあります。
(block obj_base_template
(context<br /> nodedev_file_context<br /> (.u<br /> .r<br /> nodedev<br /> (systemlow<br /> systemlow)))
(blockabstract obj_base_template)
(type<br /> nodedev)
(call .dev.node.obj_type (nodedev)))
この特定のコードは、 null.nodedev typeと、 u:r:null.nodedevであるnull.nodedev_file_contextコンテキストを作成します。( systemlowは多段階セキュリティのためのものですが、ここでは使用しません。)
call文はobj_typeという名前のマクロを呼び出します。nodedev.cil nodedev.cilおそらくそこにマクロがあるはずです)を見ても、そこにはありません。つまり、そのファイル内のblockinheritの中にあるはずです。いくつか候補があるので、マクロobj_typeを検索して最も可能性の高いものを見つけ、 file.cilの中に有望そうなものを見つけました。そして実際に、次のものがありました。
(blockinherit .file.obj_all_macro_template)
nodedev.cil内file.cil内には、次の内容があります。
(macro obj_type ((type ARG1))<br /> (typeattributeset obj_typeattr ARG1))
これにより、 null.nodedevタイプがdev.obj_typeattrに追加されます。
nodedev.cilのobj_macro_templateを見てみると、たくさんのマクロが見つかります。これらのマクロを見てみると、次のようになります。
(macro write_nodedev_chr_files ((type ARG1))<br /> (allow ARG1 nodedev write_chr_file))
そこで、ここで置換を行い、元の呼び出しに戻すと、次のようになります。
(allow lxc.subj null.nodedev write_chr_file)
これらをすべて展開すると、次のようになります。
(allow lxc.subj null.nodedev<br /> (chr_file (append getattr ioctl lock open write)))
しかし、これらはすべて不要です。なぜなら、 lxc.cilには以下の機能があるからです。
(blockinherit .agent.base_template)
最終的には以下の結果につながる:
(call .null.readwrite_nodedev_chr_files (subj_typeattr))
これは、エージェントベーステンプレートが行う多くの処理の1つである.subj.commonブロックから取得されます。そのため、通常は/dev/nullへの特別なアクセス権を追加する必要はありません。デフォルトで付与されているからです。
ヘルパープログラムとツール
対象システムで、ログが標準の監査ログ保存場所( /var/log/audit/audit.log )に送られる場合、ausearchというツールを使うとログが少し読みやすくなります。以下のコマンドを実行してください。
ausearch -i | less
そして、かなり長い行の出力が得られます。読みやすくするために、 sedを使用して行に分割することができます。
ausearch -i | sed -e 's/ : /\n /' -e 's/ scontext=/\n scontext=/'\<br /> -e 's/ tclass=/\n tclass=/' -e 's/ name=/\n name=/'\<br /> -e 's/ path=/\n path=/' | less
さらに、より整然とした出力が得られます。
----<br /> type=AVC msg=audit(02/15/21 22:07:52.490:34)<br /> avc: denied { write } for pid=860 comm=sm_manager<br /> name=tmp dev="rootfs" ino=1261<br /> scontext=u:r:smm.subj tcontext=u:r:tmp.fs<br /> tclass=dir permissive=1<br /> ----
次回のブログ記事もお楽しみに!
MVSecureサービスとMVXpertサービスの詳細については、こちらをご覧ください。
Please reach out to discuss your particular scenario today.