tomoyotitle.png

Chapter 7: How do I enforce policy?

7.1. Enabling enforcing mode

Once domain and exception policy have been sufficiently modified, the domain can be set to enforcing mode.

Run the policy editor and change the target domains to profile 3:

editpolicy-httpd-profile3.png

Press the "@" key to switch to the process list. Verify that the "/usr/sbin/httpd" process and descendants are assigned profile number 3:

editpolicy-httpd-process3.png

Quit the policy editor and try an operation which is permitted by policy:

operation-permitted.png

The operation was successfully completed, as sending mail is permitted by policy.

Let's try an operation which is not permitted by policy:

unix-penguin.png

Although it appears to be have been completed successfully, the warning message by /bin/mail shows that the input was empty and so the execution of /bin/cat was rejected:

unix-penguin-rejected.png

Just like in "Permissive Mode", you can check the /proc/ccs/stat interface for how many times policy violations have occurred and the last time a policy violation occurred:

# cat /proc/ccs/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

If audit logs have been configured at 4.6. Saving audit logs (optional), rejected requests can be picked up from "/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 type!=execute_handler } 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 type!=execute_handler } 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

The first log reports that execution of /bin/cat was requested by /bin/sh, which was invoked by /usr/sbin/httpd. The command line argument at position 0, also referred to as argv[0], was "cat". The command line argument at position 1, also referred to as argv[1], was "/etc/passwd". As its first line has "mode=enforcing" and "granted=no", this request was rejected.

The second log reports that opening /bin/cat for reading requested by /bin/sh which was invoked by /usr/sbin/httpd. This was rejected because /bin/sh tried to open the requested program for reading when that program was not executed.

If the "Enforcing Mode" profile is configured with PREFERENCE={ enforcing_penalty=1 } then domains that violate policy will be made to sleep for 0.1 seconds. This is useful for avoiding infinite loops that can cause CPU usage to reach 100%. The video below demonstrates a hijacked Samba server process consuming CPU by repeating a request that is not permitted by policy:

7.2. Notification daemon

ccs-notifyd is a daemon program that can be used to report the occurrence of a policy violation. For example, run "/usr/sbin/ccs-notifyd" from "/etc/rc.local".

Configuration is specified in the "/etc/ccs/tools/notifyd.conf" file, as shown below:

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

# ccs-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 ccs-queryd command and
# responding to the policy violation event.
# If you specify non 0 value, you need to register ccs-notifyd command to
# /proc/ccs/manager as well as ccs-queryd command, for ccs-notifyd needs to
# behave as if ccs-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\040ccs-notifyd root@localhost
minimal_interval 60

Modify the "action_to_take" line as required and start ccs-notifyd.

This will send mails similar to the following (identical to audit logs, but with serial numbers in the header):

# 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 ccs-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 ccs-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 type!=execute_handler } 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. Handling policy violations in real-time

Policy violations can be handled in real time using ccs-queryd. This is especially useful during the installation of software updates. When packages are updated, policy may need to be altered if any of the following occur:

The ideal way to update policy is to rebuild from scratch using learning mode as has been described. However, it is not desirable to change a domain from enforcing mode to learning mode once the system has entered into a production state as this will cause the system to become vulnerable to attack through this unrestricted domain.

Fortunately, ccs-queryd can help administrators update policy in real-time while running in "Enforcing Mode". Please note that this method cannot always support every case and the resulting policy may not be fully optimized.

7.3.1. Example usage of "ccs-queryd"

The video below demonstrates example usage of ccs-queryd, which is summarised in the text below:

Use ccs-queryd to view, in realtime, the access requests that have been rejected by policy:

# /usr/sbin/ccs-queryd
Monitoring /proc/ccs/query . Press Ctrl-C to terminate.

Policy violations may occur while updating packages due to unusual behaviour (e.g. restarting daemons). When a policy violation occurs, a prompt appears in the ccs-queryd console:

#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 type!=execute_handler } 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):

This indicates that a process that belongs to the domain "<kernel> /etc/rc.d/init.d/sshd" attempted to execute /bin/sleep in order to process the command sleep 1. Usually this would be instantly denied, but since ccs-queryd is running, the kernel waits for the administrators decision before accepting or rejecting the request.

Press "Y" to grant the request.
Press "N" to reject the request.
Press "R" to retry the request (for example after editing domain policy manually).
Press "S" to show domain policy for the process.
Press "A" to append the request to domain policy and retry (a chance to edit the request is given first).

Do not grant access requests unconditionally. Policy violations are not always due to updating packages, but may be malicious requests by attackers.

Do not logout while this program is running. Access requests that violated policy are kept pending and may otherwise sleep forever. Monitor the output to make sure programs have the minimum permissions to run properly. If permissions are missing, they will be printed to the console output. Once policy has been updated, the program can be stopped with "Ctrl-C".

Note that this program directly edits policy currently loaded into the kernel, so run ccs-savepolicy to save policy to disk, otherwise policy will be lost on shutdown.

# /usr/sbin/ccs-savepolicy

7.3.2. Example output from "ccs-queryd"

This is an example of what the output might look like while running ccs-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 type!=execute_handler } 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 type!=execute_handler } 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
network inet dgram recv 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 type!=execute_handler } 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 type!=execute_handler } 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 type!=execute_handler } 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 type!=execute_handler } 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. Enable enforcing mode for every domain

Once you are familiar with the methods and tools described in the previous chapters, it will be possible to develop policy for every domain in the system. Placing every domain in "Enforcing Mode" will reduce the points of vulnerability through which a system might be compromised. Thus, all the previous steps should be repeated for all the other domains.

7.5. Beyond the core topics

The chapters in this guide so far aim to provide enough knowledge to set up TOMOYO Linux on a system. In order to further improve your knowledge, please read on. The following chapters cover advanced topics that are not absolutely essential, but can help to increase the security of a system. The appendices found at the end of this guide can also be very helpful, particularly the specification.

Remember that security is only as strong as the weakest point. While proper use of the Mandatory Access Control possible with TOMOYO Linux will strengthen a system against being compromised, other security practices and system-hardening methods must not be forgotten. These methods are beyond the scope of this guide but should be eagerly pursued by any who wish to maximize the security of their system.