SELinuxシリーズ
本記事は、SELinuxシリーズの3記事目です。
- Linuxプロセスアクセス制御の概要
- SELinuxの概要
- SELinux Type Enforcement ←今ココ
- SELinuxの実践
- (参考) SELinuxのRBAC、UBAC、MLS、MCS
- (参考) SELinux Module Policyのソースコード読解、ビルド
- 参考URL
1〜3記事目は、4記事目を理解するための前提知識をカバーしています。
4記事目が最も重要で、SELinuxの具体的な操作方法やコマンド、トラブルシューティング手順を紹介しています。
5記事目以降は参考情報です。
SELinuxの関連記事は、SELinuxタグから探せます。
一連の記事はFedora環境を前提として書いています。
FedoraやRHELに類するディストリビューションであればほぼ同等の挙動になると思いますが、他のディストリビューションでは挙動に差異がある可能性があるのでご注意ください。
お伝えしたいこと
本記事では、SELinuxのアクセス制御において必ず必要となるType Enforcementの理論を説明します。
SELinuxの運用で使う具体的なコマンドやテクニックについては、次の記事であるSELinuxの実践にて紹介します。
SELinuxで実装可能なアクセス制御は、以下のとおり複数存在します。
- TE (Type Enforcement)
- RBAC (Role-Based Access Control)
- UBAC (User-Based Access Control)
- MCS (Multi-Category Security)
- MLS (Multi-Level Security)
SELinuxのデフォルト構成 (targeted policy) においては、TEとMCS以外のアクセス制御は実質的に全て無効化されています。
また、MCSを利用するアプリケーションもごく一部のみです (※)。
したがって、ほとんどの場合はTEのみ覚えれば十分です。
(※) MCSを使っているのは、主にKVMやコンテナ技術などの仮想化周りです
本記事においてもRBAC、UBAC、MCS、MLSについては概要レベルで軽く触れますが、後半からはTEのみにフォーカスして詳しく説明します。
- SELinuxシリーズ
- お伝えしたいこと
- SELINUXTYPE (policy)
- TE (Type Enforcement)
- Security Contextの確認
- Security Contextの決まり方
- Type Transition
- (参考) Typeの意味の見分け方
- File Contextとrelabel
- Boolean
- (参考) アクセス制御ルールはどこに書いてあるのか
- まとめ
- 次の記事
SELINUXTYPE (policy)
SELINUXTYPE (policy) とは
SELinuxの設定ファイルが/etc/selinux/config
にありますが、ここでSELinuxの大まかな設定を変えることができます。
その設定項目の一つがSELINUXTYPEです。
SELINUXTYPEは、単にpolicyと呼ばれることもあります (※)。1,2
(※) アクセス制御ルールの定義ファイルであるSecurity Policyと、SELINUXTYPEを表すpolicyは似て非なる言葉なので、混同しないようご注意ください。
SELINUXTYPEが変わることで具体的に何が起こるかというと、読み込まれるSecurity Policyファイルそのものが変わります。
Security Policyのファイルパスは、以下のとおりです。
/etc/selinux/SELINUXTYPE/policy/policy.NN
つまりSELINUXTYPEが変わると、SELinuxのアクセス制御ルールが全く異なる内容に変化します。
SELINUXTYPEは、以下の3種類のいずれかです3。
セキュリティは、minimum < targeted < mls
の順に強くなります。
デフォルトはtargetedで、基本的に変更することはありません。
これより先では、特に明記しない限りtargeted policyを前提として説明します。
policy | 詳細 |
---|---|
minimum |
|
targeted |
|
mls |
SELINUXTYPEの確認方法
SELINUXTYPEは、OS起動時に読み込まれる/etc/selinux/config
で設定します。
/etc/selinux/config
の一部を以下に抜粋します。
# 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
実際のステータス値としてのSELINUXTYPEは、sestatus
で確認できます。
以下の出力は、targetedとして動作しているときのものです。
sestatus # 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
minimum, targeted, mlsの違い
3つのpolicyの違いを下表にまとめました。
- ×:デフォルトは実質無効
- △:デフォルトは一部有効
- ◯:デフォルトで有効
基本はデフォルト値のtargeted policyを使います。
targeted policyはMCSとTEがありますが、基本的にはTEのみ意識すれば十分です。
上表で「×」でマークされた機能が実質無効である根拠については、後続記事の(参考) SELinuxのRBAC、UBAC、MLS、MCSで説明します。
本記事については、上表が正しい前提で話を進めます。
(参考) TEの概要
TE (Type Enforcement)とは、SubjectとObject割り当てられたTypeと呼ばれる識別子に基づき、アクセス可否を制御するSELinuxの最も基本的なアクセス制御実装です。
今の時点では、「SELinuxのアクセス制御は基本的にTEで実装されており、他のアクセス制御は別の観点を追加することでセキュリティを高めている」と理解ください。
TEについて、詳細は#TE (Type Enforcement)以降のセクションで説明します。
(参考) MCSの概要
MCSは、プロセスやリソースをCategoryに分けてアクセス制御を行う技術です4。
CategoryはTypeとは独立して定義されます。
MCSは、TEでは同じTypeが割り当てられる関係のプロセスに対して、異なるCategoryを割り当ててより細かくアクセス制御します。
例えばコンテナを複数起動した場合、各コンテナプロセスには同じType、異なるCategoryが割り当てられます5。
これによって、MCSはTEよりも細かくコンテナ関連のアクセス制御を実装できます。
MCSを使っている主な技術は、以下のとおりです6。
- OpenShift
- virt (sVirt)
- sandbox
- network labeling
- containers (container-selinux)
上記から、コンテナやKVMなどの仮想化技術を使っているのでない限りは、MCSを意識する必要はほぼありません。
sVirtの場合、MCSのCategory割り当てのロジックは、SELinuxではなくアプリケーション側に実装されているようです。
Categoryの割り当ては基本的にsVirtの機能で自動的に行われますが、ユーザーが手動で設定することもできるようです7。
(参考) RBAC、UBAC、MLSの概要
RBAC、UBAC、MLSもMCSと同様、TEが利用するTypeとは別の識別子に基づいてアクセス制御する技術です。
いずれもデフォルトのtargeted policyでは実質無効化されているため、ここでは扱いません。
これらの用語に関する説明は、後続記事の(参考) SELinuxのRBAC、UBAC、MLS、MCSを参照してください。
(参考) targeted policyの概要
#TE (Type Enforcement)以降のセクション、及び後続記事では、targeted policyを前提に説明を進めます。
この後の説明を読んでいく中で、targeted policyの動きについては自然と理解が深まるはずです。
現時点では、targeted policyについて以下の認識を持っていただければ十分です。
(参考) mls policyの概要
mls policyは、TE、MCS、RBAC、UBAC、MLSの全てが有効化で、最もセキュリティの高い構成です。
一部の企業では使用されていますが、targeted policyでもある程度の効果が得られる点、mls policyの運用の難易度の高さからあまり使われていない印象です。
RHEL8のマニュアルでも、利用する団体の例として「軍隊」が挙げられているほどです8。
以降は、mls policyがどのように難しいのかを説明します。
まず、MLSが最小限のデフォルトの設定しかなく、自身でカスタマイズする前提の機能であることが難しさのポイントとして挙げられます。
MLSは、プロセスやファイルなどのリソースにSensitivity Levelを割り当て、セキュリティ強度の上下関係によってアクセス制御する技術です。
デフォルトで最低レベルのs0から最高レベルのs15までLevel自体は作成されますが、後はユーザー自身の手で以下のような設計・実装を行う必要があります。
- 各種リソースをどのようなLevelをつけるか 9
- Levelの違いによるアクセス許可/拒否の条件をどのように定義するか (※)
(※) デフォルトでも最低限の基本ルールはあります
他にも以下の点で、mls policyは難しいと思います。
- RBACの権限設計の難易度が高い
- RBAC前提の運用フローや手順の設計が大変
- そもそもmls policyを運用している人が少ないので情報が見つかりにくい
- mls policyは、targeted policyとは異なりデフォルトで大量のアクセス拒否エラーが出る (※)
(※) RBACの設定起因だと思うのですが、私の実体験としてログイン直後の~/.bash_profile
の読み込みがPermission Deniedになりました。他にも大量のエラーが数秒おきに発生しました
mls policyが必要な明確な要件がある場合は別ですが、多くの場合はmls policyを使いません。
targeted policyを使います。
(参考) minimum policyの概要
※このセクションでは、まだ説明していない用語を使用します。Base PolicyとModule Policyについては、後続記事の(参考) SELinux Module Policyのソースコード読解、ビルド - Base PolicyとModule Policyにて説明します。Type Transitionについては、後続セクションの#Type Transitionで説明します。
minimum policyは、Base Policy以外は何もインストールされていないモードです10。
httpdなどの代表的なミドルウェアに対するSELinuxのルールは、ほぼ定義されていません。
Linux Kernelやsyslogdなど一部の基本機能のみがアクセス制御対象となり、他のプロセスにはデフォルトのTypeが割り当てられます。
具体的には、ユーザー自身が手動で起動したプロセスには、多くの場合unconfined_t
(unconfined = 制限されない) Typeがアサインされてアクセス許可されます。
これはtargeted policyと同様です。
systemdによって自動起動されるようなプロセスの大半は、Type Transitionが働かず親プロセスのsystemdと同じinit_t
が割り当てられ、アクセスに失敗するケースが多いです。
なお、minimum policyでModule Policyを一覧表示しようとするとエラーになります。
この出力からも、ほぼBase Policyしか有効化されていないのだと理解できます。
sudo semodule -l # No modules.
minimum policyの主なユースケースは、SELinuxの開発者が最低限のModule Policyのみ有効化した構成で単体試験するときです。
我々ユーザーがminimum policyを利用することは基本ありません。
なぜなら、targeted policyやmls policyで初期インストールされたModule Policyを後からアンインストールすることはできません。
やるとしたら、私達が独自に開発したModule Policyを追加インストールするのみです。
したがって、仮に独自開発したModule Policyの動作確認をしたい要件があったとしても、わざわざminimum policyで最小構成にする必要がないのです。
私達がminimum policyを使うことはまずありません。
使うとしたらtargeted policyか、mls policyです。
(参考) SELINUXTYPEの変更方法
後続記事のSELinuxのRBAC、UBAC、MLS、MCS - (参考) mls policyに変更する方法にて手順を紹介しています。
mls policyに変更する手順を扱っていますが、他のpolicyについても同様です。
TE (Type Enforcement)
TE (Type Enforcement) は、SubjectとObjectに対してTypeと呼ばれる識別子を割り当て、Typeに基づいてアクセス可否を制御するSELinuxの最も基本的なアクセス制御実装です。
特にデフォルトのtargeted policyにおいては、TEとMCSしか使われません。
そしてMCSは一部のアプリケーションでしか使われません。
つまり、SELinuxのアクセス制御はほぼTEのみで実装されています。
TEでは、以下のようなルールを実装します。
関連するキーワードをカッコ付きで付記していますが、これらの用語については後続のセクションで説明します。
- Typeの定義 (Type, Attribute)
- Typeの割り当て方に関する規則 (Type Transition, File Context)
- Typeに基づくアクセス許可ルール (allow Statement)
一番重要なのは、最後のallow Statementです。
allow Statementが、SubjectのTypeとObjectのTypeの組み合わせに対し、許可されたActionを紐付けて定義します。
そして、allow Statementで明示的に許可されなかったアクセスパターンは、暗黙的に全て拒否されます。
この後のセクションで、TEによるアクセス制御ルールがどのように定義されているのか、順を追って紹介します。
allow Statement
allow Statementは、SELinuxが許可するアクセスを定義します。
ここで許可されなかったアクセスは、全てデフォルトで拒否されます。
setools-console
パッケージがインストールされていれば、sesearch -A
で表示できます。
デフォルトのallow Statementを一部抜粋します。
このアクセス許可ルールでは、sshdプロセス (Subject) がfile_typeに属するディレクトリ群 (Object) に対してgetattr, open, search権限を許可しています。
allow sshd_t file_type:dir { getattr open search };
allow Statementの構文は、以下のとおりです11。
ACLのように、source, target を並べて書きます。
(※) source, target, type, class, permissionなどの用語は、この後順を追って説明します。
allow source_type target_type : class perm_set;
type, class, perm_setを複数並べたいときは、{}
で囲ってスペース区切りで列挙します。
今回は、perm_set
が{ getattr open search }
と複数指定されています。
なお、SELinuxにはdeny Statementは存在しません。
既に許可されたアクセスパターンは、後から拒否することはできません。
そして、許可されなかったアクセスパターンがデフォルトで拒否されます12。
今回のルールについては、以下のような対応関係になっています。
Syntax | Syntaxの意味 | 今回の値 |
---|---|---|
source_type | SubjectのType | sshd_t |
target_type | ObjectのType (※) | file_type |
class | Object Class | dir |
perm_set | 許可するAction | getattr open search |
(※) target_typeにselfというキーワードが指定された場合、「source_typeと同じ」という意味になります
少しややこしいですが、allow StatementのSyntaxでは言葉遣いが若干変わります。
以下の言葉は同じ意味を持ちます。
- Source = Subject
- Target = Object
- Class = Object Class
- Permissions = Actions
更に新しい用語としてTypeとObject Classが出てきました。
この後のセクションで、関連用語も含めつつ順に説明していきます。
- Security Context (Label)
- Type
- Attribute
- Object Class
- Common
Security Context (Label)
Typeの説明をするために、まずはSecurity Contextという概念について紹介します。
Security Contextとは、SELinuxが有効な場合に全てのSubjectとObjectに割り当てられる識別子 (文字列) です13。
SubjectとObjectとはすなわち、全てのプロセス、ファイル、ネットワークソケット、ファイルシステム、データベース、ユーザーなど、SELinuxのアクセス制御に関わる全てのリソースです。
Security Contextは、Labelとも呼ばれます。
プロセスにSecurity Contextを割り当てることをLabeling (ラベル付け) と表現することもあります。
Security Contextのフォーマットを以下に示します。
Security Contextは、コロンで区切られた文字列で表現されます。
user:role:type[:range]
各要素の意味は、以下のとおりです。
要素名 | 意味 |
---|---|
user | |
role |
|
type |
|
range |
|
※Sensitivity Levelは、Security Levelや、単にLevelと表記されることもあります
上述の要素の中で重要なのは、typeのみです。
他の要素は無視して結構です。
なぜなら、targeted policyでは基本的にTEしか使われず、TEで使うのは基本Typeのみであるためです。
RBAC/UBAC、MLS/MCSを使う場合のみ、Type以外の要素が重要になります。
例えば、sshdプロセスのSecurity Contextは、以下のように表されます。
Security Contextは非常に長いですが、この中で重要な情報はsshd_t
のみです。
ps -o label,uid,command -C sshd # LABEL USER COMMAND # system_u:system_r:sshd_t:s0-s0:c0.c1023 root sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
SELinuxでアクセス制御を実装する際、プロセス名やファイル名を直接指定するのではなく、Security ContextやObject Classを指定してルールを定義します。
例えば今回取り上げた#allow Statementでは、プロセスやファイルが持つTypeを指定して許可設定を記載していました。
冒頭のallow Statementを再掲します。
allow sshd_t file_type:dir { getattr open search };
Type
Typeは、前述のSecurity Contextの3番目の要素です。
Typeの定義は、setools-console
パッケージが入っていればseinfo
コマンドで確認できます。
-x
をつけるとより詳細な情報がわかります。
今回はsshd_t
に絞って出力していますが、Type名を指定しなければ全て表示されます。
seinfo -t sshd_t # Types: 1 # sshd_t seinfo -xt sshd_t # Types: 1 # type sshd_t, polydomain, nsswitch_domain, login_pgm, can_change_object_identity, can_change_process_identity, can_change_process_role, corenet_unlabeled_type, domain, kernel_system_state_reader, netlabel_peer_type, privfd, daemon, syslog_client_type, pcmcia_typeattr_1, ssh_server, unconfined_login_domain, userdom_home_manager_type;
この後もseinfo
は何度か出てきますが、以降のセクションでは-x
ありの出力のみ掲載します。
-x
なしの出力は、シンプルに一覧表示するときには便利ですが、先の実行例のように出力を絞っている場合には掲載する意味がないためです。
Type名は以下の命名規則で定義するのが通例です。
_t
で終わる- プロセスのTypeは、
プロセス名_t
- プロセスを起動するための実行ファイルのTypeは、
プロセス名_exec_t
- ログファイルは、
プロセス名_log_t
- ポート番号は、
プロトコル名_port_t
Attribute
上述のseinfo -xt sshd_t
の出力において、type sshd_t
の右に並んでいるのはAttributeと呼ばれるものです。14,15,16
Attributeは、Typeの集合体です。
単一のAttributeに1つ、または複数のTypeを紐付けて定義します。
定義したAttributeは、Typeと同様に扱うことができます。
なお、AttributeにはTypeのような命名規則はありません。
Attributeの定義は以下のコマンドで確認できます。
seinfo -xa
は、AttributeとTypeの紐付けを「Attributeごとに」表示します。
紐付けを「Typeごとに」表示するseinfo -xt
と情報量は同じですが、表示方法が異なります。
seinfo -xa unconfined_login_domain # Type Attributes: 1 # attribute unconfined_login_domain; # chroot_user_t # crond_t # local_login_t # remote_login_t # rshd_t # sshd_t # sulogin_t
allow StatementにAttributeを指定することで、複数Typeを含むアクセス許可ルールを少ない文字数で表現できます。
例えば上述のunconfined_login_domain
をsource_typeに指定すると、{ chroot_user_t crond_t local_login_t remote_login_t rshd_t sshd_t sulogin_t }
を指定したのと同じ意味になります。
そして、後から別のTypeをunconfined_login_domain
に追加すると、そのTypeも既存のallow Statementによるアクセス許可の対象に含まれます。
Object Class (OC)
Object Classは、Objectを用途によってざっくり分類する概念です17。
単にclassと呼ばれることもあります。
Object Classは、(定義上) TypeやAttributeとは紐付きません18。
ニュアンスとしてはObject ClassとType/Attributeに関連性があると意識しても良いのですが、ソースコード的にはそのように書かれていません。
Object Classは、Permissionsと紐付きます。
試しにObject Classの定義を一部見てみましょう。
seinfo -xc dir # Classes: 1 # class dir # inherits file # { # add_name # reparent # search # rmdir # remove_name # }
上記の出力から、dir (ディレクトリ) というObject Classは、add_name
, reparent
, search
, rmdir
, remove_name
というPermissionsと紐付いていることがわかります。
また、定義の中にinherits file
という文字列がありますが、これも重要です。
ここで出てくるfile
は、Commonと呼ばれるものです。
Commonについては、次のセクションで説明します。
Common
CommonもActionと紐づく概念です。19, 20
Commonがallow Statementで直接指定されることはありません。
CommonはObject ClassのinheritキーワードによってActionを継承させることで、間接的に作用します。
Commonは複数のObject Classと紐づくことで、Object Classの定義を簡潔に表現するのに使われます。
以下のコマンドで、file Commonの定義を確認しましょう。
seinfo -x --common file # Commons: 1 # common file # { # watch_mount # watch_with_perm # ioctl # setattr # swapon # open # mounton # map # append # getattr # audit_access # watch_sb # create # unlink # write # lock # execmod # rename # relabelfrom # link # watch_reads # quotaon # execute # relabelto # watch # read # }
file Commonに定義された上記のPermissionsは、fileを継承するdir Classにも紐付けられます。
したがって、dir Object Classの定義上は5つのPermissionsしか定義されていませんでしたが、実際にはfile Commonと紐づく26のPermissionsも追加で扱えます。
ここで、冒頭のallow Statementを再掲します。
allow sshd_t file_type:dir { getattr open search };
Object Classとしてdirが指定された時点で、Object Classの定義上31通り (dir classの5通り + file commonの26通り) のPermissionsの実行に絞り込まれています。
更にallow Statementによって、sshd_tがfile_typeに対して実行できるActionは3つに絞り込まれた、ということになります。
最後に2点補足します。
(1)
Object ClassやCommonと紐づくPermissionsの意味は、以下のリンクで調べることができます。
同じPermission名でもCommonやObject Classによって意味が異なるので、該当箇所のPermissionsを確認するようにしてください。
例えば、同じgetattrでもdirとsocketでは若干意味が異なります。
The SELinux Notebook - Appendix A - Object Classes and Permissions
(2)
CommonとObject Classの一覧を確認すると、SELinuxがざっくり何をアクセス制御できるのかを俯瞰できて便利です。
seinfo --common # Commons: 7 # cap # cap2 # database # file # ipc # socket # x_device seinfo -c # (行数多いので一部のみ抜粋) # Classes: 134 # alg_socket # capability # capability2 # context # db_database # db_table # dbus # dir # fd # fifo_file # file # filesystem # icmp_socket # ipc # kernel_service # process # process2 # proxy # sock_file # socket # system # tcp_socket # tun_socket # udp_socket # unix_dgram_socket # unix_stream_socket # x_keyboard # x_pointer # x_server
Security Contextの確認
Security Contextの確認方法を下表に整理します。
多くの場合、-Z
オプションをつけることでSecurity Contextを表示できます。
特に重要なのはps -Z
、ls -Z
、seinfo --portcon
なので、この3つは確実に覚えてください。
確認対象 | コマンド |
---|---|
プロセス | ps -Z |
ファイル | ls -Z |
ユーザー (ログインシェルのプロセス) | id -Z |
ネットワークソケット | ss -Z seinfo --portcon |
Security Contextが割り当てられているリソースとして、他にもファイルシステムやデータベースなどあると思いますが、代表的なコマンドは上記のみです。
他のリソースのSecurity Contextを調べる方法もあるかもしれませんが、私が調べた範囲では見つかりませんでした。
以下に具体例を示します。
プロセスのLabel表示 (ps -Z)
まずは、プロセスの表示コマンドです。
-e
オプションにより、全ユーザーのプロセスを表示できます。
他にも-o
によって表示列を指定したり、-C
によって特定プロセスのみ表示することも可能です。
※grepやawkで頑張らなくても良いのです
ps -eZ # LABEL PID TTY TIME CMD # system_u:system_r:init_t:s0 1 ? 00:00:00 systemd # (以下略) ps -o label,user,cmd -C sshd # LABEL USER CMD # system_u:system_r:sshd_t:s0-s0:c0.c1023 root sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
ファイルのLabel表示 (ls -Z)
ファイルのLabel表示は、ls -Z
で行います。
ls -Z /etc/hosts # system_u:object_r:net_conf_t:s0 /etc/hosts
getfattr
やstat
でも確認できますが、ls -Z
があるのでほぼ使いません。
ちなみに、getfattr
は、ファイルシステムの拡張アトリビュート (Extended Attribute) を確認するコマンドです。
この出力から、ファイルのLabelは拡張アトリビュートとして保持されていることが読み取れます。
拡張アトリビュートについて詳細が気になる方は、man xattrをご覧ください。
# getfattr -n security.selinux /etc/hosts でも良い getfattr -m - -d /etc/hosts # getfattr: Removing leading '/' from absolute path names # # file: etc/hosts # security.selinux="system_u:object_r:net_conf_t:s0" stat /etc/hosts # File: /etc/hosts # Size: 158 Blocks: 8 IO Block: 4096 regular file # Device: fd00h/64768d Inode: 1048867 Links: 1 # Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) # Context: system_u:object_r:net_conf_t:s0 # Access: 2022-01-02 01:22:36.647398431 +0900 # Modify: 2021-07-16 17:35:49.000000000 +0900 # Change: 2021-11-24 15:36:03.671000000 +0900 # Birth: 2021-11-24 15:36:03.670000000 +0900
(参考) ユーザーのLabel表示 (id -Z)
ログインユーザーのLabelは、id -Z
で表示します。
より正確には、ログインシェルプロセスのLabelを表示します。
id -Z # unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
SELinuxが有効な環境では、単にid
を実行するだけでもSecurity Contextが表示されます。
しかしid -Z
の方が見やすいので、あまり使いません。
id
# uid=1000(endy) gid=1001(endy) groups=1001(endy),10(wheel),1000(shared) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
id -Z
で表示されるSecurity Contextは、ログインシェルのSecurity Contextと同じです。
つまり、id -Z
は以下のpsコマンドと同じ情報を表示しています。
ps -Z | grep bash | grep -v grep # unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 26530 pts/0 00:00:01 bash
targeted policyにおいては、id -Z
で表示されるのは基本unconfined_t
のみです。
どのユーザーでも結果は同じなので、このコマンドを叩く機会はそう多くないでしょう。
ネットワークソケットのLabel表示
ネットワークソケットのLabel表示には、ss -Z
を使います。
以下の実行例では、sedによって、先頭行と_t
を含む行のみ抽出しています。
_t
はTypeの一部であり、Security Contextを持つSocketのみを表示するために指定しています。
grepではなくsedを使っているのは、先頭行も抽出するためです。
grep -e 条件1 -e 条件2
のようにOR条件で抽出しても良いですが、sedの方が条件指定が簡単です (sedは1
行目を表示する条件式が1p
なので)。
ssコマンドはtcp, udpを含めて様々なタイプのソケットを表示するコマンドですが、ヒットしたのはu_str (Unix Stream) のみでした。
Unix Streamは、平たく言えばローカル通信用で、IPC (Inter-Process Communication) に使われるようです。
すなわち、ssコマンドではネットワーク外部通信用のソケット (tcp, udpなど) のSecurity Contextを表示しません。
割り当てられているのは、IPCに関わる一部のソケットのみでした。
そして、そのソケットもunconfined_t
を持つため、実質的にアクセス制御されていないことがわかります。
したがって、targeted policyにおいてはss -Z
というコマンドを覚える必要はありません。
ss -nZ | sed -ne 1p -e /_t/p # Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process # u_str ESTAB 0 0 * 20153 * 20914 users:(("systemd",pid=935,proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023,fd=20)) # u_str ESTAB 0 0 * 20869 * 20130 users:(("systemd",pid=935,proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023,fd=2),("systemd",pid=935,proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023,fd=1))
TCP/UDP用のソケットと紐づくSecurity Contextをステータス値として確認するコマンドはありませんでしたが、Typeとの紐付け設定はseinfo --portcon
で確認できます。
semanage port -a
によってローカルポリシーでポート番号のSecurity Contextを追加していたとしても、このコマンドでちゃんと表示されます。
seinfo --portconは、実運用でもよく使う重要なコマンドです。
seinfo --portcon # Portcon: 652 # portcon sctp 1-511 system_u:object_r:reserved_port_t:s0 # (以下略) # ポート番号の指定も可能 # seinfo --portcon 22 # Portcon: 4 # portcon sctp 1-511 system_u:object_r:reserved_port_t:s0 # portcon tcp 1-511 system_u:object_r:reserved_port_t:s0 # portcon tcp 22 system_u:object_r:ssh_port_t:s0 # portcon udp 1-511 system_u:object_r:reserved_port_t:s0
seinfo --portcon
と同等の情報を得られるコマンドとしてsudo semanage port -l
もありますが、root権限が必要なので使い勝手としてはあまりよくありません。
参照用途のみであれば、seinfo
に軍配が上がります。
semanage port -a
でポート番号をカスタマイズしている場合は、semanage port -lC
でカスタマイズ値のみ表示できるのが便利なぐらいです。
sudo semanage port -l | sed -ne 1p -e /ssh/p # SELinux Port Type Proto Port Number # ssh_port_t tcp 22
Security Contextの決まり方
Security Contextの決まり方は、以下のリンクに書いてあります。
The SELinux Notebook - Computing Security Contexts
本セクションでは、上記リンクで説明されている内容を整理し、噛み砕いてお伝えしたいなと思います。
対象は、targeted policyに関わるプロセスとファイルに絞ります。
プロセスとファイルのSecurity Contextの決まり方は、大きく分けて2種類あります。
1のSecurity Policyによる制御では、大まかに言うと以下の順序でSecurity Contextが決まります。
- 基本的には親要素のSecurity Contextを引き継ぐ
- 特殊なルールによって、親とは異なるSecurity Contextを持つ状況がある
- 親要素がない場合など、上記仕組みで決まらない場合には別途定められたデフォルト値に従う
2のlibselinux APIについてはアプリケーション側のソースコード上の実装となるので、Security Contextの決まり方はアプリケーションの作りに依存します。
私の経験では、今までこのようなアプリケーションを見たことはありません。
もしそういったアプリケーションを扱う機会が出てきたら意識しましょう。
本記事では、libselinux APIについては取り扱わないこととします。
では、次のセクションから具体的な内容に入っていきましょう。
プロセスのContext計算
プロセスのSecurity Contextは、以下の流れで決まります21。
libselinux APIが関わる部分はあまり意識しないで良い部分なので、文字をグレーにして目立たなくしています。
- プロセスがforkされた時、forkされた子プロセスは親プロセスのSecurity Contextを引き継ぐ
- プロセスがexecされた時、execされた子プロセスは以下のルールでSecurity Contextが変化する
- Transition Ruleの条件を満たす場合、そのルールに従って決まる (※1)
- libselinuxのsetexeccon(3)でSecurity Contextが変化する (※アプリ依存)
- Default Ruleが指定されている場合、そのルールに従ってデフォルト値がセットされる (※2)
- 上記挙動を上書きしてlibselinux APIのsetcon(3) でSecurity Contextが上書きされる。非推奨な実装 (※アプリ依存)
2点補足します。
- Default Ruleは、本記事で扱うtargeted policyでは実質意識不要です。詳細は#(参考) Default Ruleで補足します
- ファイル実行によってプロセスが生成する時、fork > execの順に行われます。したがって、上記の1と2の処理は一瞬の間に両方行われます。新規プロセスのSecurity Contextはfork時の親プロセスのものを最初に持ちますが、次の瞬間exec時に変化することがあるとご理解ください
重要な部分を抽出すると、以下のように理解すれば十分です。
- 親プロセスのSecurity Contextを引き継ぐ
- ただしType Transitionのルールに該当する場合、Security Contextが書き換わる
forkやexecという用語については、以下の記事を参考にしてください。
前提知識として、exec系のライブラリ関数はexecveというシステムコールと関係することを頭に入れた上でお読みいただけるとスムーズです。
残りのDefault Rule、Transition Ruleといった用語については、ファイルのContext計算のセクションの後でまとめて説明します。
ファイルのContext計算
ファイルのSecurity Contextは、以下の流れで決まります22。
Type以外の情報はあまり重要ではないので、グレーで目立たなくしてあります。
- Userは、ファイルを作成するプロセス (Subject) から引き継ぐ
- Roleは、role_transitionとdefault_roleの影響を受ける。これらのルールがない場合は、デフォルトでobject_rになる
- Typeは、type_transitionとdefault_typeの影響を受ける。これらのルールがない場合は、デフォルトで親ディレクトリと同じTypeになる
- range_transitionとdefault_rangeの影響を受ける。これらのルールがない場合は、デフォルトでファイルを作成したプロセスのlow/current levelになる
勘違いしやすいポイントについて補足しますが、ファイル作成時にはsudo semanage fcontext -l
で表示されるFile Contextの値は関係ありません。
ここで表示される値は、restorecon
コマンドを実行した時のrelabel処理時に、どのSecurity Contextを割り当てるか判断するために参照されます。
restorecon
以外にも、/.autorelabel
をつけてOS再起動したとき、fixfiles restore
やfixfiles relabel
コマンドを実行した時、restorecond
デーモンがファイル作成時に自動的にrelabelする際などが該当します。
relabelについては、後続の#File Contextとrelabelで説明します。
(参考) Default Rule
この機能をtargeted policyで使うことはありません。
興味のある方以外は、本セクションを丸ごとスキップしても結構です。
プロセスやファイルなどのリソースが生成するとき、プロセスは親プロセス、ファイルは上位ディレクトリのSecurity Contextを引き継ぐのが基本です。
Default Ruleは、このデフォルト挙動を若干変える効果を持ちます23。
Default Ruleが発動する条件は単純で、Objectが特定のObject Classだった場合に常に発動します。
default系のStatementには以下のバリエーションがあります。
それぞれuser, role, type, rangeのデフォルト値の決定方法を上書きするのに使われます。
- default_user
- default_role
- default_type
- default_range
この中で重要なのはdefault_typeのみです。
なぜなら、targeted policyにおいては (MCSと) TEのみ意識すれば良いためです。
その前提で、targeted policyで定義されているDefault Ruleを確認してみましょう。
seinfo --default # Default rules: 7 # default_range blk_file target low; # default_range chr_file target low; # default_range dir target low; # default_range fifo_file target low; # default_range file target low; # default_range lnk_file target low; # default_range sock_file target low;
上記出力を見ると、default_typeルールがないことがわかります。
さらに、我々ユーザーが新たにDefault Ruleを追加することはそもそも不可能です。
それは、Module Policyのソースコードにはdefault_typeを記述できないためです。
default_typeの仕様を確認すると、Module Policyの欄に "No" と書かれていることからも読み取れます。
default_typeを変更する影響は非常に大きいので、私達ユーザーが書き換えるようなパラメータではないということだと思います (※)。
(※) 厳密にはGitHubからSELinuxのソースコード全体をダウンロードし、Base Policyを編集して全体をビルドし直せば、Default Ruleだけでなく何でも書き換えられます。しかし、そこまですることはまずないでしょう。
targeted policyにおいて、Default RuleがTypeを書き換えることはありません。
したがって、私達がDefault Ruleの仕様を気にする必要は全くありません。
Default Ruleは、MLSを使う方のみ気にするようにしましょう。
Transition Rule
Transition RuleもDefault Ruleと同様に、プロセスやファイルが新規作成されたとき、デフォルトのSecurity Contextを指定するルールです。
両者の役割は基本同じですが、Default Ruleと比較してType Transitionはより細かくSecurity Contextを書き換える条件を指定できます。
Transition Ruleには、以下のバリエーションがあります。
それぞれrole、type、rangeの変化に関するルールを記述するStatementです。
これらの中で、重要なのはTypeを変化させるtype_transitionのみです。
Type Transitionについては、#Type Transitionのセクションにて詳細に説明します。
(参考) SID (Security ID)
SID (Security ID) を知ることでSecurity Contextの決まり方について更に理解が進むので、ここで紹介しておきます。
SELinuxを運用する上でSIDは必ずしも必要にはならないので、興味のある方のみご覧いただければと思います。
SIDとは、Security Contextのデフォルト値を決めるパラメータです27。
Initial SIDと呼ばれることもあります。
デフォルト値と言えば、プロセスの場合は親プロセス、ファイルの場合は親ディレクトリのSecurity Contextが引き継がれるのでした。
SIDは、上記ルールでもカバーできないような状況でのデフォルト値を定義する、言ってみれば最後のデフォルト値です。
例えば、PPID (Parent Process ID) が0、つまり親プロセスを持たないsystemd
プロセスや、SELinuxが無効化された状態で作成されたためSecurity Contextを持たないファイルなどに対して、SIDが利用されます。
SIDのSyntaxは以下の通りです。
やや冗長ですが、1行目でsid_idを定義し、2行目でsid_idにSecurity Contextを紐付けます。
sid sid_id; sid sid_id context;
SIDの定義を以下に示します。
SID名の後にSecurity Contextが紐付いています。
seinfo -x --initialsid # Initial SIDs: 27 # sid any_socket system_u:object_r:unlabeled_t:s0 # sid devnull system_u:object_r:null_device_t:s0 # sid file system_u:object_r:unlabeled_t:s0 # sid file_labels system_u:object_r:unlabeled_t:s0 # sid fs system_u:object_r:fs_t:s0 # sid icmp_socket system_u:object_r:unlabeled_t:s0 # sid igmp_packet system_u:object_r:unlabeled_t:s0 # sid init system_u:object_r:unlabeled_t:s0 # sid kernel system_u:system_r:kernel_t:s0 # sid kmod system_u:object_r:unlabeled_t:s0 # sid netif system_u:object_r:netif_t:s0 # sid netmsg system_u:object_r:netlabel_peer_t:s0 # sid node system_u:object_r:node_t:s0 # sid policy system_u:object_r:unlabeled_t:s0 # sid port system_u:object_r:port_t:s0 # sid scmp_packet system_u:object_r:unlabeled_t:s0 # sid security system_u:object_r:security_t:s0 # sid sysctl system_u:object_r:sysctl_t:s0 # sid sysctl_dev system_u:object_r:unlabeled_t:s0 # sid sysctl_fs system_u:object_r:unlabeled_t:s0 # sid sysctl_kernel system_u:object_r:unlabeled_t:s0 # sid sysctl_modprobe system_u:object_r:unlabeled_t:s0 # sid sysctl_net system_u:object_r:unlabeled_t:s0 # sid sysctl_net_unix system_u:object_r:unlabeled_t:s0 # sid sysctl_vm system_u:object_r:unlabeled_t:s0 # sid tcp_socket system_u:object_r:unlabeled_t:s0 # sid unlabeled system_u:object_r:unlabeled_t:s0
各種SIDが使われる条件は、ざっくり以下の通りです28。
- kernelが起動したプロセスやスレッドはkernel SIDのSecurity Contextが割り当てられる
- file classやdir classがSecurity Contextを持たない場合、file SIDのSecurity Contextが割り当てられる
- (その他のSIDも同様)
- Security Contextが (値なしではなく) 不正な値を持っていた場合、unlabeled SIDのSecurity Contextが割り当てられる (滅多にないと思います)
kernel SIDが使われるケースは、例えばこんな状況です29。
- kernelが起動したsystemd/initプロセス (PID 1) や、その他いくつかのスレッドはkernel SIDのkernel_t Typeが割り当てられる
- ただしsystemd/initプロセスは、その後Type Transitionしてinit_t Typeに変わる
file SIDが使われるケースは、例えばこんな状況です30。
- SELinuxを一時的に無効化した (disabled)
- ファイルを作成した。SELinuxは無効なのでラベル付けされない
- SELinuxを有効化した。有効化にはOS再起動を伴うので、ファイルシステムも再度読み込まれる
- 2で作成したファイルはSecurity Contextを持たないため、file SIDのSecurity Contextであるunlabeled_t Typeが割り当てられる
ただ、最近のディストリビューションではSELinuxをdisabledからenforcingなどに変更したタイミングで自動的にrelabelされるので、File Contextが<<none>>
(relabelしない)として定義されていない限りは上記のような状況にはならないと思います31。
Type Transition
Type Transitionとは、プロセスやファイルが生成した時にSecurity Contextの一部であるTypeを変化させるアクセス制御ルールです32。
Type Transitionがないと、プロセスは全てデフォルトのkernel_tかsystemdと同じinit_tになってしまいます。
実際にはプロセスによって異なるTypeを持っていますが、これはType Transitionの一種であるDomain Transitionの働きによるものです。
Type Transitionは2種類に分類できます。
名前は異なりますが、何のTypeが変化するかで呼び方を分けているだけで、本質は変わりません。
- Domain Transition: 新規生成するプロセスのTypeが変化するType Transition
- Object Transition: 新規生成するプロセス以外 (主にファイル) のTypeが変化するType Transition
以降のセクションで、Domain TransitionとObject Transitionについて図解と具体例を交えつつ説明します。
Domain Transition
Domain Transitionの概要
Domain Transitionとは、新規発行された子プロセスが親プロセスとは別のSecurity Contextに遷移する処理のことです。
(※) Default Ruleとは別物なので、区別してください
詳細な説明に入る前に、Domainという言葉をイメージしてみましょう。
以下の図も活用しつつ、説明を進めます。
Domainとは、一般に「範囲」を意味する言葉です。
SELinuxにおいては、Subjectであるプロセスのアクセス可能な範囲のことをDomainと呼びます。33,34,35
上図で言うと、init_t Domainとsshd_t Domainが存在します。
それぞれのDomainは、init_tとsshd_tをSubjectとしてアクセス可能なObjectを内包しています。
言い換えると、init_tとsshd_tをSubjectとして、矢印でつながった先をObjectとするallow Statementが存在する範囲のことをDomainと呼びます。
Domain Transitionとは、子プロセスが親プロセスのTypeを引き継がず別Typeを持つことで、異なるDomainに遷移することです。
これにより、子プロセスのsshdは、親プロセスのsystemdとは異なるsshdならではのリソースにアクセスできるようになります。
Entry Pointという言葉も重要です。
Entry Pointとは、子プロセスが別ドメインへ移動する際の入口役となる実行ファイルのことです。
上図ではsshd_exec_tがsshd_t DomainへのEntry Pointということになります。
最後に、図中に出てくるexecute, read, getattr, entrypoint, transitionは、Domain Transitionを実行するためにallow Statementで許可する必要があるPermissionです。
これらのPermissionに加え、type_transition Statementが別途定義されていることでDomain Transitionが可能となります。
Domain Transitionに必要なルール定義については、この後更に詳細に説明します。
Domain Transitionに必要な制御ルール
上記の具体例で言うと、Domain Transitionを行うのに必要なアクセス制御ルールは4行あります36。
Domain Transitionを実行するtype_transition
ルール1行と、必要なアクセスを許可するallow
ルール3行です。
前セクションの図において、実線の黒い矢印で表現されている部分に相当します。
# execute allow init_t sshd_exec_t : file { execute read getattr }; # entrypoint allow sshd_t sshd_exec_t : file entrypoint; # transition allow init_t sshd_t : process transition; type_transition init_t sshd_exec_t : process sshd_t;
実際にsesearch
でルール検索すると、ちゃんとヒットします。
initrc_domain
などAttributeを使って表現しているものもあるので表記が若干異なりますが、アクセス制御ルールとしてはちゃんと内包されています。
sesearchコマンドのオプションは次の記事で詳しく扱いますので、今は「実機でもちゃんとエビデンスが取れているんだな」とご理解いただければ十分です。
sesearch -A -s init_t -t sshd_exec_t -c file -p execute,read,getattr # allow init_t file_type:file { getattr relabelfrom relabelto }; # allow initrc_domain direct_init_entry:file { execute getattr map open read }; sesearch -A -s sshd_t -t sshd_exec_t -c file -p entrypoint # allow sshd_t sshd_exec_t:file { entrypoint execute execute_no_trans ioctl lock map open read }; sesearch -A -s init_t -t sshd_t -c process -p transition # allow initrc_domain daemon:process transition; sesearch --type_trans -s init_t -t sshd_exec_t # type_transition init_t sshd_exec_t:process sshd_t;
今回はsystemdプロセスからsshdプロセスが発行される例を取り上げて説明しましたが、Domain Transitionのルールの書き方は一般に同じです。
一般化して、initをparentに、sshdをchildに置き換えたルールも以下に添付しておきます。
# execute allow parent_t child_exec_t : file { execute read getattr }; # entrypoint allow child_t child_exec_t : file entrypoint; # transition allow parent_t child_t : process transition; type_transition parent_t child_exec_t : process child_t;
一般化した図も添付します。
type_transition Statement
type_transition Statementは、Type Transition (Domain/Object Transition) を実行する制御ルールです。
type_transitionのSyntaxは以下のとおりです37。
type_transition source_type target_type : class default_type;
Syntax上の各要素の意味は、以下のとおりです。
要素 | 意味 |
---|---|
source_type | TransitionのトリガーとなったActionのSubject (※) Transitionの条件1 |
target_type | TransitionのトリガーとなったActionのObject (※) Transitionの条件2 |
class | Transition対象のTypeのObject Class |
default_type | Transition後のType (※) 新規生成するプロセスやファイルのデフォルト値 |
例えば、先ほどのDomain Transitionの例をモデルにします。
Transitionのトリガーは、以下のallow Statementに対応するexecute命令でした。
以下のallow Statementは、init_tがsshd_exec_tを実行 (execute) することを許可するアクセス制御ルールです。
Subjectがinit_t、Objectがsshd_exec_tです。
allow init_t sshd_exec_t : file { execute read getattr };
それに対応するtype_transition Statementは以下のとおりです。
allow Statementと縦に並べるとわかりやすいですが、上述のallow StatementとSubjectとObjectが揃っています。
type_transitionのSubjectとObjectには、トリガーとなったexecuteのSubjectとObjectを指定します。
type_transition init_t sshd_exec_t : process sshd_t;
Transition後のTypeはsshd_tですが、これに関してはそのままの意味なので説明は不要だと思います。
最後にObject Classがprocessですが、これはTransition先のsshd_tがプロセスであることと対応しています。
なお、Domain TransitionとObject Transitionは全く同じ構文ですが、簡単な見分け方があります。
それは、Object ClassがprocessならDomain Transition、それ以外 (fileなど) ならObject Transitionということです。
Object Classがprocessということは、ファイル実行によって新規生成したプロセスのDomainが変わったということです。
このことから、このTransitionはObject Transitionではなく、Domain Transitionであると言えます。
Object Transition
Object Transitionの概要
Object Transitionとは、新規発行されたプロセス以外のリソース (ファイル、ディレクトリ、データベースのSchemaなど) が親要素とは別のSecurity Contextに遷移する処理のことです。
今回は、ファイルやディレクトリに着目して説明を進めます。
ファイルやディレクトリは、Type Transitionが発生しない場合は、生成したファイルの親ディレクトリのTypeを引き継ぐのがデフォルトの動作です。
Object Transitionが発生すると、生成したファイルやディレクトリが別のTypeを持ちます。
これによって、新規生成したファイル/ディレクトリは親ディレクトリと異なるallow Statementに一致するようになり、異なるアクセス制御パターンを実装できるようになります。
Object Transitionの具体例を下図に示します。
NetworkManagerが/var/log/wicd.*
にログファイルを作成するとします。
Object Transitionがなければ、/var/log/
と同じTypeを引き継いで/var/log/wicd.*
にvar_log_t
を割り当てようとします。
しかし、今回の場合はObject Transitionによって/var/log/wicd.*
というObjectにNetworkManager_log_t
が割り当てられました。
上述の挙動を実現するためには、Domain Transitionと同様にtype_transition
ルールと、付随するいくつかのallow
ルールが必要です。
詳細は次のセクションで説明します。
Object Transitionに必要な制御ルール
上記の具体例で言うと、Object Transitionを行うのに必要なアクセス制御ルールは3行あります38。
Object Transitionを実行するtype_transition
ルール1行と、必要なアクセスを許可するallow
ルール2行です。
前セクションの図において、実線の黒い矢印で表現されている部分に相当します。
allowルールによって、NetworkManagerプロセスが親ディレクトリにファイル追加する権限 (add_name)と、対象のファイルを作成する権限 (create) を中心にアクセス許可しています。
Object Transitionの場合は、type_transitionに親ディレクトリへのadd_nameと同じSubjectとObjectをセットすることに気をつけてください。
ファイルのcreateの方ではありません。
# add_name allow NetworkManager_t var_log_t:dir { add_name write search }; # create allow NetworkManager_t NetworkManager_log_t:file { create write getattr }; # transition type_transition NetworkManager_t var_log_t:file NetworkManager_log_t;
target policyの実機上では、以下のようにルール定義されていました。
# add_names sesearch -A -s NetworkManager_t -t var_log_t -c dir -p add_name,write,search # allow NetworkManager_t var_log_t:dir { add_name ioctl lock read remove_name write }; # allow domain var_log_t:dir { getattr open search }; # create sesearch -A -s NetworkManager_t -t NetworkManager_log_t -c file -p create,write,getattr # allow NetworkManager_t NetworkManager_log_t:file { create open setattr }; # allow application_domain_type logfile:file { append getattr ioctl lock }; # allow daemon logfile:file { append getattr ioctl lock }; # transfer sesearch --type_trans -s NetworkManager_t -t var_log_t -c file # type_transition NetworkManager_t var_log_t:file NetworkManager_log_t;
今回はNetworkManagerプロセスからログファイルを自動生成する例を取り上げて説明しましたが、Object Transitionのルールの書き方は一般に同じです。
一般化して、NetworkManagerをprocessに、/var/log
を/parent/dir
に置き換えたルールも以下に添付しておきます。
# add_name allow process_t parent_dir_t:dir { add_name write search }; # create allow process_t process_yyy_t:file { create write getattr }; # transition type_transition process_t parent_dir_t:file process_yyy_t;
一般化した図も添付します。
Name Transition
Name TransitionはObject Transitionの一種です。
Name Transitionとは、TypeとObject Classだけでなく、ファイル名も含めてTransitionする条件を細かく制御する機能です。
Name Transitionのルール設定例を以下に示します。
sesearch --type_trans -s init_t -t etc_t -c file # (一部のみ抜粋) # type_transition init_t etc_t:file syslog_conf_t rsyslog.conf; # type_transition init_t etc_t:file passwd_file_t passwd;
syslog_conf_t
やpasswd_file_t
などのTransition後のType指定の後に、rsyslog.conf
やpasswd
などのファイルが追加で指定されています。
このように最後のファイル名を指定することで、作成するファイル名によってTransition後のTypeを区別する書き方が可能となります。
今回の例では、両ルール共にSubject、Object、Classは全て同じです。
通常のObject Transitionでは、このような状況においては2つ以上のTypeを使い分けることはできません。
Name Transitionは、SubjectとObjectのTypeが同じで、それでもTransitionルールを区別したいときに使います。
Name Transition用のtype_transitionのSyntaxは、以下の構造です39。
#type_transition Statementで取り上げたDomain/Object Transitionの構文の末尾にobject_name
が増えています。
object_name
には、ファイル名を完全一致で指定します。
type_transition source_type target_type : class default_type object_name;
Name Transitionの場合も、Object Transitionと同様のallowルールが追加で必要です。
(参考) Typeの意味の見分け方
sshd_t
というTypeがあったとします。
このTypeがObjectとなった場合の典型的なObject Classと、具体的にどのようなリソースと紐づくかをすぐに言い当てることはできますでしょうか?
今回は簡単なので、すぐにわかるかもしれません。
しかし、5000強あるTypeとAttribute全てについて用途を言い当てることは難しいと思います。
そこで、ここでは用途を見分けるちょっとしたコツを紹介したいと思います。
Typeの見分け方
Typeは、以下の段階を踏んで見分けていくのが早いと思います。
- 名前から判断する
- manで検索する (
selinux-policy-doc
パッケージのインストール推奨) - allow Statementから推測する
どういったアプローチか、1つずつ説明します。
名前から判断する
絶対ではありませんが、Typeにはおおよその命名規則があります。
この命名規則から、多くの場合プロセス名とObject Classを判断できます。
Type名 | 具体例 | 用途 (class) |
---|---|---|
プロセス名_t | sshd_t | sshdプロセス (file) |
プロセス名_exec_t | sshd_exec_t | sshdのentry point、実行ファイル (file) |
プロセス名_log_t | zabbix_log_t | zabbixのログファイル (file) |
プロセス名_conf_t | syslog_conf_t | syslogの設定ファイル (file) |
プロセス名_port_t | syslogd_port_t | syslogdのポート番号 (tcp_socket, udp_socket) |
Object Classを判断できたら、後はclassごとに特化した確認コマンドを実行すればより具体的な情報がわかります。
プロセスの場合は、2通りのアプローチがあります。
1つ目の方法は、プロセスが起動している場合に使えます。
プロセス起動中という条件はあるものの、簡単に調べがつきます。
# sshd_t = /usr/sbin/sshd ps -eo user,label,command | grep sshd_t | grep -v grep # root system_u:system_r:sshd_t:s0-s0:c0.c1023 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
2つ目の方法は、allow Statementから追いかける方法です。
プロセスが起動していなくても調査可能です。
今回はプロセスとわかっているので、entrypointのルールから調べています。
もしプロセスと知らない場合はtype_transitionルールから探すのが確実ですが、これについては後述します。
# sshd_exec_tがentry point sesearch -A -s sshd_t -p entrypoint # allow sshd_t sshd_exec_t:file { entrypoint execute execute_no_trans ioctl lock map open read }; # sshd_exec_tは、/usr/sbin/sshd sudo semanage fcontext -l | grep :sshd_exec_t: # /usr/sbin/gsisshd regular file system_u:object_r:sshd_exec_t:s0 # /usr/sbin/sshd regular file system_u:object_r:sshd_exec_t:s0
余談ですが、関連ファイルが1つでも分かればパッケージを特定して追加の情報を得ることも可能です。
# パッケージはopenssh-server dnf provides /usr/sbin/sshd # openssh-server-8.7p1-2.fc35.x86_64 : An open source SSH server daemon # Repo : @System # Matched from: # Filename : /usr/sbin/sshd # openssh-serverとは何か? dnf info openssh-server # Installed Packages # Name : openssh-server # Version : 8.7p1 # Release : 2.fc35 # Architecture : x86_64 # Size : 1.0 M # Source : openssh-8.7p1-2.fc35.src.rpm # Repository : @System # From repo : fedora # Summary : An open source SSH server daemon # URL : http://www.openssh.com/portable.html # License : BSD # Description : OpenSSH is a free version of SSH (Secure SHell), a program for logging # : into and executing commands on a remote machine. This package contains # : the secure shell daemon (sshd). The sshd daemon allows SSH clients to # : securely connect to your SSH server.
ファイルの場合はFile Contextを確認すれば大体わかります。
zabbix_log_t
は/var/log/zabbix.*
とわかりました。
Zabbixのログファイルという予想は正しそうです。
sudo semanage fcontext -l | grep :zabbix_log_t: # /var/log/zabbix.* all files system_u:object_r:zabbix_log_t:s0
TCP/UDP Socketの場合は、ポート番号のSecurity Contextを確認すればポート番号を特定できます。
もしサービスが起動していれば、ss
から追加の情報を得られます。
そうでなくても、/etc/services
からポート番号と対応する和名を調べることができます。
(※) /etc/services
は、現在Activeなポート番号とプロセス名の最新の紐付けを示すファイルではなく、あくまでLinuxがポート番号の和名を表示するためのマッピング情報が静的に記述されているだけのファイルです。参考:man services
sudo semanage port -l | grep syslogd_port_t # syslogd_port_t tcp 601, 20514 # syslogd_port_t udp 514, 601, 20514 grep -P ' (601/tcp|20514/tcp|514/udp|601/udp|20514/udp) ' /etc/services # syslog-conn 601/tcp # Reliable Syslog Service # syslog-conn 601/udp # Reliable Syslog Service
manで検索する
このやり方は非常に簡単で、頭を使わずにできます。
man -Kw
に検索ワードを指定するだけです。
唯一の弱点は、manに載っていないと使えないことです。
この方法はTypeに限らず、Attribute、Booleanなど何でも使えます。
それどころか、SELinuxに限らず一般的に使えます。
-K
は、man全文からのキーワード検索をするオプションです。
検索にヒットしたmanを順に開いていきます。
-w
は検索結果の返し方をチューニングするオプションです。
検索にヒットしたmanファイルのフルパスを一覧表示します。
-K
のみだと検索がたくさんヒットしたときに全体俯瞰しづらいので、-w
と組み合わせます。
man -Kw watchdog_t # /usr/share/man/man8/watchdog_selinux.8.gz # /usr/share/man/man8/freeipmi_bmc_watchdog_selinux.8.gz # 載ってないこともある man -Kw vmware_device_t # No manual entry for vmware_device_t
watchdog_tについてより詳しく知るには、man watchdog_selinux
、man freeipmi_bmc_watchdog_selinux
を実行すれば良いとわかります。
allow Statementから推測する
私達が気にするTypeの大半はプロセスかファイルです。
そしてプロセスかファイルは、systemdなど一部を除いてほぼ全てがDomain/Object TransitionしてそのTypeに変化しています。
つまり、Type Transitionルールを検索すれば何かしらのヒントを得られます。
対象がプロセスだった場合は簡単です。
以下の出力から「sshd_t
はinit_t
からsshd_exec_t
をentry pointとしてDomain Transitionしたプロセスである」というところまで一発でわかります。
sesearch --type_trans -D sshd_t # (一部のみ抜粋) # type_transition init_t sshd_exec_t:process sshd_t;
後は#名前から判断するの例と同様に、sshd_exec_t
のFile Contextを確認して詳細を調べていけます。
対象がファイルやディレクトリだった場合も同様に簡単です。
以下の出力から、「locale_t
はzabbix_script_t
プロセスがetc_t
のディレクトリ配下にファイルを生成した時にObject Transitionした、ファイルである」ことがわかります。
Object Classがfileなのでファイルと判断しましたが、ここがdirの場合はディレクトリです。
sesearch --type_trans -D locale_t # type_transition zabbix_script_t etc_t:file locale_t clock;
ファイルであることがわかったので、後は#名前から判断すると同様にFile Contextを調べれば詳細を確認できます。
対象がファイルでもプロセスでもなかった場合は、type_transitionルールにヒットしないと思われます。
こういったTypeの正体を突き止めるのは困難を極めます。
基本的にはmanやGoogleを検索し、わからなければサポートに問い合わせなければ厳しいと思います。
そもそもこういったTypeを調べる場面は想像することも難しいほどレアだと思います。
もしあるとしたら、エラーが発生した場合でしょうか。
その場合は、アプリケーションのエラーログやsetroubleshootのログも合わせて総合的に調査方針を検討する必要があると思います。
File Contextとrelabel
ファイルのSecurity Contextを計算する場面
#ファイルのContext計算にて、ファイルが新規作成されるときのTypeは以下のように決まると説明しました。
以下の他にもDefault Ruleなどの存在はありますが、実際にはほとんど意識する必要がないので割愛しています。
- 作成されたファイルの親ディレクトリと同じTypeを持つ
- ただし、Object Transitionの条件を満たす時、type_transitionルールに従ってTypeが決定する
実は、ファイル作成以外にもファイルのSecurity Contextを計算・変更する状況があります。
chcon
コマンドによって、対象のファイルを任意のSecurity Contextに変更したとき- relabel処理が走ったとき
1のchcon
コマンドは、テストしたいときを除いて滅多に実行することはありません。
ここで取り上げたいのは、2のrelabel処理についてです。
次のセクションでrelabelとは何かについて説明します。
relabelとは
relabelとは、ファイルを再度ラベル付けする処理のことです。40,41
relabel対象のファイルのSecurity Contextを確認し、File Contextの内容と差分があればFile Contextの定義通りの値に変更します。
File Context (fcontext) とは
File Context (fcontext) とは、ファイルパスとSecurity Contextの紐付け定義です。
relabel処理は、File Contextの紐付け通りになるようにファイルのSecurity Contextを書き換えます。
File Contextは、allow Statementやtype_transition Statementなどと同様に、Module Sources (ソースコード) にて定義されます。
また、semanage fcontext
コマンドによってユーザーの手で追加のFile Contextを定義することも可能です。
semanage fcontext -l
でFile Contextの定義を一覧表示できます。
File Contextは、ファイルパスはPerl互換の正規表現で定義できます42。
grepと組み合わせて、特定Typeと紐づくFile Contextを調べるのによく使います。
sudo semanage fcontext -l # SELinux fcontext type Context # / directory system_u:object_r:root_t:s0 # /.* all files system_u:object_r:default_t:s0 # (以下略) sudo semanage fcontext -l | grep :user_home_dir_t: # /home/[^/]+ directory unconfined_u:object_r:user_home_dir_t:s0 # /home/[^/]+ symbolic link unconfined_u:object_r:user_home_dir_t:s0
逆にファイルパスを元に対応するSecurity Contextを知りたい場合は、matchpathcon
コマンドが便利です。
selabel_lookup -k
でも同じことはできますが、matchpathcon
の方が楽に覚えられると思います。
matchpathcon /etc/selinux/config # /etc/selinux/config system_u:object_r:selinux_config_t:s0 selabel_lookup -k /etc/selinux/config # Default context: system_u:object_r:selinux_config_t:s0
これらのコマンドは、引数に渡したPATHをFile Contextと突き合わせてSecurity Contextを返しています。
したがって、matchpathconとselabel_lookup -kの引数はフルパスで指定しないと想定する結果が返ってこないので注意してください。
pwd # /etc/selinux matchpathcon config # config <<none>>
relabelが発生する場面
relabel処理は、以下の状況で発生します。
/.autorelabel
を配置してOS再起動restorecon
コマンドの実行fixfiles restore
コマンドの実行fixfiles relabel
コマンドの実行 (ほぼ使わない)
他にも、ドキュメントには書かれていませんがSELINUXTYPE (targeted/minimum/mls) が変わった時にも自動的にrelabel処理が走りました。
また、RHEL8の場合はSELinuxがdisabledからpermissive/enforcingに変化したときにもrelabel処理が走ります43。
次のセクションから、relabelを実行する操作を1つずつ説明します。
/.autorelabel
/.autorelabel
ファイルを配置してからOS再起動すると、Linux起動中に以下の処理が走ります44。
fixfiles restore
rm /.autorelabel
1つ目の処理で、ファイルシステム全体をrelabelします。
2つ目の処理で/.autorelabel
ファイルを削除し、次回以降の再起動ではrelabelが走らないようにします。
(※) man selinux_configによると空の/.autorelabel
を配置するだけでfixfiles -F restore
を実行しそうな説明が書いてありますが、実際にはfixfiles restore
の実行になります。空の/.autorelabel
を配置して再起動してもSELinux UserはRelabelされませんでした。fixfiles -F restore
を実行するには、fixfiles -F onboot
を実行するか、-Fと書いてある/.autorelabel
を配置する必要があります
OS再起動は伴うものの、/.autorelabel
を使うのがrelabelのやり方として最も確実とSELinuxのマニュアルに書かれています45。
とはいえ、ちょっとした修正であれば#restoreconや#fixfiles restoreを利用して問題ありません。
OS再起動をすれば、/dev
なども含めてより確実にrelabelできるということと理解しています。
/.autorelabel
を使うのは、SELinuxを無効 (disabled) から有効 (enforcing/permissive) に変更したときです。
SELinuxが無効の状態で作成されたファイルはSecurity Contextが割り当てられません。
Security Contextが割り当てられていないファイルは、以下のように見えます。
getenforce # Disabled touch x ls -Z x # ? x
この状態でSELinuxを有効化すると、ファイルに想定外のSecurity Contextが割り当てられることで、SELinuxによるアクセス拒否が大量に発生してしまう恐れがあります46。
ただ、実際にはRHEL8の場合は無効から有効に切り替えたタイミングで/.autorelabel
が無くてもrelabelが走る仕様です。
とはいえ、過信は禁物です。
SELinuxをdisabledからenforcingに切り替える際は、必ず/.autorelabel
を配置してからOS再起動しましょう。
また、滅多にやらないと思いますがSELINUXTYPEの値を変更する際にも/.autorelabel
を配置すべきです。
/.autorelabel
の使い方の例を以下に示します。
/.autorelabel
の配置にはtouchコマンドを使っても良いのですが、今回の例では専用コマンドのfixfiles onboot
を使います。
個人的には、専用コマンドの方がタイプミスの心配が少なくて良いかなと思います。
通常のユースケースではType Enforcementしか使わないので、-F
の指定は必要ないと思います。
# sudo touch /.autorelabelと同等
sudo fixfiles onboot
sudo reboot
targeted policyからmls policyに変更する場合など、TE以外のRBAC、UBAC、MLS、MCSなどを使う場合にはType以外のSecuirty Contextも重要になってきます。
以下の例では-F
を指定することで、TypeだけでなくUser,Role,Rangeもrelabel対象としています。
(※) TE以外を使うことは基本的にないので、あくまで参考情報です
# sudo bash -c 'echo -n -F > /.autorelabel'と同等 sudo fixfiles -F onboot sudo reboot
restorecon
特定のファイルのSecurity Contextを修正したい時、restoreconは便利です47。
restoreconは、特定ファイルやディレクトリに対象を絞ったrelabelを実行するコマンドです。
対象ファイルのSecurity ContextをFile Contextに合わせて変更します。
よくあるシナリオとしては、ある場所に作成したファイルをmvで移動したことで、Security Contextがおかしくなった時にrestoreconで修正します。
以下に具体例を示します。
ホームディレクトリ配下にファイルxを作成します。
作成したファイルはuser_home_t
Typeを持ちます。
touch /home/endy/x ls -Z /home/endy/x # system_u:object_r:user_home_t:s0 /home/endy/x
作成したファイルをmvで移動します。
mvはcpとは異なり、オーナーやタイムスタンプなどのメタ情報を保持します。
これは拡張ファイル属性として保持されるSecurity Contextも例外ではなく、これも保持されます。
しかしmatchpathcon
が示すとおり、File Contextの値はsystem_u:object_r:usr_t:s0
です。
sudo mv /home/endy/x /opt/x ls -Z /opt/x # unconfined_u:object_r:user_home_t:s0 /opt/x matchpathcon /opt/x # /opt/x system_u:object_r:usr_t:s0
ここで、restoreconを実行して/opt/x
のSecurity ContextをFile Contextの値に合わせて変更します。
restoreconは実行しても標準出力を出しませんが、-v
をつけることで変更内容を表示するようになります。
また、-n
をつけるとテストモード実行のようにSecurity Contextを変更しません。
-n
は-v
とセットで使うことが多いです。
以下で試してみましょう。
restorecon -nv /opt/x # Would relabel /opt/x from unconfined_u:object_r:user_home_t:s0 to unconfined_u:object_r:usr_t:s0 ls -Z /opt/x # unconfined_u:object_r:user_home_t:s0 /opt/x
変更内容は表示されますが、実際には変更されていません。
では、実際に変更してみます。
Typeがusr_t
に変化しました。
しかし、Userは変化していないです。
restorecon /opt/x ls -Z /opt/x # unconfined_u:object_r:usr_t:s0 /opt/x matchpathcon /opt/x # /opt/x system_u:object_r:usr_t:s0
このように、restoreconはデフォルトでTypeしか変更しません。
-F
をつけて実行すれば、User/Role/Rangeも含めて変更します。
一旦chconで元の状態に戻した上で、今度は-F
付きで試してみましょう。
(※) chcon
は、ファイルに任意のSecurity Contextをセットするコマンドです。今回のようなテスト用途でたまに使います
chcon -t user_home_t /opt/x ls -Z /opt/x # unconfined_u:object_r:user_home_t:s0 /opt/x restorecon -F /opt/x ls -Z /opt/x # system_u:object_r:usr_t:s0 /opt/x
restoreconの挙動確認はこれで一旦おしまいです。
/opt/x
はもう使わないので、削除しておきます。
sudo rm /opt/x
fixfiles
fixfilesは、内部的にはrestoreconを呼び出しています。
このことは、man fixfilesの以下の文言から読み取れます。
-v Modify verbosity from progress to verbose. (Run restorecon with -v instead of -p)
fixfilesは、restoreconと比較して大規模なrelabelを行うのに使われます。
デフォルトでrestorecon -R
のように再帰的に実行する上、実行対象のパスを指定しなければ暗黙的に/
が指定されます。
つまり、シンプルにfixfiles restore
とだけ実行すると、ファイルシステム全体がrelabelされます。
/etc/selinux/fixfiles_exclude_dirs
にディレクトリパスを列挙しておくと、そのディレクトリについてはrelabelの対象外とするような制御も可能です。
初期状態ではfixfiles_exclude_dirs
ファイル自体が存在しないので、対象外のディレクトリは存在しないのがデフォルト動作となります (Fedora35で確認)。
fixfilesは以下のサブコマンドを持ちます。 以降のセクションで一つ一つ説明します。
サブコマンド | 意味 |
---|---|
onboot | /.autorelabel を作成する |
check またはverify |
relabelせず、relabelが必要なファイルを列挙する (≒ restorecon -nv ) |
restore | ファイルシステム全体をrelabelする (≒restorecon -Rp / ) |
relabel | restoreとほぼ同じ。 ただし、実行前に /tmp 配下を削除できる (≒rm -rf /tmp/*; restorecon -Rp / ) |
fixfiles onboot
fixfiles onboot
は、touch /.autorelabel
と同じ意味を持ちます。
fixfiles -F onboot
で、echo -n '-F' > /.autorelabel
と同じ意味を持ちます。
基本的にはTypeしか使わないので、-F
をつけることはあまりないと思います。
ls /.autorelabel # ls: cannot access '/.autorelabel': No such file or directory sudo fixfiles onboot # System will relabel on next boot ls /.autorelabel # /.autorelabel
この後OS再起動すると、#/.autorelabelで説明したとおりfixfiles restore
相当のrelabelが実行されます。
fixfiles check (または、fixfiles verify)
fixfiles check
は、relabelを実行したときにSecurity Contextが書き換わるファイルを列挙します。
実際にはSecurity Contextを書き換えません。
fixfiles verify
も全く同じ意味です。
restorecon -Rnv
とほぼ同等の挙動です。
試しに、ファイルxのSecurity Contextを書き換えた上でfixfiles check
を実行してみます。
touch /home/endy/x chcon -u sysadm_u -t tmp_t /home/endy/x ls -Z /home/endy/x # sysadm_u:object_r:tmp_t:s0 /home/endy/x sudo fixfiles check # Checking / /boot /dev /dev/hugepages /dev/mqueue /dev/pts /dev/shm /run /run/user/1000 /sys /sys/fs/cgroup /sys/fs/pstore /sys/kernel/debug /sys/kernel/debug/tracing /sys/kernel/tracing /tmp # Would relabel /home/endy/x from sysadm_u:object_r:tmp_t:s0 to sysadm_u:object_r:user_home_t:s0
fixfiles
もrestorecon
と同様、デフォルトではTypeしか確認しません。
-F
を指定することで、User, Role, Rangeを全て確認してくれます。
-F
の挙動は、onboot, restore, relabelなど他のサブコマンドについても同様です。
また、fixfiles check
の後に対象のファイルやディレクトリを指定することで、チェック対象を絞り込むことができます。
ディレクトリを指定した場合は配下のファイルやディレクトリを再帰的にチェックします。
fixfiles restore
も同様にファイルやディレクトリを指定できます。
fixfiles relabel
は、常に/
が暗黙的に選択され、全てのファイルをrelabelします。
では、これらの特徴を試してみましょう。
対象が/home
配下に絞られているので処理が早く終わります。
また、TypeだけでなくUserもrelableするというチェック結果になっていることがわかります。
sudo fixfiles -F check /home/ # Would relabel /home/endy/x from sysadm_u:object_r:tmp_t:s0 to unconfined_u:object_r:user_home_t:s0
fixfiles check
の動作確認はここでおしまいです。
使い終わったファイルを削除しておきます。
rm /home/endy/x
fixfiles restore
fixfiles restore
は、ファイルシステム全体をrelabelします。
このコマンドを単体で使うと、OS再起動することなくrelabelが可能です。
OS再起動を伴わない分/.autorelabel
を使った方法よりも気軽に実行しやすいです。
しかし、man selinuxでも触れられている通り/.autorelabel
を使った方法が "Best" とのことなので、もしリリース前など、気軽に再起動できる状況であればOS再起動を伴う方法の方が手堅いとは思います。
以下に実行例を示します。
単にfixfiles restore
を実行すると、Typeのみrelabelします。
また、restorecon
と同様に-v
を指定しないと何が書き換わったかわかりません。
実行時間短縮のため、/home/endy/
配下に対象を絞って実行します。
touch /home/endy/x chcon -u system_u -t tmp_t /home/endy/x ls -Z /home/endy/x # system_u:object_r:tmp_t:s0 /home/endy/x sudo fixfiles restore /home/endy/ ls -Z /home/endy/x # system_u:object_r:user_home_t:s0 /home/endy/
一旦Typeを元に戻して、今度は-F
と-v
を指定して実行します。
今度は-F
の指定によってTypeだけでなくUser/Role/Rangeも含めてrelabelされます。
また、-v
によって実行結果が詳細に出力されます。
chcon -t tmp_t /home/endy/x ls -Z /home/endy/x # system_u:object_r:tmp_t:s0 /home/endy/x sudo fixfiles -Fv restore /home/endy # Relabeled /home/endy/x from system_u:object_r:tmp_t:s0 to unconfined_u:object_r:user_home_t:s0
(参考) fixfiles relabel
fixfiles relabel
を実行すると、fixfiles restore
と同様に対象をrelabelします。
ただし、実行前に/tmp
を削除するか聞かれます。
fixfiles relabel
のユースケースは、正直思い浮かびません。
「基本使わない」と覚えておけば良いと思います。
/tmp
配下を削除しないよう指定すると、fixfiles restore
と同様に動作します。
sudo fixfiles relabel # Files in the /tmp directory may be labeled incorrectly, this command # can remove all files in /tmp. If you choose to remove files from /tmp, # a reboot will be required after completion. # Do you wish to clean out the /tmp directory [N]? n # Relabeling / /boot /dev /dev/hugepages /dev/mqueue /dev/pts /dev/shm /run /run/user/1000 /sys /sys/fs/cgroup /sys/fs/pstore /sys/kernel/debug /sys/kernel/debug/tracing /sys/kernel/tracing /tmp # / 100.0% # /boot 100.0% # /dev 100.0% # /dev/hugepages 100.0% # Warning no default label for /dev/mqueue # /dev/mqueue 100.0% # /dev/pts 100.0% # /dev/shm 100.0% # /run 100.0% # /run/user/1000 100.0% # /sys 100.0% # /sys/fs/cgroup 100.0% # /sys/fs/pstore 100.0% # /sys/kernel/debug 100.0% # Warning no default label for /sys/kernel/debug/tracing # /sys/kernel/debug/tracing 100.0% # /sys/kernel/tracing 100.0% # /tmp 100.0% # Cleaning up labels on /tmp
/tmp
配下を削除するよう指定すると、fixfiles restore
と同様に動作します。
-f
を指定することで、/tmp
を削除するか聞かれずに無条件で削除するよう選択します。
/tmp
配下を削除した後は、Linuxが正しく動作するように一度再起動する必要があります。
sudo fixfiles -f relabel # Cleaning out /tmp # Relabeling / /boot /dev /dev/hugepages /dev/mqueue /dev/pts /dev/shm /run /run/user/1000 /sys /sys/fs/cgroup /sys/fs/pstore /sys/kernel/debug /sys/kernel/debug/tracing /sys/kernel/tracing /tmp # / 100.0% # /boot 100.0% # /dev 100.0% # /dev/hugepages 100.0% # Warning no default label for /dev/mqueue # /dev/mqueue 100.0% # /dev/pts 100.0% # /dev/shm 100.0% # /run 100.0% # /run/user/1000 100.0% # /sys 100.0% # /sys/fs/cgroup 100.0% # /sys/fs/pstore 100.0% # /sys/kernel/debug 100.0% # Warning no default label for /sys/kernel/debug/tracing # /sys/kernel/debug/tracing 100.0% # /sys/kernel/tracing 100.0% # /tmp 100.0% # Cleaning up labels on /tmp ls /tmp # (出力なし) sudo reboot
fixfiles restore
とfixfiles relabel
の違いは、/tmp
を削除するか否かです。
正直、/tmp
を削除するメリットはいまいちわかりません。
fixfiles relabel
を使うことはほぼないと思います。
Boolean
Booleanの概要
SELinuxのModule Policyには、いくつかのBooleanが定義されています48。
BooleanはPolicy Source (ソースコード) 上で条件分岐 (if文) として登場し、Booleanが1か0かによって挙動が変わるようにロジックが組まれています。
Booleanが1の場合はTrueを、0の場合はFalseを表します。
このBooleanの値を変更することで、ソースコードを変更すること無く既存のアクセス制御ルールの挙動を変更することができます。
ソースコード上は3種類のBooleanの定義方法がありますが、私達が使う段階においては特に機能に差はありません (※1)49。
ソースコード上の定義方法によっては、BooleanのことをTunableと呼ぶこともあります。
私達が扱うBooleanの大半はTunableになります (※2)。
(※1) The SELinux Notebookからgen_bool、gen_tunable、tunable_policyなど、各種Booleanを定義するための構文を参照できます。これらの構文を見比べると、結局のところ同じ使い方をしています。Boolean変数名を宣言して、その先で変数を利用したif文を記述するという使い方です。こういった理由から、各種Booleanは記述場所や記述方法が異なるのみで、機能的な差異は特にないと判断しました。
(※2) Fedoraが管理するSELinux Policyのソースコード上で、Global Booleanを定義するgen_boolよりもTunable Booleanを定義するgen_tunableとその中身を記述するtunable_policyの方が圧倒的にヒット数が多かったためです
Boolean関連コマンド
Booleanの値を調べるには、以下のいずれかのコマンドを使います。
getsebool -a
sudo semanage boolean -l
Booleanの意味を調べるには、以下のコマンドが有効です。
sesearch -A --type_trans -b <boolean>
Booleanの値を1 (True) に変更するには、以下のいずれかのコマンドを使います。
sudo setsebool -P <boolean> 1
sudo semanage boolean -m -1 <boolean>
Booleanの値を0 (False) に変更するには、以下のいずれかのコマンドを使います。
sudo setsebool -P <boolean> 0
sudo semanage boolean -m -0 <boolean>
Booleanのより詳細な使い方については、後続記事のSELinuxの実践の「Boolean有無の確認」セクションを参照してください。
(参考) アクセス制御ルールはどこに書いてあるのか
アクセス制御ルールが書いてある場所
アクセス制御ルールの情報は、Security Policyと呼ばれる単一のバイナリファイルに格納されていることは既に説明したとおりです。
このバイナリファイルを作る工程として、開発者はソースコード (Module Sources) を書いています。
したがって、SELinuxのTypeの定義やallow Statementなどの情報は、ソースコードを追うことでも確認することができます。
下図において、右下にある.te
、.fc
、.if
の拡張子を持つファイルが主なソースコードです。
これらのソースコードを専用のコマンドによるコンパイル・パッケージ化・インストールという工程を経てSecurity Policyファイルが生成します。
ソースコードを読む必要はあるのか?
実用上、ソースコードを読む必要はありません。
必要な定義情報は、全てseinfoやsesearchなどで検索することができます。
わざわざ読みづらいソースコードから理解する必要は全くありません。
非常にレアなケースとして、自分でソースコードを書いてルール定義したくなる場面もあるかもしれません。
ただ、相当なレアケースですので一旦は忘れて良いと思います。
重要なのはseinfoやsesearchコマンドを使いこなすことです。
このあたりのテクニック面のお話は、まとめて次の記事で説明します。
SELinuxの実践
ソースコード周りの話については、別途専用の記事を用意してあります。
もし 不幸にも ソースコードを書く必要な状況が出てきたら、目を通していただければと思います。
(参考) SELinux Module Policyのソースコード読解、ビルド
まとめ
SELinuxの最も重要な要素であるTE (Type Enforcement) について一通りの理論を説明しました。
かなり盛りだくさんの内容となりましたが、実運用をする上では全てを暗記する必要はありません。
本記事で扱った基礎理論をベースに、次の記事ではSELinuxのエラーを修正するための実践的なノウハウを紹介します。
ノウハウ理解のために知識の補完が必要な場合は、改めて本記事を辞書的に活用いただければ幸いです。
次の記事
SELinuxの実運用に必要な知識として、アクセス拒否エラーの切り分け手順と原因別の対処方を紹介します。
-
The SELinux Notebook - Types of SELinux Policy - #Policy Functionality Based on Name or Type↩
-
The SELinux Notebook - The Reference Policy - #Policy Functionality↩
-
The SELinux Notebook - The Reference Policy - #Policy Functionality↩
-
Red Hat - SELinux Coloring Book - #MCS Enforcement ※MCSはTEよりも少し細かい制御↩
-
RED HAT BLOG - Why you should be using Multi-Category Security for your Linux containers↩
-
RHEL8 - Using SELinux - Configuring Multi-Category Security for data confidentiality↩
-
Gentoo Wiki - SELinux/Tutorials/SELinux Multi-Level Security - #MLS on a default installation↩
-
Gentoo Wiki - SELinux/Quick introduction - #SELinux security subsystem↩
-
SELinux by Example: Using Security Enhanced Linux - 5.2.2. Types and Attributes ※書籍↩
-
SELinux by Example: Using Security Enhanced Linux - 5.3.1.2. Using Attributes in AV Rules ※書籍↩
-
The SELinux Notebook - Objects - #Object Classes and Permissions↩
-
The SELinux Notebook - Object Class and Permission Statements - #class-2↩
-
The SELinux Notebook - Object Class and Permission Statements - #Associating Permissions to a Class↩
-
The SELinux Notebook - Object Class and Permission Statements - #common↩
-
The SELinux Notebook - Computing Security Contexts - #Process↩
-
The SELinux Notebook - Computing Security Contexts - #Files↩
-
SELinux by Example: Using Security Enhanced Linux - 10.6. Initial Security Identifiers ※書籍↩
-
The SELinux Notebook - Computing Security Contexts - #Process↩
-
The SELinux Notebook - Computing Security Contexts - #Files↩
-
RHEL8 - Using SELinux - Permanent changes in SELinux states and modes↩
-
The SELinux Notebook - SELinux Overview - #Is SELinux useful → “SELinux can confine an application within its own ‘domain’ and allow it to have the minimum privileges required to do its job.”↩
-
The SELinux Notebook - Mandatory Access Control → “processes run in domains and the actions on objects are controlled by policy.”↩
-
The SELinux Notebook - Type Enforcement → “Basically if the type identifier is used to reference a subject it is referring to a Linux process or collection of processes (a domain or domain type)”↩
-
The SELinux Notebook - Domain and Object Transitions - #Domain Transition↩
-
The SELinux Notebook - Type Statements ※同じページにtype_changeやtype_memberがありますが、これらはlibselinux APIを使う類のルールなので基本意識不要です↩
-
The SELinux Notebook - Domain and Object Transitions - #Object Transition↩
-
RHEL8 - Using SELinux - Permanent changes in SELinux states and modes↩
-
RHEL8 - Using SELinux - Permanent changes in SELinux states and modes↩
-
The SELinux Notebook - The Reference Policy - #Booleans, Global Booleans and Tunable Booleans↩