D-Busと少し仲良くなろう
はじめまして、スクウェア・エニックスのBと申します。 Linux上で良く分からない内に使用している方が多いであろう機能として、D-Busがあります。 D-Busは、プロセス間通信を実現する方法としてメッセージバスを提供してくれます。
名前からデスクトップ用途でしか使用することがないと思われる方もいるかもしれませんが、サーバ用途でも様々な箇所で使用されています。 例えば、SELinuxの関連でsetroubleshootというサービスがD-Busを利用しています。 これは、ポリシ違反に関する記録をもとに、その分析をおこなってくれるものです。
過去に私は負荷試験の過程で、setroubleshootを暴走させてしまいました。 setroubleshootが悪い訳ではなく、ポリシの調整不足から、大量の違反をsetroubleshootに分析させ続けてしまう状況にしてしまいました。 そして、それを停止するために、setroubleshootの仕組みを調査しました。 その過程でD-Busの設定や動作状態についても簡単に確認する必要がありました。 ここでは、その際に活用したD-Bus用ツールによるD-Busの確認方法について主に取り上げます。
setroubleshoot
D-Busの確認方法について紹介する前に、setroubleshootについても簡単にではありますが説明します。 setroubleshootはその名の通り、SELinuxに関するトラブルシュートを補助してくれるサービスです。 少なくとも、Red Hat Enterprise Linux 8では最初から裏で稼働しています。
setroubleshoot用のツールである sealert
による情報の出力操作とその例です。
ポリシ違反内容やその回数、ポリシの修正方法等を比較的分かりやすい形式で表示してくれます。
$ sealert -l '*'
# 出力例: コンテナ内からホスト上にディレクトリ /home/testuser/tmp を作成しようとした場合
SELinux is preventing /usr/bin/coreutils from write access on the directory labeled user_home_dir_t.
***** Plugin catchall (100. confidence) suggests **************************
If you believe that coreutils should be allowed write access on directory labeled user_home_dir_t by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# ausearch -c 'mkdir' --raw | audit2allow -M my-mkdir
# semodule -X 300 -i my-mkdir.pp
Additional Information:
Source Context system_u:system_r:container_t:s0:c3,c874
Target Context unconfined_u:object_r:user_home_dir_t:s0
Target Objects (null) [ dir ]
Source mkdir
Source Path /usr/bin/coreutils
Port <Unknown>
Host testhost
Source RPM Packages
Target RPM Packages
SELinux Policy RPM selinux-policy-targeted-3.14.3-95.el8.noarch
Local Policy RPM selinux-policy-targeted-3.14.3-95.el8.noarch
Selinux Enabled True
Policy Type targeted
Enforcing Mode Permissive
Host Name testhost
Platform Linux testhost 4.18.0-372.16.1.el8_6.x86_64 #1 SMP
Tue Jun 28 03:02:21 EDT 2022 x86_64 x86_64
Alert Count 3
First Seen 2022-07-14 10:53:47 JST
Last Seen 2022-07-14 10:53:47 JST
Local ID ee1a77bb-627d-4df6-ac09-cf822b4a8ad8
Raw Audit Messages
type=AVC msg=audit(1657763627.857:140): avc: denied { write } for pid=7425 comm="mkdir" name="testuser" dev="vda3" ino=25328689 scontext=system_u:system_r:container_t:s0:c3,c874 tcontext=unconfined_u:object_r:user_home_dir_t:s0 tclass=dir permissive=1
type=AVC msg=audit(1657763627.857:140): avc: denied { add_name } for pid=7425 comm="mkdir" name="tmp" scontext=system_u:system_r:container_t:s0:c3,c874 tcontext=unconfined_u:object_r:user_home_dir_t:s0 tclass=dir permissive=1
type=AVC msg=audit(1657763627.857:140): avc: denied { create } for pid=7425 comm="mkdir" name="tmp" scontext=system_u:system_r:container_t:s0:c3,c874 tcontext=system_u:object_r:user_home_dir_t:s0 tclass=dir permissive=1
type=SYSCALL msg=audit(1657763627.857:140): arch=x86_64 syscall=mkdir success=yes exit=0 a0=7fff12d67e3b a1=1ff a2=0 a3=0 items=2 ppid=7401 pid=7425 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm=mkdir exe=/usr/bin/coreutils subj=system_u:system_r:container_t:s0:c3,c874 key=(null)
type=CWD msg=audit(1657763627.857:140): cwd=/
type=PATH msg=audit(1657763627.857:140): item=0 name=(null) inode=25328689 dev=fc:03 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 nametype=PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1657763627.857:140): item=1 name=(null) inode=167829603 dev=fc:03 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:user_home_dir_t:s0 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
Hash: mkdir,container_t,user_home_dir_t,dir,write
D-Busの確認方法
CLI上でD-Busの設定や動作状態を確認する方法を探すと、dbus-send
や dbus-monitor
等にたどり着きます。
これらには多くの引数を渡す必要があり、D-Busについて分からない場合に難しく思えます。
現在は busctl
のみでもう少し簡単に似たような操作をおこなうことができます。
バスを一覧で表示する
$ busctl list
# 出力例: 実際にはより多くの行が出力されますが、setroubleshootに関係ない出力は省略
NAME PID PROCESS USER CONNECTION UNIT SESSION DESCRIPTION
:1.39 865 sedispatch root :1.39 auditd.service - -
:1.41 7427 setroubleshootd setroubleshoot :1.41 dbus.service - -
:1.45 7427 setroubleshootd setroubleshoot :1.45 dbus.service - -
org.fedoraproject.SetroubleshootFixit - - - (activatable) - -
org.fedoraproject.SetroubleshootPrivileged - - - (activatable) - -
org.fedoraproject.Setroubleshootd 7427 setroubleshootd setroubleshoot :1.41 dbus.service - -
特定バスのより詳細な情報を取得する
$ busctl status :1.39
# 出力例
PID=865
PPID=861
TTY=n/a
UID=0
EUID=0
SUID=0
FSUID=0
GID=0
EGID=0
SGID=0
FSGID=0
SupplementaryGIDs=
Comm=sedispatch
Exe=/usr/sbin/sedispatch
CommandLine=/usr/sbin/sedispatch
Label=system_u:system_r:auditd_t:s0
CGroup=/system.slice/auditd.service
Unit=auditd.service
Slice=system.slice
UserUnit=n/a
UserSlice=n/a
Session=n/a
AuditLoginUID=n/a
AuditSessionID=n/a
UniqueName=:1.39
EffectiveCapabilities=
PermittedCapabilities=
InheritableCapabilities=
BoundingCapabilities=
特定バス上の特定の宛先が受け付ける命令やシグナルを確認する
$ busctl introspect org.fedoraproject.Setroubleshootd /org/fedoraproject/Setroubleshootd
# 出力例
NAME TYPE SIGNATURE RESULT/VALUE FLAGS
org.fedoraproject.SetroubleshootdIface interface - - -
.avc method s s -
.check_for_new method s ii -
.delete_alert method s b -
.finish method - - -
.get_alert method s ssiasa(ssssbbi)tts -
.get_all_alerts method - a(ssi) -
.get_all_alerts_ignored method - a(ssi) -
.get_all_alerts_since method t a(ssi) -
.set_filter method ss b -
.start method - - -
.alert signal ss - -
.restart signal v - -
org.freedesktop.DBus.Introspectable interface - - -
.Introspect method - s -
特定バス宛に流れるメッセージを確認する
$ busctl monitor org.fedoraproject.Setroubleshootd
# 出力例: 実際には複数のメッセージが出力されますが、その中から1個を抜粋
Monitoring bus message stream.
Type=method_call Endian=l Flags=0 Version=1 Priority=0 Cookie=2 Timestamp="Thu 2022-07-14 01:53:47.862121 UTC"
Sender=:1.39 Destination=org.fedoraproject.Setroubleshootd Path=/org/fedoraproject/Setroubleshootd Interface=org.fedoraproject.SetroubleshootdIface Member=avc
UniqueName=:1.39
MESSAGE "s" {
STRING "type=AVC msg=audit(1657763627.857:140): avc: denied { write } for pid=7425 comm="mkdir" name="testuser" dev="vda3" ino=25328689 scontext=system_u:system_r:container_t:s0:c3,c874 tcontext=unconfined_u:object_r:user_home_dir_t:s0 tclass=dir permissive=1
type=AVC msg=audit(1657763627.857:140): avc: denied { add_name } for pid=7425 comm="mkdir" name="tmp" scontext=system_u:system_r:container_t:s0:c3,c874 tcontext=unconfined_u:object_r:user_home_dir_t:s0 tclass=dir permissive=1
type=AVC msg=audit(1657763627.857:140): avc: denied { create } for pid=7425 comm="mkdir" name="tmp" scontext=system_u:system_r:container_t:s0:c3,c874 tcontext=system_u:object_r:user_home_dir_t:s0 tclass=dir permissive=1
type=SYSCALL msg=audit(1657763627.857:140): arch=c000003e syscall=83 success=yes exit=0 a0=7fff12d67e3b a1=1ff a2=0 a3=0 items=2 ppid=7401 pid=7425 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="mkdir" exe="/usr/bin/coreutils" subj=system_u:system_r:container_t:s0:c3,c874 key=(null)
type=CWD msg=audit(1657763627.857:140): cwd="/"
type=PATH msg=audit(1657763627.857:140): item=0 name=(null) inode=25328689 dev=fc:03 mode=040700 ouid=1000 ogid=1000 rdev=00:00 obj=unconfined_u:object_r:user_home_dir_t:s0 nametype=PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1657763627.857:140): item=1 name=(null) inode=167829603 dev=fc:03 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:user_home_dir_t:s0 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PROCTITLE msg=audit(1657763627.857:140): proctitle=2F7573722F62696E2F636F72657574696C73002D2D636F72657574696C732D70726F672D73686562616E673D6D6B646972002F7573722F62696E2F6D6B646972002F686F6D652F74657374757365722F746d70
";
};
setroubleshootに関してD-Busから得られた情報を整理する
busctl
で得られた出力を組み合わせると、setroubleshootは図のように動作していることが分かります。
setroubleshootd
と sedispatch
がD-Bus経由で接続されています。
SELinuxのポリシ違反に関する情報は sedispatch
から、avc
命令のメッセージとして送られます。
setroubleshootd
はD-Bus経由で受け取った情報をもとに、分析をおこないます。
sedispatch
はAuditから実行されます。
※ 実際には、D-Busにより調査をおこなった後に、setroubleshootのソースコードで更に調査をおこなっています。
※ 図に書いた要素以外にもsetroubleshootには、SetroubleshootPrivileged.py
と SetroubleshootFixit.py
が関係しています。
最後に
ここでは、setroubleshootを例にD-Bus用ツールである busctl
について紹介しました。
D-Busについては、日本語で記述された資料があまり多くないと認識しています。
ここでD-Busについて確認する方法の一部を紹介したことで、皆さんがD-Busと少しでも仲良くなる助けとなると幸いです。