スクエニ ITエンジニア ブログ

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-senddbus-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は図のように動作していることが分かります。

setroubleshootとD-Bus

setroubleshootdsedispatch がD-Bus経由で接続されています。 SELinuxのポリシ違反に関する情報は sedispatch から、avc 命令のメッセージとして送られます。 setroubleshootd はD-Bus経由で受け取った情報をもとに、分析をおこないます。 sedispatch はAuditから実行されます。

※ 実際には、D-Busにより調査をおこなった後に、setroubleshootのソースコードで更に調査をおこなっています。
※ 図に書いた要素以外にもsetroubleshootには、SetroubleshootPrivileged.pySetroubleshootFixit.py が関係しています。

最後に

ここでは、setroubleshootを例にD-Bus用ツールである busctl について紹介しました。 D-Busについては、日本語で記述された資料があまり多くないと認識しています。 ここでD-Busについて確認する方法の一部を紹介したことで、皆さんがD-Busと少しでも仲良くなる助けとなると幸いです。

この記事を書いた人

記事一覧
SQUARE ENIXでは一緒に働く仲間を募集しています!
興味をお持ちいただけたら、ぜひ採用情報ページもご覧下さい!