Chapter 5: How do I manage domains?
Each domain will behave differently and require a unique set of permissions. Their behaviour must therefore be analyzed to determine which actions you wish to permit in domain policy. TOMOYO Linux can be used to restrict only a subset of the domains in a system, but the most secure system would restrict every domain in order to make sure there are no points of vulnerability.
First, choose an application that you wish to analyze or protect. To demonstrate the procedure, this guide will use Apache in CentOS 5.
Start the target application:
# service httpd start
Run the policy editor again without the "/etc/ccs/" option so that the policy loaded by the kernel can be edited directly. If you are already running the policy editor, switch to the "Domain Transition Editor" screen.
In CentOS 5, the location of Apache is "/usr/sbin/httpd".
Scroll the cursor using arrow-keys and/or Home/End/PageUp/PageDown keys to find the line "/usr/sbin/httpd". In this picture, it is line 386:
/usr/sbin/httpd is invoked by "<kernel> /usr/sbin/mingetty /bin/login /bin/bash", then the domain name is "<kernel> /usr/sbin/mingetty /bin/login /bin/bash /usr/sbin/httpd".
You will notice that the picture above may look a little different to what you can see on your own screen. This is because the domain "<kernel> /usr/sbin/httpd" has been registered with the initialize_domain directive. Let's spend some time exploring the management of domains before we continue.
Advanced control of domain transition is possible with TOMOYO Linux, and involves changes to exception policy. The instructions in this section require use of the policy editor tool. To edit exception policy, run the policy editor and switch to the exception policy editor screen. To add an entry, press the "a" key, type out the new entry you wish to add and press "Enter". To see what other commands are available, press the "?" key.
When a unique execution occurs for application, a new domain is created. This allows for an application to receive different permissions depending on how it was executed (e.g. from an Xterm). However, it may be desirable to give the same permissions to an application without regard to how it was executed. This can simplify policy and make it easier to manage.
To do this, we need to enter a new entry into the exception policy. For example, you might add the following directive to exception policy:
initialize_domain /usr/sbin/sshd from any
Of course, "/usr/sbin/sshd" can be the full pathname of any application you wish to control domain transitions for. Having added this to exception policy, the application will now not create a new domain every time a unique execution occurs. Instead, it will reinitialize the domain to "<kernel> /usr/sbin/sshd":
The text "from any" included in the above directive signifies that the application domain should be reinitialized when invoked by any domain. It is possible to cause reinitialization to happen only when the application domain is invoked by a single specified domain. This is achieved by adding the following to exception policy:
initialize_domain /usr/sbin/sshd from <kernel> /etc/rc.d/init.d/sshd
It is also allowable to specify only the last part of the domain name instead of the whole domain name. For example, just "from /etc/rc.d/init.d/sshd" instead of "from <kernel> /etc/rc.d/init.d/sshd". This would of course be less specific a rule, and would for example still apply to the sshd daemon being run from a terminal.
If you switch back to the "Domain Transition Editor" screen, you may see domains with a "!" mark in the third column. This means that the domain is unreachable and can safely be deleted. The domain you have chosen to initialize to will appear with a "*" mark.
Note that any policy specified in the unreachable domains will not automatically carry over into the initialized domain. For now, we have not developed any policy yet so this is not a problem. If you use this directive later on for domains that you have already developed policy for, you will need to either re-learn policy or copy over policy to the initialized domain.
After using the initialize_domain rule, a situation may arise where you do not want an application to be reinitialized from a particular domain. For example, the application
/usr/sbin/sendmail.sendmail in order to send mails. Consider that the following has been added to exception policy:
initialize_domain /usr/sbin/sendmail.sendmail from any
For example, if you wish to have separate permissions for sending mail and receiving mail, you can add the following to exception policy:
no_initialize_domain /usr/sbin/sendmail.sendmail from /bin/mail
It may be preferable that any executed applications from a particular domain are suppressed from undergoing a domain transition. They therefore act within the permissions of the domain that has invoked it. For example, suppose you wish apply the same policy to all applications run within an ssh shell, you would add the following to exception policy:
keep_domain any from <kernel> /usr/sbin/sshd /bin/bash
Now the execution of any application, such as
/bin/cat will not result in the creation of a new domain. It will instead remain in the domain specified above and thus act within the permissions of that domain.
This could also be done for any shell instance by adding the following to exception policy:
keep_domain any from /bin/bash
This can be made even more specific, causing the suppression of domain transition only to occur when a specific application is executed from a specific domain. To do this, you could add the following to exception policy:
keep_domain /usr/bin/xargs from <kernel> /usr/sbin/sshd /bin/bash
The keep_domain directive does not take precedence over the initialize_domain directive. If the initialize_domain directive has been specified for a particular application, that application will leave any domain with the keep_domain directive and reinitialize into its own domain.
If you switch back to the "Domain Transition Editor" screen, you may see domains with a "!" mark in the third column. This means that the domain is unreachable and can safely be deleted. The domain that you have chosen to suppress domain transition from will appear with a "#" mark.
Note that any policy specified in the unreachable domains will not automatically be added to the parent domain (from which domain transition has been suppressed). For now, we have not developed any policy yet so this is not a problem. If you use this directive later on for domains that you have already developed policy for, you will need to either re-learn policy or copy over policy to the parent domain.
The keep_domain directive is useful in managing ssh login sessions as you cannot predict the commands the user will run and the order in which they will do so. However, there may be cases where you wish to resume domain transition, such as allowing access to password files when changing passwords or for restarting daemon services.
For example, if you wish to resume domain transition only for
/bin/cat, you could add the following to exception policy:
keep_domain any from <kernel> /usr/sbin/sshd /bin/bash no_keep_domain /bin/cat from <kernel> /usr/sbin/sshd /bin/bash
To continue with our target application, Apache, let's register it with the initialize_domain directive:
initialize_domain /usr/sbin/httpd from any
Now we can manage all instances of Apache from the "<kernel> /usr/sbin/httpd" domain. Any domains that appear with a "!" mark can be safely deleted as they are unreachable. To start developing policy for this domain, we need to switch it to "Learning Mode".
Press the "s" key, enter '1' and press the "Enter" key:
Now the profile number of the "/usr/sbin/httpd" domain has changed to 1:
Press the "@" key to switch to the process list. Verify that "/usr/sbin/httpd" processes are assigned profile number 1:
Restart the Apache in order to learn what permissions are required for starting/finishing the Apache:
# service httpd restart
Run the policy editor again and go to the "/usr/sbin/httpd" line. The line number may have changed due to the creation of new domains from executed programs.
Press the "Enter" key to browse the permissions that have been gathered:
This list was previously empty, but because the domain is in "Learning Mode", any new actions that occurred were appended to domain policy. This will continue until the domain is no longer placed in "Learning Mode". You can press the "r" key to refresh the screen.
Quit the editor and use Apache to generate necessary permissions for normal usage. All actions should be performed that you wish to allow:
Remember to save policy, as permissions are accumulated only in kernel memory. If the system is rebooted, the gathered permissions will be lost.
To save policy to disk, use the following command:
ccs-savepolicy, four files ("exception_policy.conf", "domain_policy.conf", "profile.conf", "manager.conf") are created in the "/etc/ccs/policy/YYYY-MM-DD.hh:mm:ss/" directory. ( YYYY-MM-DD.hh:mm:ss is current timestamp.)
To load the policy currently on the disk into the kernel, use the
# /usr/sbin/ccs-loadpolicy -df < /etc/ccs/domain_policy.conf # /usr/sbin/ccs-loadpolicy -ef < /etc/ccs/exception_policy.conf # /usr/sbin/ccs-loadpolicy -p < /etc/ccs/profile.conf # /usr/sbin/ccs-loadpolicy -m < /etc/ccs/manager.conf
The "-df" option means overwrite "/proc/ccs/domain_policy".
The "-ef" option means overwrite "/proc/ccs/exception_policy".
The "-p" option means append to "/proc/ccs/profile".
The "-m" option means append to "/proc/ccs/manager".
To make it harder for fatal mistakes to happen, "-pf" and "-mf" are not supported.
You might see warning messages like below printed on the console and the entry quota_exceeded appear in domain policy:
WARNING: Domain '<kernel> /usr/sbin/httpd' has too many ACLs to hold. Stopped learning mode.
This is a safeguard to prevent TOMOYO Linux from consuming all the memory available on the system. If "Learning Mode" did not have a limit, the system may become unusably slow due to comparison with already learned permissions. This limit can be increased with the max_learning_entry values in each of the profiles. However, care should be taken when increasing this value as this will require more memory. It is recommended to tune policy before increasing this value. Steps for tuning policy are described in the next chapter, and doing so can reduce the size of domain policy to become more manageable. You would then no longer need to increase the max_learning_entry value.
The configuration file "/etc/ccs/stat.conf" can be used to specify quotas for memory usage:
# Memory quota (byte). 0 means no quota. Memory used by policy: 0 Memory used by audit log: 16777216 Memory used by query message: 1048576
These settings can be loaded into kernel memory by running the following command:
ccs-loadpolicy -s < /etc/ccs/stat.conf
It is important to set a limit on the "Memory used by policy", as the creation of domains consumes kernel memory. If enough domains are created, the system will run out of memory and crash. If a limit is set, the creation of new domains can be stopped before the system crashes. At the end of this guide after you have set up a complete policy, view how much memory is being used by policy in the "Statistics" screen. Use this information to set an appropriate limit, such as 25% more than the current memory being used. If you make many additions to policy or create many additional domains, this limit should be changed appropriately.