tomoyotitle.png

Chapter 7: ポリシーの適用はどのように行いますか?

7.1. 強制モードを有効にする

ドメインポリシーと例外ポリシーの調整が完了したら、ドメインに対して強制モードを割り当てることができます。

ポリシーエディタを実行して、対象となるドメインにプロファイル 3 を割り当てます:

editpolicy-httpd-profile3.png

@ キーを押してプロセス一覧表示に切り替えてください。そして、 /usr/sbin/httpd プロセスとその子孫に対してプロファイル 3 が割り当てられていることを確認してください:

editpolicy-httpd-process3.png

ポリシーエディタを終了して、ポリシーで許可されている操作をしてみましょう:

operation-permitted.png

メールの送信はポリシーで許可されているので、操作は正常に終了しました。

ポリシーで許可されていない操作をしてみましょう:

unix-penguin.png

一見すると正常に終了したように見えますが、実際には /bin/mail が「入力が空っぽです」と警告しているとおり、 /bin/cat の実行が拒否されています:

unix-penguin-rejected.png

確認モードと同様、 /sys/kernel/security/tomoyo/stat インタフェースからポリシー違反の発生回数と最後に発生した時刻について知ることができます:

# cat /sys/kernel/security/tomoyo/stat
Policy update:                              1571 (Last: 2010/12/25 16:10:48)
Policy violation in learning mode:           453 (Last: 2010/12/25 15:33:21)
Policy violation in permissive mode:          22 (Last: 2010/12/25 15:47:10)
Policy violation in enforcing mode:            2 (Last: 2010/12/25 16:08:35)
Memory used by policy:                    165728
Memory used by audit log:                      0 (Quota:   16777216)
Memory used by query message:                  0 (Quota:    1048576)
Total memory used:                        165728

もしアクセスログの設定を 4.6. アクセスログを保存する(任意)で行っていた場合は、拒否されたアクセス要求を /var/log/tomoyo/reject_003.log から抽出することができます:

# cat /var/log/tomoyo/reject_003.log
#2010/12/25 16:08:35# profile=3 mode=enforcing granted=no (global-pid=3628) task={ pid=3628 ppid=3627 uid=48 gid=48 euid=48 egid=48 suid=48 sgid=48 fsuid=48 fsgid=48 } path1={ uid=0 gid=0 ino=688153 major=8 minor=1 perm=0755 type=file } path1.parent={ uid=0 gid=0 ino=688129 perm=0755 } exec={ realpath="/bin/cat" argc=2 envc=7 argv[]={ "cat" "/etc/passwd" } envp[]={ "TERM=vt100" "PATH=/sbin:/usr/sbin:/bin:/usr/bin" "_=/bin/cat" "PWD=/usr/share/horde/admin" "LANG=en_US.UTF-8" "SHLVL=3" "LANGUAGE=en_US.UTF-8" } }
<kernel> /usr/sbin/httpd /bin/sh
file execute /bin/cat

#2010/12/25 16:08:35# profile=3 mode=enforcing granted=no (global-pid=3628) task={ pid=3628 ppid=3627 uid=48 gid=48 euid=48 egid=48 suid=48 sgid=48 fsuid=48 fsgid=48 } path1={ uid=0 gid=0 ino=688153 major=8 minor=1 perm=0755 type=file } path1.parent={ uid=0 gid=0 ino=688129 perm=0755 }
<kernel> /usr/sbin/httpd /bin/sh
file read /bin/cat

最初のログは、 /usr/sbin/httpd から実行された /bin/sh から /bin/cat の実行が要求され、そのときの0番目の引数( argv[0] と呼ばれます)は cat 、1番目の引数( argv[1] と呼ばれます)は /etc/passwd であったことを示しています。このログの1行目に mode=enforcing および granted=no という内容が含まれているため、この要求は拒否されたことが判ります。

2番目のログは、 /usr/sbin/httpd から実行された /bin/sh/bin/cat を読み込みモードでオープンしようとして拒否されたことを示しています。これは、要求されたプログラムを実行できなかった場合そのプログラムの内容を確認するために読み込みモードでオープンしようとするという習性が /bin/sh にあるためです。

7.2. 通知デーモン

ポリシー違反の発生を通知するために tomoyo-notifyd というデーモンプログラムが提供されています。 /etc/rc.local 等から /usr/sbin/tomoyo-notifyd を起動するようにしてください。

通知方法は /etc/tomoyo/tools/notifyd.conf に記録されています。以下に初期設定を示します:

# This file contains configuration used by tomoyo-notifyd command.

# tomoyo-notifyd is a daemon that notifies the occurrence of policy violation
# in enforcing mode.
#
# time_to_wait is grace time in second before rejecting the request that
# caused policy violation in enforcing mode. For example, if you specify
# 30, you will be given 30 seconds for starting tomoyo-queryd command and
# responding to the policy violation event.
# If you specify non 0 value, you need to register tomoyo-notifyd command to
# /sys/kernel/security/tomoyo/manager as well as tomoyo-queryd command, for tomoyo-notifyd needs to
# behave as if tomoyo-queryd command is running.
# Also, you should avoid specifying too large value (e.g. 3600) because
# the request will remain pending for that period if you can't respond.
#
# action_to_take is a command line you want to use for notification.
# The command specified by this parameter must read the policy violation
# notification from standard input. For example, mail, curl and xmessage
# commands can read from standard input.
# This parameter is passed to execve(). Thus, please use a wrapper program
# if you need shell processing (e.g. wildcard expansion, environment
# variables).
#
# minimal_interval is grace time in second before re-notifying the next
# occurrence of policy violation. You can specify 60 to limit notification
# to once per a minute, 3600 to limit notification to once per an hour.
# You can specify 0 to unlimit, but notifying of every policy violation
# events (e.g. sending a mail) might annoy you because policy violation
# can occur in clusters if once occurred.

# Please use TOMOYO Linux's escape rule (e.g. '\040' rather than '\ ' for
# representing a ' ' in a word).

# Examples:
#
# time_to_wait 180
# action_to_take mail admin@example.com
#
#    Wait for 180 seconds before rejecting the request.
#    The occurrence is notified by sending mail to admin@example.com
#    (if SMTP service is available).
#
# time_to_wait 0
# action_to_take curl --data-binary @- https://your.server/path_to_cgi
#
#    Reject the request immediately.
#    The occurrence is notified by executing curl command.
#
time_to_wait 0
action_to_take mail -s Notification\040from\040tomoyo-notifyd root@localhost
minimal_interval 60

action_to_take 行を変更して tomoyo-notifyd を実行してください。

ポリシー違反が発生すると以下のようなメールが届くはずです。このメールの内容は、ヘッダにシリアルナンバーが付与されている点を除いてアクセスログと同一内容です:

# mail
Mail version 8.1 6/6/93.  Type ? for help.
"/var/spool/mail/root": 1 messages 1 new
>N  1 root@localhost.local  Sun Dec 26 01:08  18/1211 "Notification from tomoyo-notifyd"
&
Message 1:
From root@localhost.localdomain  Sun Dec 26 01:08:35 2010
Date: Sun, 26 Dec 2010 01:08:35 +0900
From: root <root@localhost.localdomain>
To: root@localhost.localdomain
Subject: Notification from tomoyo-notifyd

Q0-0
#2010/12/25 16:08:35# profile=3 mode=enforcing granted=no (global-pid=3628) task={ pid=3628 ppid=3627 uid=48 gid=48 euid=48 egid=48 suid=48 sgid=48 fsuid=48 fsgid=48 } path1={ uid=0 gid=0 ino=688153 major=8 minor=1 perm=0755 type=file } path1.parent={ uid=0 gid=0 ino=688129 perm=0755 } exec={ realpath="/bin/cat" argc=2 envc=7 argv[]={ "cat" "/etc/passwd" } envp[]={ "TERM=vt100" "PATH=/sbin:/usr/sbin:/bin:/usr/bin" "_=/bin/cat" "PWD=/usr/share/horde/admin" "LANG=en_US.UTF-8" "SHLVL=3" "LANGUAGE=en_US.UTF-8" } }
<kernel> /usr/sbin/httpd /bin/sh
file execute /bin/cat

7.3. ポリシー違反を対話的に処理する

強制モードで発生したポリシー違反は、 tomoyo-queryd を用いることで対話的に処理することができます。この機能は、ソフトウェアアップデート時に便利です。なぜなら、ソフトウェアのアップデートにより、以下の何れかの状況が発生した場合にポリシーを修正する必要が生じる場合があるからです:

学習モードを使ってポリシーを最初から再取得するのが理想です。しかし、一度強制モードでの運用を開始したシステムを強制モード以外に変更することは、アクセスが制限されていないドメインへの攻撃に対してシステム全体が無防備になってしまうため、望ましくありません。

幸いなことに、 tomoyo-queryd を使うことで、管理者は強制モードでシステムを稼働させた状態のままポリシーの修正を行うことができます。ただし、この方法は、全てのケースに対応できるとは限らず、最適なポリシーであることを保証するものではありません。

7.3.1. tomoyo-queryd の操作例

実際の tomoyo-queryd の操作手順について以下のムービーで紹介しています。また、以下にテキストでも示します:

ポリシーに違反したアクセス要求を処理するために tomoyo-queryd コマンドを利用します:

# /usr/sbin/tomoyo-queryd
Monitoring /sys/kernel/security/tomoyo/query . Press Ctrl-C to terminate.

パッケージのアップデート中に、デーモンの再起動などのように普段行われない動作によりポリシー違反が発生するかもしれません。ポリシー違反が発生した場合、 tomoyo-queryd にプロンプトが表示されます:

#2010/12/30 00:21:11# profile=3 mode=enforcing granted=no (global-pid=11788) task={ pid=11788 ppid=11779 uid=0 gid=0 euid=0 egid=0 suid=0 sgid=0 fsuid=0 fsgid=0 } path1={ uid=0 gid=0 ino=753729 major=253 minor=0 perm=0755 type=file } path1.parent={ uid=0 gid=0 ino=753665 perm=0755 } exec={ realpath="/bin/sleep" argc=2 envc=6 argv[]={ "sleep" "1" } envp[]={ "TERM=xterm" "PATH=/sbin:/usr/sbin:/bin:/usr/bin" "PWD=/" "LANG=en_US.UTF-8" "SHLVL=1" "_=/bin/sleep" } }
<kernel> /etc/rc.d/init.d/sshd
file execute /bin/sleep
Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy and retry):

上記の例は、 <kernel> /etc/rc.d/init.d/sshd というドメインに属しているプロセスが sleep 1 というコマンドラインを処理するために /bin/sleep の実行を要求したが、ポリシーによって拒否されたことを示しています。通常であればポリシーに違反したアクセス要求は直ちに拒否されますが、 tomoyo-queryd が動作しているため、カーネルはあなたの判断を仰いでいることを示しています:

Y を押すと許可します。
N を押すと拒否します。
R を押すと再試行します。(手作業でドメインポリシーを変更した後などに利用します。)
S を押すとそのプロセスのドメインポリシーが表示します。
A を押すと編集した上でドメイン用ポリシーに追加後、再試行します。(先にドメインポリシーを編集することができます。)

無条件にアクセス要求を許可しないようにしてください。ポリシー違反の原因がパッケージのアップデートによるものとは限らず、侵入者の攻撃によるものである可能性があるからです。

このプログラムが動作している間は、ポリシーによって拒否されたアクセス要求は、あなたが応答するまで永遠に保留状態となりますので、ログアウトしないでください。プログラムが必要とするアクセス許可が与えられるようにするために、出力の監視を忘れないようにしてください。もし、アクセス許可の不足が検出された場合にはプロンプトが表示されます。ポリシーをのアップデートが完了したら、 Ctrl-C を入力して終了させてください。

このプログラムはメモリ上のポリシーを直接編集します。シャットダウンすると失われてしまいますので、忘れずに tomoyo-savepolicy を実行してポリシーを保存してください。

# /usr/sbin/tomoyo-savepolicy

7.3.2. tomoyo-queryd の出力例

以下は tomoyo-queryd がどのような出力を行うかの例を示しています:

#2010/12/30 00:21:11# profile=3 mode=enforcing granted=no (global-pid=11788) task={ pid=11788 ppid=11779 uid=0 gid=0 euid=0 egid=0 suid=0 sgid=0 fsuid=0 fsgid=0 } path1={ uid=0 gid=0 ino=753729 major=253 minor=0 perm=0755 type=file } path1.parent={ uid=0 gid=0 ino=753665 perm=0755 } exec={ realpath="/bin/sleep" argc=2 envc=6 argv[]={ "sleep" "1" } envp[]={ "TERM=xterm" "PATH=/sbin:/usr/sbin:/bin:/usr/bin" "PWD=/" "LANG=en_US.UTF-8" "SHLVL=1" "_=/bin/sleep" } }
<kernel> /etc/rc.d/init.d/sshd
file execute /bin/sleep
Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy and retry):a
Enter new entry> file execute /bin/sleep
Added 'file execute /bin/sleep'.

----------------------------------------
#2010/12/30 00:22:12# profile=3 mode=enforcing granted=no (global-pid=11937) task={ pid=11937 ppid=1 uid=26 gid=26 euid=26 egid=26 suid=26 sgid=26 fsuid=26 fsgid=26 } path1={ uid=0 gid=0 ino=690602 major=253 minor=0 perm=0644 type=file } path1.parent={ uid=0 gid=0 ino=690114 perm=0755 }
<kernel> /etc/rc.d/init.d/postgresql /sbin/runuser /bin/bash /usr/bin/postmaster
file read /usr/share/zoneinfo/posix/Pacific/Pohnpei
Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy and retry):s
# select global-pid=11937
<kernel> /etc/rc.d/init.d/postgresql /sbin/runuser /bin/bash /usr/bin/postmaster
use_profile 3
use_group 0

network unix stream connect /var/run/nscd/socket
file read /usr/lib/locale/locale-archive
file read /var/lib/pgsql/data/postgresql.conf
file read /var/lib/pgsql/data/PG_VERSION
file read /var/lib/pgsql/data/global/pg_control
file write /var/lib/pgsql/data/global/pg_control
file create /var/lib/pgsql/data/postmaster.pid 0600
file read /var/lib/pgsql/data/postmaster.pid
file write /var/lib/pgsql/data/postmaster.pid
file unlink /var/lib/pgsql/data/postmaster.pid
file read /usr/share/zoneinfo/MST7MDT
(...snipped...)
file read /usr/share/zoneinfo/EST5EDT
network inet stream bind 127.0.0.1 5432
network inet stream listen 127.0.0.1 5432
file create /tmp/.s.PGSQL.5432.lock 0600
file read /tmp/.s.PGSQL.5432.lock
file write /tmp/.s.PGSQL.5432.lock
file unlink /tmp/.s.PGSQL.5432.lock
file unlink /tmp/.s.PGSQL.5432
network unix stream bind /tmp/.s.PGSQL.5432
network unix stream listen /tmp/.s.PGSQL.5432
file mksock /tmp/.s.PGSQL.5432 0700
file chmod /tmp/.s.PGSQL.5432 0777
file write /var/lib/pgsql/data/postmaster.opts
file truncate /var/lib/pgsql/data/postmaster.opts
file mkdir /var/lib/pgsql/data/pg_log/ 0700
file append /var/lib/pgsql/data/pg_log/postgresql-Wed.log
network inet dgram bind 127.0.0.1 0
file read /var/lib/pgsql/data/pg_hba.conf
file read /var/lib/pgsql/data/pg_ident.conf
file read /var/lib/pgsql/data/pg_xlog/000000010000000000000000
file write /var/lib/pgsql/data/pg_xlog/000000010000000000000000
file read /var/lib/pgsql/data/pg_clog/0000
file write /var/lib/pgsql/data/pg_clog/0000
file read /var/lib/pgsql/data/pg_multixact/offsets/0000
file write /var/lib/pgsql/data/pg_multixact/offsets/0000
file read /var/lib/pgsql/data/global/pg_fsm.cache
file write /var/lib/pgsql/data/global/pg_fsm.cache
file unlink /var/lib/pgsql/data/global/pg_fsm.cache
file read /var/lib/pgsql/data/global/1262
file write /var/lib/pgsql/data/global/1262
file read /var/lib/pgsql/data/global/1260
file write /var/lib/pgsql/data/global/1260
file read /var/lib/pgsql/data/global/1261
file write /var/lib/pgsql/data/global/1261
file read /var/lib/pgsql/data/global/pg_auth
file read /var/lib/pgsql/data/global/pgstat.stat
file create /var/lib/pgsql/data/global/pgstat.tmp 0666
file write /var/lib/pgsql/data/global/pgstat.tmp
file rename /var/lib/pgsql/data/global/pgstat.tmp /var/lib/pgsql/data/global/pgstat.stat
file read /var/lib/pgsql/data/pg_subtrans/0000
file write /var/lib/pgsql/data/pg_subtrans/0000
file create /var/lib/pgsql/data/global/pg_fsm.cache 0666
file create /var/lib/pgsql/data/global/pg_auth.\$ 0666
file create /var/lib/pgsql/data/global/pg_database.\$ 0666
file rename /var/lib/pgsql/data/global/pg_auth.\$ /var/lib/pgsql/data/global/pg_auth
file rename /var/lib/pgsql/data/global/pg_database.\$ /var/lib/pgsql/data/global/pg_database
file unlink /var/lib/pgsql/data/base/\$/pg_internal.init
file write /var/lib/pgsql/data/global/pg_auth.\$
file write /var/lib/pgsql/data/global/pg_database.\$
network inet dgram send 127.0.0.1 1024-65535


#2010/12/30 00:22:26# profile=3 mode=enforcing granted=no (global-pid=11937) task={ pid=11937 ppid=1 uid=26 gid=26 euid=26 egid=26 suid=26 sgid=26 fsuid=26 fsgid=26 } path1={ uid=0 gid=0 ino=690602 major=253 minor=0 perm=0644 type=file } path1.parent={ uid=0 gid=0 ino=690114 perm=0755 }
<kernel> /etc/rc.d/init.d/postgresql /sbin/runuser /bin/bash /usr/bin/postmaster
file read /usr/share/zoneinfo/posix/Pacific/Pohnpei
Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy and retry):a
Enter new entry> file read /usr/share/zoneinfo/\{\*\}/\*
Added 'file read /usr/share/zoneinfo/\{\*\}/\*'.

----------------------------------------
#2010/12/30 00:22:23# profile=3 mode=enforcing granted=no (global-pid=11974) task={ pid=11974 ppid=11968 uid=0 gid=0 euid=0 egid=0 suid=0 sgid=0 fsuid=0 fsgid=0 } path1={ uid=0 gid=0 ino=524564 major=253 minor=0 perm=0644 type=file } path1.parent={ uid=0 gid=0 ino=524555 perm=0755 }
<kernel> /usr/sbin/sshd
file read /etc/pki/tls/openssl.cnf
Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy and retry):a
Enter new entry> file read /etc/pki/tls/openssl.cnf
Added 'file read /etc/pki/tls/openssl.cnf'.

----------------------------------------
#2010/12/30 00:22:53# profile=3 mode=enforcing granted=no (global-pid=11937) task={ pid=11937 ppid=1 uid=26 gid=26 euid=26 egid=26 suid=26 sgid=26 fsuid=26 fsgid=26 } path1.parent={ uid=26 gid=26 ino=426399 perm=0700 }
<kernel> /etc/rc.d/init.d/postgresql /sbin/runuser /bin/bash /usr/bin/postmaster
file create /var/lib/pgsql/data/pg_log/postgresql-Thu.log 0666
Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy and retry):a
Enter new entry> file create /var/lib/pgsql/data/pg_log/postgresql-\*
Added 'file create /var/lib/pgsql/data/pg_log/postgresql-\*.log 0666'.

#2010/12/30 00:23:04# profile=3 mode=enforcing granted=no (global-pid=11937) task={ pid=11937 ppid=1 uid=26 gid=26 euid=26 egid=26 suid=26 sgid=26 fsuid=26 fsgid=26 } path1={ uid=26 gid=26 ino=426434 major=253 minor=0 perm=0600 type=file } path1.parent={ uid=26 gid=26 ino=426399 perm=0700 }
<kernel> /etc/rc.d/init.d/postgresql /sbin/runuser /bin/bash /usr/bin/postmaster
file append /var/lib/pgsql/data/pg_log/postgresql-Thu.log
Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy and retry):a
Enter new entry> file append /var/lib/pgsql/data/pg_log/postgresql-\*
Added 'file append /var/lib/pgsql/data/pg_log/postgresql-\*.log'.

7.4. 全てのドメインに対して強制モードを有効にする

これまでに紹介してきた概念を理解しツールを使いこなせるようになれば、システム全体をアクセス制御の対象とするようなポリシーを作成することができることでしょう。全てのドメインを「強制モード」で運用すれば、システムの侵害へとつながるような弱点を減らすのに有効です。 Apache を制限する例で示した手順は、そのまま全てのドメインを制限するために使うことができます。

7.5. おわりに

このガイドのこの章までの内容は、 TOMOYO Linux を設定するのに十分な知識を提供することを狙っています。より深い知識を得るために、この先の章も読んでください。次の章から先は必ずしも不可欠とはいえない応用的な内容ですが、システムのセキュリティを高めるために役に立つことでしょう。このガイドの末尾にある付録、特に仕様についての解説は役に立つことでしょう。

セキュリティ対策が最も弱い場所を狙われるということを忘れないでください。 TOMOYO Linux が提供する強制アクセス制御機能を正しく使うことは、システムが侵害されることへの対策ではありますが、その他のシステムのセキュリティを高めるための手法や実践も忘れないでください。その他のシステムのセキュリティを高めるための手法や実践はこのガイドの対象外ですが、システムのセキュリティを最大限に高めたいと思うのならば真剣に取り組むようにしてください。