newrole -r role_r -t domain_t
を実行しなければいけません (通常 SELinux ロールと SELinux ドメインは一対一に対応しているため、-t
パラメータは省略されることが多いです)。newrole
コマンドはユーザに自分のパスワードを入力させることで認証を行います。この機能のおかげで、プログラムが自動的に SELinux ロールを切り替えることを禁止できます。SELinux ロールの変更を行えるのは、ユーザが SELinux ポリシーに基づいて SELinux ロールの変更を許可されている場合に限ります。
ssh
は ssh_exec_t
でラベリングされています。ssh
プログラムが起動すると ssh
プログラムは ssh_t
SELinux ドメインに自動的に切り替わります)。この自動 SELinux ドメイン遷移メカニズムによって、それぞれのプログラムに対して必要な権限だけを認めることが可能です。これが SELinux の基本原則です。
apt install selinux-basics selinux-policy-default
コマンドで、SELinux システムを設定するために必要なパッケージが自動的にインストールされます。
unconfined
モジュールを無効化しなければいけません (モジュール管理に関してはこの節でさらに詳しく説明しています)。
fixfiles relabel
を使って手作業で開始しなければいけません。
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 がまだ動作していなかった時とラベリングの実行中にラベリングされていないファイルが新しく作成されることを避けることが可能です)。この点は注目に値します。
semodule
コマンドです。さらに、管理者はそれぞれのユーザに与える SELinux ロールを定義する能力を持っていなければいけません。これは semanage
を使って行います。
semodule
と semanage
コマンドは /etc/selinux/default/
に保存されている現在の SELinux 設定を変更するために使われます。/etc/
に配置されている SELinux 以外の設定ファイルと異なり、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
#
semodule -l
abrt 1.5.0 Disabled accountsd 1.1.0 acct 1.6.0 [...]
#
semodule -e abrt
#
semodule -d accountsd
#
semodule -l
abrt 1.5.0 accountsd 1.1.0 Disabled acct 1.6.0 [...]
#
semodule -r abrt
#
semodule -l
accountsd 1.1.0 Disabled acct 1.6.0 [...]
semodule
は -n
オプションを付けない限り、すぐさま新しい設定を読み込みます。semodule
プログラムがデフォルトで現在の設定に対して操作を行う点は注目に値します (現在の設定は /etc/selinux/config
内の SELINUXTYPE
変数によって表されます)。しかし -s
オプションを使えば、他の設定に対して操作を行うことも可能です。
semanage
コマンドを使えば、2 種類 (Unix ログイン名から SELinux ユーザ名へ、SELinux ユーザ名から SELinux ロールへ) の対応付けを設定することが可能です。
semanage
コマンドはサブコマンドごとに管理する要素が決められています。サブコマンドの構文はすべてのサブコマンド間で類似しているとは言うものの、管理者は semanage(8) マニュアルページを読むべきです。すべてのサブコマンドに対して共通のオプションが存在します。たとえば -a
は追加、-d
は削除、-m
は修正、-l
はリスト、-t
は SELinux タイプ (または SELinux ドメイン) の指定を表します。
semanage login -l
は Unix ログイン名と SELinux ユーザ名の現在の対応付けをリストします。明確なエントリを設定されていない Unix ログイン名を持つユーザは __default__
という Unix ログイン名に対応する SELinux ユーザ名を割り当てられます。semanage login -a -s user_u user
コマンドを使うことで、user で指定した Unix ログイン名を持つユーザに user_u で指定した SELinux ユーザ名を割り当てます。最後に、semanage login -d user
は user で指定した Unix ログイン名を持つユーザに関連付けられたエントリを削除します。
#
semanage login -a -s user_u rhertzog
#
semanage login -l
ログイン名 SELinux ユーザー MLS/MCS 範囲 サービス __default__ unconfined_u SystemLow-SystemHigh * rhertzog user_u SystemLow * root unconfined_u SystemLow-SystemHigh * system_u system_u SystemLow-SystemHigh * #
semanage login -d rhertzog
semanage user -l
は SELinux ユーザ名と許可された SELinux ロールの対応付けをリストします。新しい SELinux ユーザ名を追加する場合、SELinux ユーザ名に対応する SELinux ロールと、個人ファイル (/home/user/*
) に SELinux タイプを割り当てるために使われるラベリングプレフィックスが必要になります。このプレフィックスは user
、staff
、sysadm
のどれか 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
ラベリング MLS/ MLS/ SELinux ユーザー プレフィックス MCS レベル MCS 範囲 SELinux ロール root sysadm SystemLow SystemLow-SystemHigh staff_r sysadm_r system_r staff_u staff SystemLow SystemLow-SystemHigh staff_r sysadm_r sysadm_u sysadm SystemLow SystemLow-SystemHigh sysadm_r system_u user SystemLow SystemLow-SystemHigh system_r test_u staff SystemLow SystemLow staff_r user_r unconfined_u unconfined SystemLow SystemLow-SystemHigh system_r unconfined_r user_u user SystemLow SystemLow user_r #
semanage user -d test_u
/srv/www/
ファイル階層内のファイルを読むことを許可する場合、semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
を実行し、その後 restorecon -R /srv/www/
を実行します。semanage fcontext -a
で新しいラベリングルールを登録し、restorecon
で現在のラベリングルールに基づいてファイルの SELinux タイプを再設定します。
semanage port -m -t http_port_t -p tcp 8080
を実行します。
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
/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
ファイルはモジュールのインターフェースを定義します。つまり、モジュールのインターフェースは一連の「公開関数」で、他のモジュールはこの関数を使ってここで作成されたモジュールと情報をやり取りします。
.fc
ファイルの構造を十分に理解することが可能です。複数のファイルおよび完全なディレクトリツリーに対して同じセキュリティコンテキストを割り当てるために、正規表現を使うことが可能です。
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; ')
example.te
を見てみましょう。
policy_module(myapp,1.0.0) ######################################## # # SELinux タイプと SELinux ドメインの宣言 # type myapp_t; type myapp_exec_t; domain_type(myapp_t) domain_entry_file(myapp_t, myapp_exec_t) type myapp_log_t; logging_log_file(myapp_log_t) type myapp_tmp_t; files_tmp_file(myapp_tmp_t) ######################################## # # myapp のローカルポリシー # allow myapp_t myapp_log_t:file { read_file_perms append_file_perms }; allow myapp_t myapp_tmp_t:file manage_file_perms; files_tmp_filetrans(myapp_t,myapp_tmp_t,file)
モジュールは名前とバージョン番号で識別されます。policy_module マクロは必須です。
| |
モジュールによって新しい SELinux タイプが導入される場合、type 文を使って新しい SELinux タイプを必ず宣言してください。多くの無駄な権限を与えるのでなく、必要な SELinux タイプをすべて作成してください。遠慮はいりません。
| |
ここでは domain_type および domain_entry_file インターフェースを使って、myapp_exec_t とラベリングされた実行ファイルによって使われるプロセスの SELinux ドメインとして myapp_t SELinux タイプを定義しています。こうすることで、暗黙のうちにオブジェクトに exec_type 属性が追加されます。このおかげで、他のモジュールは myapp_exec_t とラベリングされたプログラムを実行する権限を取得することが可能になります。たとえば userdomain モジュールを使うことで、user_t 、staff_t 、sysadm_t SELinux ドメインを持つプロセスが自分を実行することが可能になります。他の閉じ込められたアプリケーションの SELinux ドメインは、その SELinux ドメインに割り当てられたルールが同様の権限を取得しない限り (たとえば dpkg_t SELinux ドメインを持つ dpkg がこの場合に相当します)、myapp_exec_t とラベリングされたプログラムを実行する権限を持ちません。
| |
logging_log_file はリファレンスポリシーによって提供されるインターフェースです。これは指定された SELinux タイプでラベリングされたファイルはその SELinux タイプに対応するルールから恩恵を受ける義務があるログファイルであることを表します (たとえば、logrotate がログファイルを処理することを可能にするために、logrotate に権限を与える場合に使います)。
| |
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 には、最も役に立つパーミッションのマクロが説明されています。
以下のウェブページでは、オブジェクトクラスと与えられるパーミッションの比較的包括的なリストが載せられています。
|
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 } | この操作には read と write パーミッションが必要です。 |
pid=1876 | PID 1876 のプロセスがこの操作を実行しました (または実行を試行しました)。 |
comm="syslogd" | プロセスは syslogd プログラムのインスタンスです。 |
name="xconsole" | 対象のオブジェクトは xconsole と名付けられました。場合によってはこれの代わりにフルパスを含む「path」変数が設定されていることもあります。 |
dev=tmpfs | 対象のオブジェクトをホストしているデバイスは tmpfs (メモリ内ファイルシステム) です。実ディスクの場合、オブジェクトをホストしているパーティション (たとえば「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 ファイルです。 |
allow syslogd_t device_t:fifo_file { read write }
のようになります。この作業は自動化することが可能です。これが audit2allow
コマンド (policycoreutils パッケージに含まれます) の役割です。設定する必要のある内容に応じてさまざまなオブジェクトが既に正しくラベリングされている場合にのみ、このアプローチは役に立ちます。いずれにせよ、管理者は必ず生成されたルールを注意深く確認し、アプリケーションに対する知識に基づいてルールの妥当性を検査しなければいけません。事実上、このアプローチはアプリケーションが本当に必要としている権限よりも多くの権限を与えようとします。ほとんどの場合、新しい SELinux タイプを作成し、作成した SELinux タイプだけに権限を与えることが適切な解決策と言えます。また、拒否された操作がアプリケーションにとって致命的でない場合もあります。この場合、「dontaudit
」ルールを追加するだけに留めることがより良い解決策かもしれません。こうすることで、実際の実行を拒否するのではなくログエントリの記録だけが拒否されます。