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:
Press the "@" key to switch to the process list. Verify that the "/usr/sbin/httpd
" process and descendants are assigned profile number 3:
Quit the policy editor and try an operation which is permitted by policy:
The operation was successfully completed, as sending mail is permitted by policy.
Let's try an operation which is not permitted by policy:
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:
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 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 pathnames of files have changed
- The dependencies of files have changed
- The access permissions required have changed or increased
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.