Product SiteDocumentation Site

14.5. SELinux の紹介

14.5.1. 原理

SELinux (Security Enhanced Linux) は Linux の LSM (Linux Security Modules) インターフェース上に設けられた強制アクセス制御システムです。具体的に言えば、カーネルはそれぞれのシステムコールの前にシステムコールを発行したプロセスが指定された操作に対する権限を与えられているか SELinux に問い合わせます。
SELinux はまとめてポリシーとして知られているルール群を使い、操作を許可したり禁止したりします。これらのルールの作成は難しいです。幸いなことに、設定作業の大部分を避けるために 2 種類の標準的なポリシー (targetedstrict) が提供されています。
SELinux を使うと、権限管理が伝統的な Unix システムとは全く違ったものになります。プロセスの権限は SELinux のセキュリティコンテキストに依存します。SELinux のセキュリティコンテキストはプロセスを開始したユーザの SELinux ユーザ名SELinux ロール、ユーザがプロセス開始時点で持っていた SELinux ドメインによって定義されます。正しく言えばプロセスの権限は SELinux ドメインに依存しますが、SELinux ドメイン間の遷移は SELinux ロールによって制御されます。最後に SELinux ロール間の遷移の可否は SELinux ユーザ名に依存します。
セキュリティコンテキストと Unix ログイン名

図 14.1 セキュリティコンテキストと Unix ログイン名

In practice, during login, the user gets assigned a default security context (depending on the roles that they should be able to endorse). This defines the current domain, and thus the domain that all new child processes will carry. If you want to change the current role and its associated domain, you must call newrole -r role_r -t domain_t (there is usually only a single domain allowed for a given role, the -t parameter can thus often be left out). This command authenticates you by asking you to type your password. This feature forbids programs to automatically switch roles. Such changes can only happen if they are explicitly allowed in the SELinux policy.
権限がすべてのオブジェクト (ファイル、ディレクトリ、ソケット、デバイスなど) に適用されないのは明らかです。権限はオブジェクトによって異なります。これを実現するために、それぞれのオブジェクトは SELinux タイプ と結び付けられています (これをラベリングと呼びます)。このため SELinux ドメインの権限はオブジェクトの SELinux タイプ (および、与えられた SELinux タイプによって間接的にラベリングされたすべてのオブジェクト) に対する一連の許可された (されていない) 操作を使って表現されます。
デフォルトで、プログラムはプログラムを起動したユーザに割り当てられた SELinux ドメインを継承しますが、標準的な SELinux のポリシーは多くの重要なプログラムが専用の SELinux ドメインで実行されることを要求しています。これを成し遂げるために、重要なプログラムの実行ファイルは専用の SELinux タイプでラベリングされています (たとえば、sshssh_exec_t でラベリングされています。ssh プログラムが起動すると ssh プログラムは ssh_t SELinux ドメインに自動的に切り替わります)。この自動 SELinux ドメイン遷移メカニズムによって、それぞれのプログラムに対して必要な権限だけを認めることが可能です。これが SELinux の基本原則です。
SELinux ドメイン間の自動遷移

図 14.2 SELinux ドメイン間の自動遷移

14.5.2. SELinux のセットアップ

SELinux のサポートは Debian の提供する標準的なカーネルに組み込まれています。コア Unix ツールは SELinux をサポートしており、修正は必要ありません。このため、SELinux を有効化することは比較的簡単です。
apt install selinux-basics selinux-policy-default コマンドで、SELinux システムを設定するために必要なパッケージが自動的にインストールされます。
selinux-policy-default パッケージには、標準的なルールが含まれています。デフォルトで、このポリシーは広範囲にわたって提供されるサービスへのアクセスを制限するだけです。ユーザセッションは制限されませんから、SELinux が正当なユーザ操作を妨害することはほとんどありません。しかしながら、このポリシーはマシンで実行されているシステムサービスのセキュリティを強化します。古い「strict」ルールと同じポリシーをセットアップするには、unconfined モジュールを無効化しなければいけません (モジュール管理に関してはこの節でさらに詳しく説明しています)。
selinux-policy-default パッケージをインストールしたら、すべての利用できるファイルをラベリングするべきです (これはファイルに SELinux タイプを割り当てることを意味します)。この操作は fixfiles relabel を使って手作業で開始しなければいけません。
これで SELinux システムの準備が整いました。SELinux を有効化するには、selinux=1 security=selinux パラメータを Linux カーネルに追加する必要があります。audit=1 パラメータを指定した場合、SELinux のログ記録が有効化され、すべての拒否された操作が記録されます。最後に enforcing=1 パラメータを指定した場合、ルールをアプリケーションに強制します。enforcing=1 パラメータを指定しなかった場合、SELinux はデフォルトの permissive モードで動作します。permissive モードの場合、拒否された操作はログ記録され、実行されます。このため、GRUB ブートローダ設定ファイルを変更して必要なパラメータを追加するべきです。これを簡単に行うには、/etc/default/grub の中の GRUB_CMDLINE_LINUX 変数に必要なパラメータを追加し、update-grub を実行します。SELinux は再起動後に動作状態になります。
selinux-activate スクリプトを使うことで、GRUB ブートローダ設定ファイルに対する変更操作が自動化され、次回起動時にラベリングが強制されます (強制的にラベリングすることで SELinux がまだ動作していなかった時とラベリングの実行中にラベリングされていないファイルが新しく作成されることを避けることが可能です)。この点は注目に値します。

14.5.3. SELinux システムの管理

selinux-policy-default パッケージに含まれる SELinux ポリシーはモジュール式のルール群で、selinux-policy-default パッケージはインストール時にインストール済みのサービスに基づいて対応するモジュールを自動的に検出して有効化します。そのため、システムは SELinux ポリシーをすぐに利用できるようになります。しかしながら、SELinux ポリシーを設定した後にサービスをインストールした場合、対応するモジュールを手作業で有効化する必要があります。これを行うのが semodule コマンドです。さらに、管理者はそれぞれのユーザに与える SELinux ロールを定義する能力を持っていなければいけません。これは semanage を使って行います。
このため semodulesemanage コマンドは /etc/selinux/default/ に保存されている現在の SELinux 設定を変更するために使われます。/etc/ に配置されている SELinux 以外の設定ファイルと異なり、SELinux の設定ファイルはすべて手作業で修正されなければいけません。管理者は SELinux 設定ファイルを編集するために設計されたプログラムを使うべきです。

14.5.3.1. SELinux モジュールの管理

利用できる SELinux モジュールは /usr/share/selinux/default/ ディレクトリに保存されています。現在の設定の中で SELinux モジュールの 1 つをインストールするには、semodule -i module.pp.bz2 を使うべきです。pp.bz2 拡張子は bzip2 で圧縮されたポリシーパッケージを意味しています。
現在の設定からモジュールを削除するには semodule -r module を使います。最後に、semodule -l コマンドは現在インストールされているモジュールとそのバージョンをリストします。モジュールを選択的に有効化するには semodule -e、無効化するには semodule -d を使います。
# semodule -i /usr/share/selinux/default/abrt.pp.bz2
libsemanage.semanage_direct_install_info: abrt module will be disabled after install as there is a disabled instance of this module present in the system.
# semodule -l
accountsd
acct
[...]
# semodule -e abrt
# semodule -d accountsd
# semodule -l
abrt
acct
[...]
# semodule -r abrt
libsemanage.semanage_direct_remove_key: abrt module at priority 100 is now active.semodule -l
semodule-n オプションを付けない限り、すぐさま新しい設定を読み込みます。semodule プログラムがデフォルトで現在の設定に対して操作を行う点は注目に値します (現在の設定は /etc/selinux/config 内の SELINUXTYPE 変数によって表されます)。しかし -s オプションを使えば、他の設定に対して操作を行うことも可能です。

14.5.3.2. ユーザの身元管理

ユーザはログイン時に毎回、SELinux ユーザ名を割り当てられます。SELinux ユーザ名はユーザに与える SELinux ロールを定義します。semanage コマンドを使えば、2 種類 (Unix ログイン名から SELinux ユーザ名へ、SELinux ユーザ名から SELinux ロールへ) の対応付けを設定することが可能です。
You should definitely read the semanage(8) manual page. All the managed concepts have their own manual page; for instance, semanage-login(8). Even if the command's syntax tends to be similar for all the concepts which are managed, it is recommended to read its manual page. You will find common options to most sub-commands: -a to add, -d to delete, -m to modify, -l to list, and -t to indicate a type (or domain).
semanage login -l は Unix ログイン名と SELinux ユーザ名の現在の対応付けをリストします。明確なエントリを設定されていない Unix ログイン名を持つユーザは __default__ という Unix ログイン名に対応する SELinux ユーザ名を割り当てられます。semanage login -a -s user_u user コマンドを使うことで、user で指定した Unix ログイン名を持つユーザに user_u で指定した SELinux ユーザ名を割り当てます。最後に、semanage login -d useruser で指定した Unix ログイン名を持つユーザに関連付けられたエントリを削除します。
# semanage login -a -s user_u rhertzog
# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         s0-s0:c0.c1023       *
rhertzog             user_u               s0                   *
root                 unconfined_u         s0-s0:c0.c1023       *
# semanage login -d rhertzog
semanage user -l は SELinux ユーザ名と許可された SELinux ロールの対応付けをリストします。新しい SELinux ユーザ名を追加する場合、SELinux ユーザ名に対応する SELinux ロールと、個人ファイル (/home/user/*) に SELinux タイプを割り当てるために使われるラベリングプレフィックスが必要になります。このプレフィックスは userstaffsysadm のどれか 1 つを選ばなければいけません。「staff」プレフィックスを選んだ場合、ファイルの SELinux タイプは「staff_home_dir_t」になります。新しい SELinux ユーザ名を作成するには semanage user -a -R roles -P prefix identity を使います。最後に、SELinux ユーザ名を削除するには semanage user -d identity を使います。
# semanage user -a -R 'staff_r user_r' -P staff test_u
# semanage user -l

                Labeling   MLS/       MLS/                          
SELinux User    Prefix     MCS Level  MCS Range                      SELinux Roles

root            sysadm     s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r
staff_u         staff      s0         s0-s0:c0.c1023                 staff_r sysadm_r
sysadm_u        sysadm     s0         s0-s0:c0.c1023                 sysadm_r
system_u        user       s0         s0-s0:c0.c1023                 system_r
test_u          staff      s0         s0                             staff_r user_r
unconfined_u    unconfined s0         s0-s0:c0.c1023                 system_r unconfined_r
user_u          user       s0         s0                             user_r
# semanage user -d test_u

14.5.3.3. ファイルコンテキスト、ポート、ブール値の管理

各 SELinux モジュールにはファイルラベリングルール群が含まれますが、特別な場合に応じてラベリングルールをカスタマイズすることも可能です。たとえば、ウェブサーバに /srv/www/ ファイル階層内のファイルを読むことを許可する場合、semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?" を実行し、その後 restorecon -R /srv/www/ を実行します。semanage fcontext -a で新しいラベリングルールを登録し、restorecon で現在のラベリングルールに基づいてファイルの SELinux タイプを再設定します。
同様に TCP/UDP ポートをラベリングして、ポート番号とそのポートのリッスンを許可するデーモンを対応付けることが可能です。たとえば、ウェブサーバがポート 8080 番をリッスンすることを可能にしたい場合、semanage port -m -t http_port_t -p tcp 8080 を実行します。
一部の SELinux モジュールでは、ブール値オプションを使ってデフォルトルールの挙動を微調整することが可能です。getsebool ユーティリティを使ってブール値オプションを調査します (getsebool boolean は 1 つのオプションを表示し、getsebool -a はすべてのオプションを表示します)。setsebool boolean value コマンドはブール値オプションの現在の値を変更します。-P オプションを付けるとこの修正が永続的なものになります。つまり、新しい値がデフォルトになり、再起動後も適用されることになります。以下の例では、ウェブサーバにホームディレクトリに対するアクセス権を与えています (ユーザが個人的なウェブサイトを ~/public_html/ の下に作る場合、この設定を使うと便利です)。
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
# setsebool -P httpd_enable_homedirs on
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on

14.5.4. ルールの適用

SELinux ポリシーはモジュール式なので、モジュールの用意されていない (場合によっては特注の) アプリケーション用に新しいモジュールを開発する方法を知っておくと良いでしょう。新しいモジュールはリファレンスポリシーを満足させなければいけません。
新しいモジュールを作成するには、selinux-policy-dev および selinux-policy-doc パッケージが必要です。selinux-policy-doc パッケージには、標準的なルールに関する文書 (/usr/share/doc/selinux-policy-doc/html/) と新しいモジュールを作成するためのテンプレートとして使えるサンプルファイルが含まれます。これらのファイルをインストールし、さらにしっかりと勉強してください。
$ cp /usr/share/doc/selinux-policy-doc/Makefile.example Makefile
$ cp /usr/share/doc/selinux-policy-doc/example.fc ./
$ cp /usr/share/doc/selinux-policy-doc/example.if ./
$ cp /usr/share/doc/selinux-policy-doc/example.te ./
.te ファイルは最も重要なファイルです。.te ファイルがルールを定義します。.fc ファイルは「ファイルコンテキスト」を定義します。「ファイルコンテキスト」はこのモジュールに関連するファイルに割り当てる SELinux タイプを意味します。.fc ファイルに含まれるデータはファイルのラベリング中に使われます。最後に、.if ファイルはモジュールのインターフェースを定義します。つまり、モジュールのインターフェースは一連の「公開関数」で、他のモジュールはこの関数を使ってここで作成されたモジュールと情報をやり取りします。

14.5.4.1. .fc ファイルの書き方

以下の例を読めば、.fc ファイルの構造を十分に理解することが可能です。複数のファイルおよび完全なディレクトリツリーに対して同じセキュリティコンテキストを割り当てるために、正規表現を使うことが可能です。

例 14.2 example.fc ファイル

# myapp 実行ファイルのファイルコンテキスト定義:
# ラベル: system_u:object_r:myapp_exec_t
# MLS sensitivity: s0
# MCS categories: <none>

/usr/sbin/myapp         --      gen_context(system_u:object_r:myapp_exec_t,s0)

14.5.4.2. .if ファイルの書き方

以下の例では、1 番目のインターフェース (「myapp_domtrans」) はアプリケーションを実行できるユーザを制御します。2 番目のインターフェース (「myapp_read_log」) はアプリケーションのログファイルに対する読み込み権限を制御します。
それぞれのインターフェースは .te ファイルに組み込むことが可能な有効なルール群を生成しなければいけません。そんなわけで、管理者は (gen_require マクロを使って) 使用するすべての SELinux タイプを宣言し、権限を取得するために標準的な指示文を使うべきです。しかしながら、他のモジュールが提供するインターフェースを使うことが可能な点に注意してください。次の節では、これらの権限を表現する方法についてより詳しく説明します。

例 14.3 example.if ファイル

## <summary>myapp ポリシーの一例</summary>
## <desc>
##      <p>
##              ここには myapp に関する追加説明を書きます。
##              <desc> タグの中では書式指定をするために
##              <p>、<ul>、<ol> html タグを使えます。
##      </p>
##      <p>
##              本ポリシーは myapp の以下に示す機能を動作させるために必要です。
##              <ul>
##              <li>機能 A</li>
##              <li>機能 B</li>
##              <li>機能 C</li>
##              </ul>
##      </p>
## </desc>
#

########################################
## <summary>
##      myapp を実行するために SELinux ドメインを遷移させます。
## </summary>
## <param name="domain">
##      遷移を許可する SELinux ドメイン。
## </param>
#
interface(`myapp_domtrans',`
        gen_require(`
                type myapp_t, myapp_exec_t;
        ')

        domtrans_pattern($1,myapp_exec_t,myapp_t)
')

########################################
## <summary>
##      myapp のログファイルを読み込みます。
## </summary>
## <param name="domain">
##      myapp のログファイルの読み込みを許可する SELinux ドメイン。
## </param>
#
interface(`myapp_read_log',`
        gen_require(`
                type myapp_log_t;
        ')

        logging_search_logs($1)
        allow $1 myapp_log_t:file r_file_perms;
')

14.5.4.3. .te ファイルの書き方

それでは example.te を見てみましょう。
policy_module(myapp,1.0.0) 1

########################################
#
# SELinux タイプと SELinux ドメインの宣言
#

type myapp_t; 2
type myapp_exec_t;
domain_type(myapp_t)
domain_entry_file(myapp_t, myapp_exec_t) 3

type myapp_log_t;
logging_log_file(myapp_log_t) 4

type myapp_tmp_t;
files_tmp_file(myapp_tmp_t)

########################################
#
# myapp のローカルポリシー
#

allow myapp_t myapp_log_t:file { read_file_perms append_file_perms }; 5

allow myapp_t myapp_tmp_t:file manage_file_perms;
files_tmp_filetrans(myapp_t,myapp_tmp_t,file)

1

モジュールは名前とバージョン番号で識別されます。policy_module マクロは必須です。

2

モジュールによって新しい SELinux タイプが導入される場合、type 文を使って新しい SELinux タイプを必ず宣言してください。多くの無駄な権限を与えるのでなく、必要な SELinux タイプをすべて作成してください。遠慮はいりません。

3

ここでは domain_type および domain_entry_file インターフェースを使って、myapp_exec_t とラベリングされた実行ファイルによって使われるプロセスの SELinux ドメインとして myapp_t SELinux タイプを定義しています。こうすることで、暗黙のうちにオブジェクトに exec_type 属性が追加されます。このおかげで、他のモジュールは myapp_exec_t とラベリングされたプログラムを実行する権限を取得することが可能になります。たとえば userdomain モジュールを使うことで、user_tstaff_tsysadm_t SELinux ドメインを持つプロセスが自分を実行することが可能になります。他の閉じ込められたアプリケーションの SELinux ドメインは、その SELinux ドメインに割り当てられたルールが同様の権限を取得しない限り (たとえば dpkg_t SELinux ドメインを持つ dpkg がこの場合に相当します)、myapp_exec_t とラベリングされたプログラムを実行する権限を持ちません。

4

logging_log_file is an interface provided by the reference policy. It indicates that files labeled with the given type are log files which ought to benefit from the associated rules (for example, granting rights to logrotate so that it can manipulate them).

5

allow 指示文は操作を許可するために使われる基本的な指示文です。1 番目のパラメータはこの操作を実行することを許されたプロセスの SELinux ドメインです。2 番目のパラメータは 1 番目のパラメータで指定した SELinux ドメインのプロセスが操作することが可能なオブジェクトを定義します。2 番目のパラメータは「type:class」の形で定義します。ここで type は SELinux タイプで class はオブジェクトの種類 (ファイル、ディレクトリ、ソケット、名前付きパイプなど) です。最後に、3 番目のパラメータはパーミッション (許可された操作) を表現します。
パーミッションは許可された操作の一式として定義され、以下のテンプレートに従います。すなわち { operation1 operation2 } です。しかしながら、最も役に立つパーミッションを表すマクロを使うことも可能です。/usr/share/selinux/devel/include/support/obj_perm_sets.spt には、最も役に立つパーミッションのマクロが説明されています。
The following web page provides a relatively exhaustive list of object classes, and permissions that can be granted.
さらに、対象のアプリケーションやサービスが正しく動くために必要な最低限のルールセットを見つけ出さなければいけません。これを行うには、アプリケーションの動作方法とアプリケーションが管理および生成するデータの種類に関する詳しい知識が必要です。
しかしながら、経験的なアプローチが使えます。対応するオブジェクトに対する正しいラベリングが終わっていれば、アプリケーションを permissive モードで使うことが可能です。そして permissive モードでは、禁止されるであろう操作はログ記録されて実行されます。このログを解析することで、許可する操作を識別することが可能になります。以下は permissive モードでアプリケーションを動かした場合に記録されるログエントリの例です。
avc:  denied  { read write } for  pid=1876 comm="syslogd" name="xconsole" dev=tmpfs ino=5510 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:device_t:s0 tclass=fifo_file permissive=1
このメッセージをより詳しく理解するために、それぞれの要素について勉強しましょう。

表 14.1 SELinux ログエントリの解析

メッセージ説明
avc: denied操作が拒否されました。
{ read write }この操作には readwrite パーミッションが必要です。
pid=1876PID 1876 のプロセスがこの操作を実行しました (または実行を試行しました)。
comm="syslogd"プロセスは syslogd プログラムのインスタンスです。
name="xconsole"対象のオブジェクトは xconsole と名付けられました。場合によってはこれの代わりにフルパスを含む「path」変数が設定されていることもあります。
dev=tmpfsThe device hosting the target object is a tmpfs (an in-memory filesystem). For a real disk, you could see the partition hosting the object (for example, “sda3”).
ino=5510オブジェクトは inode 番号 5510 で識別されています。
scontext=system_u:system_r:syslogd_t:s0これは操作を実行したプロセスのセキュリティコンテキストです。
tcontext=system_u:object_r:device_t:s0これは対象オブジェクトのセキュリティコンテキストです。
tclass=fifo_file対象オブジェクトは FIFO ファイルです。
By observing this log entry, it is possible to build a rule that would allow this operation. For example, allow syslogd_t device_t:fifo_file { read write }. This process can be automated, and it is exactly what the audit2allow command (of the policycoreutils package) offers. This approach is only useful if the various objects are already correctly labeled according to what must be confined. In any case, you will have to carefully review the generated rules and validate them according to your knowledge of the application. Effectively, this approach tends to grant more rights than are really required. The proper solution is often to create new types and to grant rights on those types only. It also happens that a denied operation isn't fatal to the application, in which case it might be better to just add a “dontaudit” rule to avoid the log entry despite the effective denial.

14.5.4.4. ファイルのコンパイル

Once the 3 files (example.if, example.fc, and example.te) match your expectations for the new rules, rename them to myapp.extension and run make NAME=devel to generate a module in the myapp.pp file (you can immediately load it with semodule -i myapp.pp). If several modules are defined, make will create all the corresponding .pp files.