SELinuxの基本を理解する

# はじめに
本記事はSecurity-Enhanced Linux（以下、SELinux）について記載しています。

日本におけるシステム開発では、OSインストール直後にSELinuxを無効化することが多いため、SELinuxを扱う機会は、少ないのではないでしょうか。

SELinuxは、強制アクセス制御によって、不正アクセスや侵害後の被害拡大を防ぐセキュリティ対策の一つです。

従ってSELinuxはサイバーセキュリティ対策として非常に有効なため、まずはSELinuxの基本を理解しましょう。

## 強制アクセス制御
Linuxのオブジェクトに対するアクセス制御方式は、ファイルパーミッションを基本とした**任意アクセス制御**と、**強制アクセス制御**の2種類に大別できます。

任意アクセス制御ではなく、強制アクセス制御を利用する目的は何でしょうか？

### 任意アクセス制御の欠点
任意アクセス制御を用いてLinuxサーバを運用する場合、以下の様なリスクが顕在化します。

Linuxのrootユーザーは、システム全体に対する完全な管理権限を持つため、AWS環境におけるAWSアカウントのルートユーザーと同様に、非常に高い権限を持っています。

そのため、rootユーザーが奪取されると、すべてのデータへのアクセスや改ざんが可能となり、システム全体の乗っ取りに繋がります。

また、任意アクセス制御はファイルなどに対する細かな権限設定が困難です。その結果、意図しない権限の過剰付与が発生しやすく、セキュリティリスクに発展します。

従って任意アクセス制御の運用は、ファイル所有者の設定に依存するため、システム全体の権限を一元的かつ強制的に制御することが難しいという課題があります。

### セキュアOS
**セキュアOS**は、SELinuxの様な強制アクセス制御(Mandatory Access Control:MAC)機能を実装したOSです。

厳密な定義はありませんが、以下の様なアクセス制御機構を持つOSが該当します。

- SELinux
    - 米国家安全保障局によって開発された、Linux向けの強制アクセス制御機構
    - ラベルベースのセキュリティポリシーに基づき、すべてのプロセスやファイルにセキュリティコンテキストを割り当て、システム全体に対して一貫性のあるアクセス制御を実施する
    - 管理者権限を持つプロセスでも、ポリシーに反したアクセスは拒否されるため、root権限の操作も抑制される
- AppArmor
    - Ubuntuをはじめとする多くのLinuxディストリビューションで採用されているLinuxセキュリティモジュールの一つ
    - Linuxの各アプリケーション毎にプロファイルを関連付けることで、特定のアプリケーション単位にアクセス制限を設定する点が特徴
    - サーバー用途だけでなく、エンドユーザー向けの環境でも広く利用されている
- Smack
    - カーネル2.6.25[^1]から組み込まれたセキュリティ機構として、軽量でシンプルなMAC機構を提供するキュリティモジュール
    - 組込み機器やIoTデバイス向けに設計されており、Tizen OS[^2]などで採用されている
    - SELinuxよりも機能がシンプルなため、設定が容易である

::: note
SELinuxは従来のサーバ用途だけでなく、組み込みやIOTの分野でも導入されています。例えば、AndroidのOSでは、デフォルトでSELinuxが有効になっています。

参考：[Android における Security-Enhanced Linux](https://source.android.com/docs/security/features/selinux?hl=ja)

また、セキュリティ監査の項目として[OpenSCAP](https://www.open-scap.org/)や[CIS Benchmarks](https://www.cisecurity.org/cis-benchmarks)などで活用されています。
:::

[^1]: [KernelNewbies: Linux_2_6_25](https://kernelnewbies.org/Linux_2_6_25)
[^2]: [Security Tips](https://docs.tizen.org/application/native/guides/security/security-tip/)

## SELinuxの仕組み
SELinuxを適切に運用するためには、SELinuxの仕組みに対する理解が重要です。

### SELinuxの効果
SELinuxの目的は「**最小権限の原則**」に基づき、システム内のプロセスやユーザーに必要最小限の権限のみを付与することで、不要なアクセスを制限し、セキュリティを強化することにあります。

SElinuxを導入していないシステムにおいて、Webサーバなどのデーモンプロセスが侵害された場合のイメージ図を以に記載します。

以下の図では、脆弱性を悪用した攻撃によって、Webサーバのデーモンプロセスが乗っ取られた状態を表現しています。

![SELinux.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/521ef550-aee2-495a-ac4d-359c7421b2c8.png)

このように侵害された場合、攻撃者はリモートからマルウェアや攻撃ツールをダウンロード及び実行し、さらなる脆弱性を突いてroot権限の奪取を試みます。結果として、システム全体が完全に制御されるリスクがあります。

しかし、SELinuxを導入することで、以下のような効果が期待でき、被害を侵害されたプロセスの範囲内に限定することが可能になります。

- システム侵害の影響を局所化（プロセス単位での権限制御）
- マルウェア・ルートキットの活動を抑制（機密性の高い情報にアクセス不可）
- ゼロデイ攻撃や未知の脆弱性に対するセキュリティ対策（ポリシーで実行制御）

![SELinux-ページ1のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/7dd6dc2f-6ade-457f-bab3-d46995e4d759.png)

::: note
仮にrootユーザーの権限が奪取された場合でも、SELinuxの強制アクセス制御はそれを回避することを許しません。従ってSELinuxのポリシーによって、rootユーザーであってもアクセスできない領域が存在し、被害を最小限に抑えることができます。
:::

### SELinuxの機能
SELinuxは、以下のような主要なセキュリティ機能によってアクセス制御を実現しています。

- Type Enforcement（TE）
- Multi-Category Security（MCS）
- ドメイン遷移
- Role Based Access Control（RBAC）

**TE**は、SELinuxの中核となる機能でありプロセス（ドメイン）がアクセスできるリソース（ファイルやソケットなど）を厳密に制御します。セキュリティポリシーには「どのドメインがどのタイプのリソースにアクセスできるか」が記述されているため、明示的に許可されていないアクセスはすべてブロックされます。

**MCS**は、同一ホスト上で複数の仮想環境やユーザーセッションを分離するために利用されます。特に仮想化やコンテナ環境において、論理的な分離を実現するための軽量なラベル付け方式として活用されます。

**ドメイン遷移**は、あるプロセスが別のプログラムを実行する際に、新たなセキュリティコンテキスト（ドメイン）に遷移させる仕組みです。これにより、例えばWebサーバがCGIスクリプトを実行する際に、スクリプトがWebサーバとは異なる最小権限のドメインで実行されるよう制御できます。

**RBAC**は、ユーザーに対して役割（ロール）を割り当て、そのロールに応じたアクセス制限を行う仕組みです。ユーザー→ロール→ドメインという階層構造でアクセス制御を行うため、ユーザー単位でのきめ細かな制御が可能です。

httpdプロセスを例にしたTEによるアクセス制御のイメージ図を記載します。

![SELinux-TE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/c145d84f-14c8-4212-8d1e-bb22445d6bb8.png)

1. httpdプロセスがWebサイトのページや画像などのコンテンツにアクセスを試みる
1. Linuxカーネルの中のSELinuxモジュールがセキュリティポリシーをチェックする
1. セキュリティポリシーによってアクセスが許可されている場合は、オブジェクトのアクセスが許可される

:::note
セキュリティポリシーは、明示的にアクセスを許可しない限り全てのアクセスが拒否されます。また、アクセスが許可されていない場合は、アクセスがブロックされたことをログに出力します。
:::

## SELinuxの設定
SELinuxの設定に関して、最低限知っておきたい内容を以下に記載します。

### 動作モード
SELinuxでは、以下3種類のモードが存在します。

Permissiveモードは、SELinuxのトラブルシューティングやデバッグなどに使用されます。

| モード | 状態 |
|:-|:-|
| disabled | SELinuxが無効（全てのアクセスが許可されログにも出力されない） |
| Enforcing | SELinuxが有効（ポリシーに違反した場合、アクセスはブロックされログ出力を行う） |
| Permissive | ポリシーは強制されないが、違反があればログに記録される |

現在の動作モードを確認したい場合は、以下のコマンドを実行します。

`# getenforce`

```
Enforcing
```

SELinuxの動作モードを無効にしたい場合は、以下のコマンドを実行します。

`# setenforce 0`

```
Permissive
```

::: note
恒久的に無効化する場合は、`/etc/selinux/config`ファイルを編集して`disabled`に設定します。
:::

また、`getenforce`コマンド以外でも以下のコマンドで状態を確認することができます。

`# selinuxenabled`

`selinuxenabled`コマンド実行後、有効な場合は0を返します。

```
root@localhost:~# echo $?
0
```

### 動作環境
SELinuxに関する設定ファイルは、`/etc/selinux/`配下に格納されています。

```
合計 8
-rw-r--r--. 1 root root 1187 10月 13 23:58 config
-rw-r--r--. 1 root root 2668  7月 18  2024 semanage.conf
drwxr-xr-x. 5 root root  133  3月 21 17:25 targeted
```

`/etc/selinux/config`ファイルは、システム上のSELinuxの状態を制御するための設定ファイルです。

```
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
# See also:
# https://docs.fedoraproject.org/en-US/quick-docs/getting-started-with-selinux/#getting-started-with-selinux-selinux-states-and-modes
#
# NOTE: In earlier Fedora kernel builds, SELINUX=disabled would also
# fully disable SELinux during boot. If you need a system with SELinux
# fully disabled instead of SELinux running with no policy loaded, you
# need to pass selinux=0 to the kernel command line. You can use grubby
# to persistently set the bootloader to boot with selinux=0:
#
#    grubby --update-kernel ALL --args selinux=0
#
# To revert back to SELinux enabled:
#
#    grubby --update-kernel ALL --remove-args selinux
#
SELINUX=enforcing
# SELINUXTYPE= can take one of these three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected.
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted
```

`targeted`ディレクトリには、targetedポリシーに関する全ての設定やコンパイル済みポリシー情報が含まれています。

以下の例では、`/etc/selinux/targeted/policy/policy.33`ファイルが該当します。また、ファイルの実態はバイナリ形式のファイルであり、数字の33についてはポリシーのバージョン番号を意味しています。

```
/etc/selinux/
├── config
├── semanage.conf
└── targeted
    ├── booleans.subs_dist
    ├── contexts
    │   ├── customizable_types
    │   ├── dbus_contexts
    │   ├── default_contexts
    │   ├── default_type
    │   ├── failsafe_context
    │   ├── files
    │   │   ├── file_contexts
    │   │   ├── file_contexts.bin
    │   │   ├── file_contexts.homedirs
    │   │   ├── file_contexts.homedirs.bin
    │   │   ├── file_contexts.local
    │   │   ├── file_contexts.subs
    │   │   ├── file_contexts.subs_dist
    │   │   └── media
    │   ├── initrc_context
    │   ├── lxc_contexts
    │   ├── openssh_contexts
    │   ├── removable_context
    │   ├── securetty_types
    │   ├── sepgsql_contexts
    │   ├── snapperd_contexts
    │   ├── systemd_contexts
    │   ├── userhelper_context
    │   ├── users
    │   │   ├── guest_u
    │   │   ├── root
    │   │   ├── staff_u
    │   │   ├── sysadm_u
    │   │   ├── unconfined_u
    │   │   ├── user_u
    │   │   └── xguest_u
    │   ├── virtual_domain_context
    │   ├── virtual_image_context
    │   └── x_contexts
    ├── logins
    ├── policy
    │   └── policy.33
    ├── setrans.conf
    └── seusers
```

SELinuxはシステム起動時に`/etc/selinux/targeted/policy/policy.33`ファイルを読み込み、対象プロセスやファイルに対してアクセス制御を実行します。

アクティブなポリシーのバージョンを確認したい場合は、`sestatus`コマンドなどで確認できます。

以下の例では、`policy.33`が使用されていることが分かります。

```
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33
```

`/etc/selinux/targeted/contexts/files/file_contexts`ファイルは、ファイルシステム上のファイルに対して、SELinuxのタイプを含むセキュリティコンテキストの割り当てを定義したファイルです。

なお、このファイルを編集しただけでは設定が反映されません。ファイルシステム内のxattrと呼ばれるファイルシステムの拡張領域に設定内容を書き込む必要があります。

そのため、ポリシーを変更した後は、`restorecon`や`setfiles`コマンドを用いて、対象ファイルのラベルをxattrに反映します。コマンドの使用方法については後述します。

### セキュリティコンテキスト
プロセスやリソースには、セキュリティコンテキストと呼ばれる属性が設定されています。

プロセスのセキュリティコンテキストを確認したい場合は、`ps`コマンドのオプションに`Z`を付与します。

以下はhttpdプロセスの例です。左からユーザー識別子、ロール識別子、タイプ識別子、MLSを示します。

また、`_t`で終わる文字列がドメインを意味し、以下の場合、httpd_tドメインが付与されています。

`# ps axZ | grep 'httpd\|LABEL'  | grep -v grep`

```
LABEL                               PID TTY      STAT   TIME COMMAND
system_u:system_r:httpd_t:s0       1451 ?        Ss     0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0       1453 ?        S      0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0       1454 ?        Sl     0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0       1521 ?        Sl     0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0       1522 ?        Sl     0:00 /usr/sbin/httpd -DFOREGROUND
```

ファイルやディレクトリのセキュリティコンテキストを確認したい場合もオプションに`Z`を付与します。

同様に`_t`で終わる文字列がタイプを意味します。

`# ls -lZ /var/www/`

```
合計 0
drwxr-xr-x. 2 root root system_u:object_r:httpd_sys_script_exec_t:s0 6  8月  1  2024 cgi-bin
drwxr-xr-x. 2 root root system_u:object_r:httpd_sys_content_t:s0     6  8月  1  2024 html
```

## 実践
`systemctl`コマンドでApacheを起動しようとした際に、SELinuxのポリシーによりアクセスが拒否され、起動に失敗するケースを例に解説します。

`# systemctl status httpd.service`

```
× httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
             /etc/systemd/system.control/httpd.service.d
             └─50-MemoryLimit.conf
     Active: failed (Result: exit-code) since Wed 2025-04-09 22:56:15 JST; 1s ago
       Docs: man:httpd.service(8)
    Process: 1204 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=exited, status=1/FAILURE)
   Main PID: 1204 (code=exited, status=1/FAILURE)
     Status: "Reading configuration..."
        CPU: 39ms

 4月 09 22:56:14 localhost.localdomain systemd[1]: Starting httpd.service - The Apache HTTP Server...
 4月 09 22:56:14 localhost.localdomain (httpd)[1204]: httpd.service: Referenced but unset environment variable evaluates to an empty string: OPTIONS
 4月 09 22:56:15 localhost.localdomain systemd[1]: httpd.service: Main process exited, code=exited, status=1/FAILURE
 4月 09 22:56:15 localhost.localdomain systemd[1]: httpd.service: Failed with result 'exit-code'.
 4月 09 22:56:15 localhost.localdomain systemd[1]: Failed to start httpd.service - The Apache HTTP Server.
```

Apacheが出力する`error_log`ファイルを参照すると、`Failed to configure certificate`のメッセージよりSSL証明書を読み込んだものの、ファイルのアクセスに失敗していることが推測できます。

`# tail /var/log/httpd/error_log`

```
[Wed Apr 09 22:56:14.996570 2025] [suexec:notice] [pid 1204:tid 1204] AH01232: suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
[Wed Apr 09 22:56:14.998253 2025] [ssl:emerg] [pid 1204:tid 1204] AH02562: Failed to configure certificate www.test.com:443:0 (with chain), check /home/test/cert/newcert.pem
[Wed Apr 09 22:56:14.998267 2025] [ssl:emerg] [pid 1204:tid 1204] SSL Library Error: error:8000000D:system library::Permission denied (calling fopen(/home/test/cert/newcert.pem, r))
[Wed Apr 09 22:56:14.998271 2025] [ssl:emerg] [pid 1204:tid 1204] SSL Library Error: error:10080002:BIO routines::system lib
[Wed Apr 09 22:56:14.998273 2025] [ssl:emerg] [pid 1204:tid 1204] SSL Library Error: error:0A080002:SSL routines::system lib
```

SELinuxによるアクセス拒否は、`/var/log/audit/audit.log`ファイルを参照することで確認できます。

しかし、ログファイルはUNIX時間で記録されていたり、他の情報も多く含まれているため、分析には手間がかかります。

### 違反したポリシーの調査方法
SELinuxのポリシー違反を調査する場合は、`ausearch`コマンドが役に立ちます。

コマンドの使い方として、`-m avc`オプション[^3]を付与することで、SELinuxに関するログが確認できます。また、以下の例では`--start today`を付与して、今日の日時を指定してフィルタしています。

`# ausearch -m avc --start today`

```
time->Wed Apr  9 22:56:14 2025
type=AVC msg=audit(1744206974.997:183): avc:  denied  { read } for  pid=1204 comm="httpd" name="newcert.pem" dev="dm-0" ino=1491936 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:user_home_t:s0 tclass=file permissive=0
```

上記ログよりApacheが`user_home_t`にラベル付けされたサーバ証明書（newcert.pem）を読みとろうとして、SELinuxによって拒否されたことが分かります。また、`permissive=0`は、SELinuxがEnforcingモードで動作していることを示してます。

アクセス拒否の理由については、Apacheのプロセスである`httpd_t`は通常、ユーザーのホームディレクトリにあるファイルの参照が許されてないためです。

`ls`コマンドでファイルのセキュリティコンテキストを確認すると、`user_home_t`のタイプについて確認できます。

`# ls -lZ /home/test/cert/newcert.pem`

```
-rw-r--r--. 1 root root system_u:object_r:user_home_t:s0 4629  3月 21 18:37 /home/test/cert/newcert.pem
```

アクセスが拒否されないようにするためには、Apacheが読み取るファイルに対して、SELinuxのラベル（タイプ）を適切に設定する必要があります。

従って`chcon`コマンドを使用して、ファイルのタイプを`httpd_sys_content_t`に変更します。

`# chcon -t httpd_sys_content_t /home/test/cert/newcert.pem`

上記コマンド実行後、セキュリティコンテキストが`httpd_sys_content_t`に変更されたことが確認できます。

`# ls -lZ /home/test/cert/newcert.pem`

```
-rw-r--r--. 1 root root system_u:object_r:httpd_sys_content_t:s0 4629  3月 21 18:37 /home/test/cert/newcert.pem
```

同様に秘密鍵についてもセキュリティコンテキストを修正すると、Apacheを起動することができます。

`# systemctl status httpd.service`

```
● httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/service.d
             └─10-timeout-abort.conf
             /etc/systemd/system.control/httpd.service.d
             └─50-MemoryLimit.conf
     Active: active (running) since Wed 2025-04-09 23:25:35 JST; 4s ago
       Docs: man:httpd.service(8)
   Main PID: 2395 (httpd)
     Status: "Started, listening on: port 443, port 80"
      Tasks: 177 (limit: 2212)
     Memory: 15.3M (limit: 100.0M peak: 15.6M)
        CPU: 43ms
     CGroup: /system.slice/httpd.service
             ├─2395 /usr/sbin/httpd -DFOREGROUND
             ├─2397 /usr/sbin/httpd -DFOREGROUND
             ├─2398 /usr/sbin/httpd -DFOREGROUND
             ├─2442 /usr/sbin/httpd -DFOREGROUND
             └─2478 /usr/sbin/httpd -DFOREGROUND

 4月 09 23:25:35 localhost.localdomain systemd[1]: Starting httpd.service - The Apache HTTP Server...
 4月 09 23:25:35 localhost.localdomain (httpd)[2395]: httpd.service: Referenced but unset environment variable evaluates to an empty string: OPTIONS
 4月 09 23:25:35 localhost.localdomain systemd[1]: Started httpd.service - The Apache HTTP Server.
 4月 09 23:25:35 localhost.localdomain httpd[2395]: Server configured, listening on: port 443, port 80
```

::: note
上記の様な権限不足について原因が単純な場合は、booleanによるアクセス権限の追加で回避できますが、booleanで用意されていない場合は、個別にアクセス許可のモジュールを追加します。
:::

[^3]: Access Vector Cacheの略称

### SELinuxのコマンド
SELinuxのコマンドについて紹介します。

- getsebool

`getsebool`コマンドは、特定のSELinuxブール値、またはすべてのSELinuxブール値の論理値をオンまたはオフで表示します。

すべてのSELinuxブール値を表示したい場合は、以下のコマンドを実行します。特定のSELinuxブール値を表示したい場合は、論理パラメータを引数に指定します。

`# getsebool -a`

<details><summary>出力例</summary>

```
brt_anon_write --> off
abrt_handle_event --> on
abrt_upload_watch_anon_write --> on
antivirus_can_scan_system --> off
antivirus_use_jit --> off
auditadm_exec_content --> on
authlogin_nsswitch_use_ldap --> off
authlogin_radius --> off
authlogin_yubikey --> off
awstats_purge_apache_log_files --> off
boinc_execmem --> on
cdrecord_read_content --> off
cluster_can_network_connect --> off
cluster_manage_all_files --> off
cluster_use_execmem --> off
cobbler_anon_write --> off
cobbler_can_network_connect --> off
cobbler_use_cifs --> off
cobbler_use_nfs --> off
collectd_tcp_network_connect --> off
colord_use_nfs --> off
condor_tcp_network_connect --> off
conman_can_network --> off
conman_use_nfs --> off
cron_can_relabel --> off
cron_system_cronjob_use_shares --> off
cron_userdomain_transition --> on
cups_execmem --> off
cvs_read_shadow --> off
daemons_dontaudit_scheduling --> on
daemons_dump_core --> off
daemons_enable_cluster_mode --> off
daemons_use_tcp_wrapper --> off
daemons_use_tty --> off
dbadm_exec_content --> on
dbadm_manage_user_files --> off
dbadm_read_user_files --> off
deny_bluetooth --> off
deny_execmem --> off
deny_ptrace --> off
dhcpc_exec_iptables --> off
dhcpd_use_ldap --> off
dnsmasq_use_ipset --> off
domain_can_mmap_files --> off
domain_can_write_kmsg --> off
domain_fd_use --> on
domain_kernel_load_modules --> on
entropyd_use_audio --> on
exim_can_connect_db --> off
exim_manage_user_files --> off
exim_read_user_files --> off
fcron_crond --> off
fenced_can_network_connect --> off
fenced_can_ssh --> off
fips_mode --> on
ftpd_anon_write --> off
ftpd_connect_all_unreserved --> off
ftpd_connect_db --> off
ftpd_full_access --> off
ftpd_use_cifs --> off
ftpd_use_fusefs --> off
ftpd_use_nfs --> off
ftpd_use_passive_mode --> off
git_cgi_enable_homedirs --> off
git_cgi_use_cifs --> off
git_cgi_use_nfs --> off
git_session_bind_all_unreserved_ports --> off
git_session_users --> off
git_system_enable_homedirs --> off
git_system_use_cifs --> off
git_system_use_nfs --> off
gitosis_can_sendmail --> off
glance_api_can_network --> off
glance_use_execmem --> off
glance_use_fusefs --> off
global_ssp --> off
gluster_anon_write --> off
gluster_export_all_ro --> off
gluster_export_all_rw --> on
gluster_use_execmem --> off
gpg_web_anon_write --> off
gssd_read_tmp --> on
guest_exec_content --> on
haproxy_connect_any --> off
httpd_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off
httpd_can_connect_ldap --> off
httpd_can_connect_mythtv --> off
httpd_can_connect_zabbix --> off
httpd_can_manage_courier_spool --> off
httpd_can_network_connect --> off
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_memcache --> off
httpd_can_network_redis --> off
httpd_can_network_relay --> off
httpd_can_sendmail --> off
httpd_dbus_avahi --> off
httpd_dbus_sssd --> off
httpd_dontaudit_search_dirs --> off
httpd_enable_cgi --> on
httpd_enable_ftp_server --> off
httpd_enable_homedirs --> off
httpd_execmem --> off
httpd_graceful_shutdown --> off
httpd_manage_ipa --> off
httpd_mod_auth_ntlm_winbind --> off
httpd_mod_auth_pam --> off
httpd_read_user_content --> off
httpd_run_ipa --> off
httpd_run_preupgrade --> off
httpd_run_stickshift --> off
httpd_serve_cobbler_files --> off
httpd_setrlimit --> off
httpd_ssi_exec --> off
httpd_sys_script_anon_write --> off
httpd_tmp_exec --> off
httpd_tty_comm --> off
httpd_unified --> off
httpd_use_cifs --> off
httpd_use_fusefs --> off
httpd_use_gpg --> off
httpd_use_nfs --> off
httpd_use_opencryptoki --> off
httpd_use_openstack --> off
httpd_use_sasl --> off
httpd_verify_dns --> off
icecast_use_any_tcp_ports --> off
init_audit_control --> on
init_create_dirs --> on
irc_use_any_tcp_ports --> off
irssi_use_full_network --> off
kdumpgui_run_bootloader --> off
keepalived_connect_any --> off
kerberos_enabled --> on
ksmtuned_use_cifs --> off
ksmtuned_use_nfs --> off
logadm_exec_content --> on
logging_syslogd_append_public_content --> off
logging_syslogd_can_sendmail --> off
logging_syslogd_list_non_security_dirs --> off
logging_syslogd_run_nagios_plugins --> off
logging_syslogd_run_unconfined --> off
logging_syslogd_use_tty --> on
login_console_enabled --> on
logrotate_read_inside_containers --> off
logrotate_use_cifs --> off
logrotate_use_fusefs --> off
logrotate_use_nfs --> off
logwatch_can_network_connect_mail --> off
lsmd_plugin_connect_any --> off
mailman_use_fusefs --> off
mcelog_client --> off
mcelog_exec_scripts --> on
mcelog_foreground --> off
mcelog_server --> off
minidlna_read_generic_user_content --> off
mmap_low_allowed --> off
mock_enable_homedirs --> off
mount_anyfile --> on
mozilla_plugin_bind_unreserved_ports --> off
mozilla_plugin_can_network_connect --> on
mozilla_plugin_use_bluejeans --> off
mozilla_plugin_use_gps --> off
mozilla_plugin_use_spice --> off
mozilla_read_content --> off
mpd_enable_homedirs --> off
mpd_use_cifs --> off
mpd_use_nfs --> off
mplayer_execstack --> off
mysql_connect_any --> off
mysql_connect_http --> off
nagios_run_pnp4nagios --> off
nagios_run_sudo --> off
nagios_use_nfs --> off
named_tcp_bind_http_port --> off
named_write_master_zones --> on
neutron_can_network --> off
nfs_export_all_ro --> on
nfs_export_all_rw --> on
nfsd_anon_write --> off
nis_enabled --> off
nscd_use_shm --> on
openfortivpn_can_network_connect --> on
openshift_use_nfs --> off
openvpn_can_network_connect --> on
openvpn_enable_homedirs --> on
openvpn_run_unconfined --> off
pcp_bind_all_unreserved_ports --> off
pcp_read_generic_logs --> off
pdns_can_network_connect_db --> off
piranha_lvs_can_network_connect --> off
polipo_connect_all_unreserved --> off
polipo_session_bind_all_unreserved_ports --> off
polipo_session_users --> off
polipo_use_cifs --> off
polipo_use_nfs --> off
polyinstantiation_enabled --> off
postfix_local_write_mail_spool --> on
postgresql_can_rsync --> off
postgresql_selinux_transmit_client_label --> off
postgresql_selinux_unconfined_dbadm --> on
postgresql_selinux_users_ddl --> on
pppd_can_insmod --> off
pppd_for_user --> off
privoxy_connect_any --> on
prosody_bind_http_port --> off
puppetagent_manage_all_files --> off
puppetmaster_use_db --> off
racoon_read_shadow --> off
radius_use_jit --> off
redis_enable_notify --> off
rngd_execmem --> off
rpcd_use_fusefs --> off
rsync_anon_write --> off
rsync_client --> off
rsync_export_all_ro --> off
rsync_full_access --> off
rsync_sys_admin --> off
samba_create_home_dirs --> off
samba_domain_controller --> off
samba_enable_home_dirs --> off
samba_export_all_ro --> off
samba_export_all_rw --> off
samba_load_libgfapi --> off
samba_portmapper --> off
samba_run_unconfined --> off
samba_share_fusefs --> off
samba_share_nfs --> off
sanlock_enable_home_dirs --> off
sanlock_use_fusefs --> off
sanlock_use_nfs --> off
sanlock_use_samba --> off
saslauthd_read_shadow --> off
screen_allow_session_sharing --> off
secadm_exec_content --> on
secure_mode --> off
secure_mode_insmod --> off
secure_mode_policyload --> off
selinuxuser_direct_dri_enabled --> on
selinuxuser_execheap --> off
selinuxuser_execmod --> on
selinuxuser_execstack --> on
selinuxuser_mysql_connect_enabled --> off
selinuxuser_ping --> on
selinuxuser_postgresql_connect_enabled --> off
selinuxuser_rw_noexattrfile --> on
selinuxuser_share_music --> off
selinuxuser_tcp_server --> off
selinuxuser_udp_server --> off
selinuxuser_use_ssh_chroot --> off
sge_domain_can_network_connect --> off
sge_use_nfs --> off
smartmon_3ware --> off
smbd_anon_write --> off
spamassassin_can_network --> off
spamd_enable_home_dirs --> on
spamd_update_can_network --> off
squid_bind_snmp_port --> off
squid_connect_any --> on
squid_use_tproxy --> off
ssh_chroot_rw_homedirs --> off
ssh_keysign --> off
ssh_sysadm_login --> off
ssh_use_tcpd --> off
sslh_can_bind_any_port --> off
sslh_can_connect_any_port --> off
sssd_access_kernel_keys --> off
sssd_connect_all_unreserved_ports --> off
sssd_use_usb --> off
staff_exec_content --> on
staff_use_svirt --> off
swift_can_network --> off
sysadm_exec_content --> on
systemd_socket_proxyd_bind_any --> off
systemd_socket_proxyd_connect_any --> off
telepathy_connect_all_ports --> off
telepathy_tcp_connect_generic_network_ports --> on
tftp_anon_write --> off
tftp_home_dir --> off
tmpreaper_use_cifs --> off
tmpreaper_use_nfs --> off
tmpreaper_use_samba --> off
tomcat_can_network_connect_db --> off
tomcat_read_rpm_db --> off
tomcat_use_execmem --> off
tor_bind_all_unreserved_ports --> off
tor_can_network_relay --> off
tor_can_onion_services --> off
unconfined_chrome_sandbox_transition --> on
unconfined_dyntrans_all --> off
unconfined_login --> on
unconfined_mozilla_plugin_transition --> on
unprivuser_use_svirt --> off
use_ecryptfs_home_dirs --> off
use_fusefs_home_dirs --> off
use_lpd_server --> off
use_nfs_home_dirs --> off
use_samba_home_dirs --> off
use_virtualbox --> on
user_exec_content --> on
varnishd_connect_any --> off
virt_hooks_unconfined --> off
virt_lockd_blk_devs --> off
virt_qemu_ga_manage_ssh --> off
virt_qemu_ga_read_nonsecurity_files --> off
virt_qemu_ga_run_unconfined --> off
virt_read_qemu_ga_data --> off
virt_rw_qemu_ga_data --> off
virt_sandbox_share_apache_content --> off
virt_sandbox_use_all_caps --> on
virt_sandbox_use_audit --> on
virt_sandbox_use_fusefs --> off
virt_sandbox_use_mknod --> off
virt_sandbox_use_netlink --> off
virt_sandbox_use_sys_admin --> off
virt_transition_userdomain --> off
virt_use_comm --> off
virt_use_execmem --> off
virt_use_fusefs --> off
virt_use_glusterd --> off
virt_use_nfs --> off
virt_use_pcscd --> off
virt_use_rawip --> off
virt_use_samba --> off
virt_use_sanlock --> off
virt_use_usb --> on
virt_use_xserver --> off
virtqemud_use_execmem --> on
webadm_manage_user_files --> off
webadm_read_user_files --> off
wine_mmap_zero_ignore --> off
xdm_bind_vnc_tcp_port --> off
xdm_exec_bootloader --> off
xdm_manage_bootloader --> on
xdm_sysadm_login --> off
xdm_write_home --> off
xen_use_nfs --> off
xend_run_blktap --> on
xend_run_qemu --> on
xguest_connect_network --> on
xguest_exec_content --> on
xguest_mount_media --> on
xguest_use_bluetooth --> on
xserver_clients_write_xshm --> off
xserver_execmem --> off
xserver_object_manager --> off
zabbix_can_network --> off
zabbix_run_sudo --> off
zarafa_setrlimit --> off
zebra_write_config --> off
zoneminder_anon_write --> off
zoneminder_run_sudo --> off
```
</details>

- togglesebool

`togglesebool`コマンドは、指定したブール値の設定を切り替えます。設定値はメモリにのみ影響するため、OS再起動後は維持されません。

`# togglesebool <boolean...>`

- fixfiles
`fixfiles`コマンドは、ファイルシステム上のファイルやディレクトリに対して、SELinuxポリシーに基づき正しいセキュリティコンテキスト（拡張属性）を適用するためのコマンドです。

| ARGUMENTS | 説明 |
|:-|:-|
| check | 間違ったファイルコンテキストラベルを出力（古いコンテキストと新しいコンテキストを表示するが、変更は行わない）|
| restore | 不正なファイルコンテキストラベルを変更 |
| relabel  | `/etc/selinux/fixfiles_exclude_dirs`にリストされているパスを除いて、ファイルシステム全体のラベルを変更 |

- restorecon
`restorecon`コマンドは、1つのファイルまたは複数のファイルに対して、SELinuxポリシーに基づき正しいセキュリティコンテキスト（拡張属性）を適用するためのコマンドです。setfilesと同じ実行ファイルですが、引数の取り扱いや動作の違いで使い分けられています。

以下の例では、`/var/www/`ディレクトリとその中にあるすべてのサブディレクトリやファイルに対して、SELinux のポリシーに基づいた正しいラベルを再適用します。また、どのファイルに対してどんな変更が行われたかが詳細に表示されます。

`# restorecon -rv /var/www/`

- setfiles
`setfiles`コマンドは、1つのファイルまたは複数のファイルシステム（またはそれらの一部）のセキュリティコンテキスト（拡張属性）を初期化するために使用されます。通常、このプログラムはSELinuxインストールプロセス（一般にラベリングと呼ばれる手順）の一環として最初に実行されます。

以下の例では、SELinuxのターゲットポリシーファイルに定義されたセキュリティコンテキストの情報をもとに、`/var/www/`ディレクトリ以下のすべてのサブディレクトリやファイルに対して、正しいラベルを再適用します。また、どのファイルに対してどんな変更が行われたかが詳細に表示されます。

`# setfiles -v /etc/selinux/targeted/contexts/files/file_contexts /var/www/`

- seinfo
`seinfo`コマンドは、現在のシステムで実行されているポリシーを検索します。ポリシーが見つからない場合、seinfoはエラーメッセージを出力して終了します。

以下の例では、実行されているポリシーのバージョンは33であることが確認できます。

`# seinfo`

```
Statistics for policy file: /sys/fs/selinux/policy
Policy Version:             33 (MLS enabled)
Target Policy:              selinux
Handle unknown classes:     allow
  Classes:             134    Permissions:         460
  Sensitivities:         1    Categories:         1024
  Types:              5225    Attributes:          258
  Users:                 8    Roles:                14
  Booleans:            355    Cond. Expr.:         385
  Allow:             66080    Neverallow:            0
  Auditallow:          174    Dontaudit:          8633
  Type_trans:       268300    Type_change:          87
  Type_member:          35    Range_trans:        6161
  Role allow:           37    Role_trans:          418
  Constraints:          70    Validatetrans:         0
  MLS Constrain:        72    MLS Val. Tran:         0
  Permissives:           8    Polcap:                6
  Defaults:              7    Typebounds:            0
  Allowxperm:            0    Neverallowxperm:       0
  Auditallowxperm:       0    Dontauditxperm:        0
  Ibendportcon:          0    Ibpkeycon:             0
  Initial SIDs:         27    Fs_use:               35
  Genfscon:            110    Portcon:             665
  Netifcon:              0    Nodecon:               0
  ```

なお、RHEL系のOS（RHEL7以降）では、Pythonのモジュールを用いてSELinuxポリシーを操作及び解析する手段が提供されています。

```
>>> import sepolicy
>>> sepolicy.info(sepolicy.ATTRIBUTE)
<generator object info.<locals>.<genexpr> at 0xffff900af940>
>>> sepolicy.info(sepolicy.TYPE) 
<generator object info.<locals>.<genexpr> at 0xffff9020b450>
>>> sepolicy.info(sepolicy.BOOLEAN)  
<generator object info.<locals>.<genexpr> at 0xffff9022bb90>
```

`sepolicy.info()`の出力はgenerator objectになっているため、list()やfor文などで展開すると、文字列で出力します。

::: note
seinfoは、SELinuxの設定を分析するためのツールとして開発されている[setools](https://github.com/SELinuxProject/setools)に含まれています。
:::

- newrole
`newrole`コマンドは、指定したタイプやロールで新しいシェルを実行します。なお、RHEL系の場合、デフォルトでインストールされません。

以下の例では、`sysadm_r`ロールに変更してシェルを起動しています。

`# newrole -r sysadm_r`

- runcon
`runcon`コマンドは、指定したセキュリティコンテキストでコマンドを実行します。

以下の例では、Webサーバ用のコンテキストでスクリプトを実行します。

`# runcon system_u:system_r:httpd_t:s0 ./script.sh`

- chcon
`chcon`コマンドは、ファイルのセキュリティコンテキストを変更します。

以下の例では、`<Pass>`以下のすべてのファイルに対するラベルを設定しています。

`# chcon -R -t httpd_sys_content_t <Pass>`

- semanage
`semanage`は、ポリシーソースの変更や再コンパイルを必要とせずに、SELinuxポリシーの設定変更を行うコマンドです。

以下の例では、恒久的にファイルシステムのラベルを変更しています。

`# semanage fcontext -a -t httpd_sys_content_t <Pass>`
`# restorecon -Rv <Pass>`

### file_contextsの確認方法
file_contextsを確認する方法について以下に記載します。

- semanage fcontext -l
`semanage fcontext -l`を実行することで、パスのパターンと対応するラベルについて確認できます。

```
SELinux fcontext                                   タイプ                コンテキスト

/                                                  directory          system_u:object_r:root_t:s0 
/.*                                                all files          system_u:object_r:default_t:s0 
/[^/]+                                             regular file       system_u:object_r:etc_runtime_t:s0 
/\.autofsck                                        regular file       system_u:object_r:etc_runtime_t:s0 
/\.autorelabel                                     regular file       system_u:object_r:etc_runtime_t:s0 
/\.ismount-test-file                               regular file       system_u:object_r:sosreport_tmp_t:s0 
/\.journal                                         all files          <<None>>
/\.snapshots(/.*)?                                 all files          system_u:object_r:snapperd_data_t:s0 

＜以下略＞
```

- matchpathcon 
`matchpathcon`はシステムポリシーを照会し、ファイルパスに関連付けられたデフォルトのセキュリティコンテキストを出力します。

`# matchpathcon /etc/httpd/conf/httpd.conf`

```
/etc/httpd/conf/httpd.conf	system_u:object_r:httpd_config_t:s0
```

::: note
ファイルパスに本来どんなラベルが付与されるのかについて確認できるため、`ls -Z`コマンドと比較すれば、ラベルの差異を確認できます。
:::

- file_contextsファイルを参照

ファイルの中身は見づらいですが、file_contextsファイルを参照することでも確認できます。

`# cat /etc/selinux/targeted/contexts/files/file_contexts`

```
/.*	system_u:object_r:default_t:s0
/[^/]+	--	system_u:object_r:etc_runtime_t:s0
/a?quota\.(user|group)	--	system_u:object_r:quota_db_t:s0
/efi(/.*)?	system_u:object_r:boot_t:s0
/nsr(/.*)?	system_u:object_r:var_t:s0
/sys(/.*)?	system_u:object_r:sysfs_t:s0
/xen(/.*)?	system_u:object_r:xen_image_t:s0
/mnt(/[^/]*)?	-d	system_u:object_r:mnt_t:s0
/mnt(/[^/]*)?	-l	system_u:object_r:mnt_t:s0
/bin/.*	system_u:object_r:bin_t:s0

＜以下略＞
```

# おわりに
SELinuxはその複雑さから敬遠されることが多い機能ですが、仕組みをしっかり理解し、適切に運用することで、非常に強力なセキュリティ対策となります。

本記事がSELinuxを導入するための一助になれば幸いです。

## 参考
- [Administering SELinux](https://docs.oracle.com/en/operating-systems/oracle-linux/selinux/)
- [SELinux](https://wiki.archlinux.jp/index.php/SELinux)
- [SELinux/EnforcePolicy](https://fedoraproject.org/wiki/SELinux/EnforcePolicy)
- [SELinux の使用](https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/9/html/using_selinux/index)