CaitSith is an access restriction module for Linux systems. This module gives you ability to restrict access (e.g. opening files, executing programs) at the kernel level. This module is designed for ease of use.
1. Difference with TOMOYO (for existing TOMOYO users)
CaitSith was derived from TOMOYO Linux, but usage of CaitSith would be too different to imagine that CaitSith was derived from TOMOYO Linux. If you are already using TOMOYO Linux, please read the difference described below.
/proc/ccs/domain_policy , /proc/ccs/exception_policy , /proc/ccs/profile , /proc/ccs/manager and /proc/ccs/stat have been aggregated into /sys/kernel/security/caitsith/policy .
/etc/ccs/policy/current/domain_policy.conf , /etc/ccs/policy/current/exception_policy.conf , /etc/ccs/policy/current/profile.conf , /etc/ccs/policy/current/manager.conf and /etc/ccs/policy/current/stat.conf have been aggregated into /etc/caitsith/policy/current .
Built-in policy files which are located under kernel source directory as security/ccsecurity/policy/domain_policy.conf , security/ccsecurity/policy/exception_policy.conf , security/ccsecurity/policy/profile.conf , security/ccsecurity/policy/manager.conf and security/ccsecurity/policy/stat.conf have been aggregated into security/caitsith/policy/policy.conf .
Only /sbin/caitsith-init , /usr/sbin/caitsith-auditd , /usr/sbin/caitsith-loadpolicy , /usr/sbin/caitsith-notifyd , /usr/sbin/caitsith-pstree , /usr/sbin/caitsith-queryd , /usr/sbin/caitsith-savepolicy , /usr/lib64/caitsith/audit-exec-param , /usr/lib64/caitsith/caitsith-agent and /usr/lib64/caitsith/init_policy are provided for managing policy. (In other words, programs such as /usr/sbin/ccs-editpolicy and /usr/sbin/ccs-setprofile have been removed.)
Command line arguments for specifying type of policy to load/save have been removed from /usr/sbin/caitsith-loadpolicy and /usr/sbin/caitsith-savepolicy .
Command line arguments for specifying profile type have been removed from /usr/lib64/caitsith/init_policy .
Policy syntax has been drastically changed. TOMOYO Linux uses process's domainname as a key for grouping permissions to do some operations. In other words, TOMOYO Linux's policy is collection of "which domain can do ..." rules. On the other hand, CaitSith uses operation as a key for checking permission. In other words, CaitSith's policy is collection of "which operation can be done by ..." rules. This change is intended for allowing users to protect resources using denylisting approach. In CaitSith, process's domainname is nothing but one of optional parameters that can be used for controlling whether to allow or deny specific operations. Users can write rules without managing domainnames unless needed.
Process's domainname representation has changed from space delimited multiple words (e.g. "<kernel> /sbin/init /etc/rc.d/rc.sysinit") to a single word (e.g. "/sbin/init").
Domain transitions no longer happen unless explicitly specified by policy.
Distinction of disabled/learning/permissive/enforcing mode has been removed.
"path_group" keyword has been renamed to "string_group", and "address_group" keyword has been renamed to "ip_group".
Representation of \ character has been changed from \\ to \134.
Distinction between directory's pathname and non-directory's pathname has been removed by removing trailing / character from pathname.
A new wildcard /\(dir\)/ has been introduced for helping converting from (e.g.) "/tmp/\{\*\}/" to "/tmp/\(\*\)/\*", for directory's pathname (except the root directory itself) no longer ends with / character which previously matched /\{\*\}/ wildcard.
Category keywords (i.e. "file", "network", "ipc", "misc", "capability", "task") have been removed because access control levels which was specified using profile has been removed. Some of operation keywords have been renamed (e.g. "network inet stream connect" became "inet_stream_connect", "misc env" became "environ").
"task auto_execute_handler" keyword has been renamed to "handler=" argument of "execute" keyword. This is intended for using execute handler for preprocessing purpose when executing specific programs rather than when executing from specific domains. "task denied_execute_handler" keyword has been removed.
Domain argument has been removed from permission to send signals (i.e. "signal" directive), for kill() system call accepts negative number for specifying multiple processes. It is impossible to selectively deny sending signals because it is not permitted to sleep while sending signals.
Restriction granularity for ptrace operation has changed from boolean (i.e. "capability SYS_PTRACE") to command number + domainname.
Restriction granularity for environment variables has changed from name only to both name and values.
Several variables for referencing file's attributes have been added.
Local port reserve functionality (i.e. "deny_autobind" keyword) has been removed.
Presentation slides which I used at LinuxCon North America 2012 that explain why CaitSith was developed are available.
CaitSith supports Linux kernel 2.6.27 and later.
There are two ways to compile CaitSith kernel module. Please choose one, but please accept that you need to choose fully featured version if you can't choose LKM-based LSM version.
LKM-based LSM version | fully featured version | |
Advantages | No need to replace kernel package. | Complete functionality and syntax are supported. |
Disadvantages | Supported functionality and syntax depend on kernel's version and kernel's configuration options. | Need to replace kernel package. |
Dependency |
Kernel package must be built with below configuration options.
| Requires patching against kernel's source and rebuilding from source. |
These packages are required for compiling the kernel module and the userspace tools:
These can be installed with the following commands:
RedHat distributions
# yum -y install wget gcc make ncurses-devel
Debian distributions
# apt-get -y install wget gcc make libncurses-dev
SUSE distributions
# yast -i wget gcc make ncurses-devel
Install the kernel development package and go to the directory that it has installed into:
RedHat distributions
# VERSION=$(uname -r) # yum -y install kernel-devel-${VERSION} # cd /usr/src/kernels/${VERSION}*/
Debian distributions
# VERSION=$(uname -r) # apt-get -y install linux-headers-${VERSION} # cd /usr/src/linux-headers-${VERSION}/
SUSE distributions
# VERSION=$(uname -r) # yast -i kernel-devel # cd /lib/modules/${VERSION}/build/
Run the following commands in order to extract source code of CaitSith:
# wget https://sourceforge.net/projects/tomoyo/files/caitsith-patch/0.2/caitsith-patch-0.2-20250415.tar.gz # wget https://sourceforge.net/projects/tomoyo/files/caitsith-patch/0.2/caitsith-patch-0.2-20250415.tar.gz.asc # wget https://tomoyo.sourceforge.net/kumaneko-key # gpg --import kumaneko-key # gpg caitsith-patch-0.2-20250415.tar.gz.asc # tar -zxf caitsith-patch-0.2-20250415.tar.gz
On systemd environments, /usr/lib/systemd/systemd will be executed rather than /sbin/init . If your system is using systemd, please edit CONFIG_CAITSITH_ACTIVATION_TRIGGER line in caitsith/config.h like below unless you choose Loading CaitSith's module from the init process:
Before:
#define CONFIG_CAITSITH_ACTIVATION_TRIGGER "/sbin/init"
After:
#define CONFIG_CAITSITH_ACTIVATION_TRIGGER "/usr/lib/systemd/systemd"
There are two types of CaitSith's policy configuration. The former is embedded into the kernel and the latter is saved as files on the filesystems (e.g. /etc/caitsith/ directory). You will need to rebuild the CaitSith kernel module whenever updating the former, but allows you to load policy without using userspace policy loader (e.g. /sbin/caitsith-init ). The latter is loaded by executing userspace policy loader when the access control by CaitSith is about to be activated (e.g. when /sbin/init or /usr/lib/systemd/systemd starts).
If you want to activate CaitSith as soon as the kernel module is loaded, you can define CONFIG_CAITSITH_OMIT_USERSPACE_LOADER line in caitsith/config.h like below. (But be sure to supply built-in policy configuration located at caitsith/policy/ directory if you define CONFIG_CAITSITH_OMIT_USERSPACE_LOADER, or the system will panic as soon as the kernel module is loaded.):
Before:
//#define CONFIG_CAITSITH_OMIT_USERSPACE_LOADER
After:
#define CONFIG_CAITSITH_OMIT_USERSPACE_LOADER
Run the following commands in order to build and install CaitSith:
# make SUBDIRS=$PWD/caitsith modules # make SUBDIRS=$PWD/caitsith modules_install # depmod ${VERSION}
If you encountered one of errors listed below, you cannot use CaitSith for your kernel. Please jump to 2.2. How to install fully featured version. For other errors, please contact the author ( penguin-kernel@I-love.SAKURA.ne.jp ).
You must choose CONFIG_SECURITY=y for building this module. You must choose CONFIG_KALLSYMS=y for building this module. You must choose CONFIG_PROC_FS=y for building this module. You must choose CONFIG_MODULES=y for building this module.
Since registering CaitSith module depends on your environment, you might encounter problems. Therefore, I recommend you to confirm that CaitSith module can be loaded at this step.
Run the following commands in order to try to load caitsith_test.ko module:
# dmesg -c > /dev/null # modprobe caitsith_test # dmesg
caitsith_test: module verification failed: signature and/or required key missing - tainting kernel security_ops=ffffffff81df6c80 find_task_by_vpid=ffffffff810821a0 find_task_by_pid_ns=ffffffff81082170 d_absolute_path=ffffffff811c8f10 All dependent symbols have been guessed. Please verify these addresses using System.map for this kernel (e.g. /boot/System.map-`uname -r` ). If these addresses are correct, you can try loading CaitSith module on this kernel.
If caitsith_test.ko was loaded successfully, guessed addresses like above are printed. Therefore, please compare guessed addresses from caitsith_test.ko and actual addresses from System.map file. (Number of symbols and addresses printed depends on your environment.):
# for i in ffffffff81df6c80 ffffffff810821a0 ffffffff81082170 ffffffff811c8f10; do grep $i /boot/System.map-${VERSION}; done
ffffffff81df6c80 b security_ops ffffffff810821a0 T find_task_by_vpid ffffffff81082170 T find_task_by_pid_ns ffffffff811c8f10 T d_absolute_path
Please proceed if these addresses are correct.
You might find some gap between guessed addresses from caitsith_test.ko and actual addresses from System.map file (like some examples shown below) if your kernel configuration uses CONFIG_RANDOMIZE_BASE=y. In this case, although guessed addresses will randomly change for every reboot, please proceed as long as the gap between guessed address and actual address is same for all guessed symbols. Otherwise, please contact the author since CaitSith module will not work even if you continue.
# for i in security_hook_heads find_task_by_vpid find_task_by_pid_ns d_absolute_path; do grep $i /boot/System.map-${VERSION}; done
ffffffff81cdac40 D security_hook_heads ffffffff810b50a0 T find_task_by_vpid ffffffff810b5030 T find_task_by_pid_ns ffffffff812789f0 T d_absolute_path
security_hook_heads=ffffffffa2cdac40 find_task_by_vpid=ffffffffa20b50a0 find_task_by_pid_ns=ffffffffa20b5030 d_absolute_path=ffffffffa22789f0
security_hook_heads=ffffffff8acdac40 find_task_by_vpid=ffffffff8a0b50a0 find_task_by_pid_ns=ffffffff8a0b5030 d_absolute_path=ffffffff8a2789f0
security_hook_heads=ffffffffb0cdac40 find_task_by_vpid=ffffffffb00b50a0 find_task_by_pid_ns=ffffffffb00b5030 d_absolute_path=ffffffffb02789f0
If caitsith_test.ko was not loaded successfully, error messages like below are printed. In this case, please contact the author since CaitSith module will not work even if you continue:
# dmesg -c > /dev/null # modprobe caitsith_test
FATAL: Error inserting caitsith_test (/lib/modules/2.6.32/extra/caitsith_test.ko): Invalid argument
# dmesg
Sorry, I couldn't guess dependent symbols. I need some changes for supporting your environment. Please contact the author.
If your kernel has /proc/sys/kernel/kptr_restrict sysctl parameter set to 2, loading of caitsith_test.ko will fail. In this case, please set /proc/sys/kernel/kptr_restrict to 0 before loading and restore /proc/sys/kernel/kptr_restrict to 2 after loading.
# dmesg -c > /dev/null # echo 0 > /proc/sys/kernel/kptr_restrict # modprobe caitsith_test # echo 2 > /proc/sys/kernel/kptr_restrict
Make sure the dependencies described above have been installed. Compile and install the tools with the following commands. (Please use USRLIBDIR=/usr/lib or USRLIBDIR=/usr/lib32 if needed):
$ wget https://sourceforge.net/projects/tomoyo/files/caitsith-tools/0.2/caitsith-tools-0.2-20241111.tar.gz $ wget https://sourceforge.net/projects/tomoyo/files/caitsith-tools/0.2/caitsith-tools-0.2-20241111.tar.gz.asc $ gpg caitsith-tools-0.2-20241111.tar.gz.asc $ tar -zxf caitsith-tools-0.2-20241111.tar.gz $ cd caitsith-tools/ $ make -s USRLIBDIR=/usr/lib64 $ su # make -s USRLIBDIR=/usr/lib64 install
Programs listed below are main userspace tools used for administrating CaitSith.
FYI: If your system has rpm-build package installed, you can make a tools RPM package with the following commands:
$ rpmbuild -tb caitsith-tools-0.2-20241111.tar.gz
Before you can make use of CaitSith, an initialization procedure must take place. This prepares the files in which policy information will be stored. All policy files are stored in the "/etc/caitsith/" directory.
Run the following command as root user to initialize. (Please use /usr/lib/caitsith/init_policy or /usr/lib32/caitsith/init_policy if needed):
# /usr/lib64/caitsith/init_policy
Creating policy directory... OK Creating configuration directory... OK Creating default policy... OK. Creating module loader... OK. Creating configuration file for caitsith-auditd ... OK. Creating configuration file for caitsith-notifyd ... OK.
CaitSith can generate audit logs and allows you to read them via /sys/kernel/security/caitsith/audit interface. To save /sys/kernel/security/caitsith/audit automatically, start /usr/sbin/caitsith-auditd from somewhere. Default setting (specified in /etc/caitsith/tools/auditd.conf ) sends access allowed logs to /dev/null , access unmatched logs to /var/log/caitsith/unmatched.log , access denied logs to /var/log/caitsith/denied.log . (The meaning and example of allowed/unmatched/denied will be explained in Example of simple access restriction rule.)
CaitSith can ask for your decision about access requests which will be denied unless you allow them via /sys/kernel/security/caitsith/query interface. To notify immediately the occurrence of access requests which CaitSith is about to deny, start /usr/sbin/caitsith-notifyd from somewhere. Default setting (specified in /etc/caitsith/tools/notifyd.conf ) sends mails to root@localhost with subject "Notification from caitsith-notifyd" up to once per a minute.
Below example launches /usr/sbin/caitsith-auditd and /usr/sbin/caitsith-notifyd from /etc/rc.d/rc.local script:
#!/bin/bash # THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES # # It is highly advisable to create own systemd services or udev rules # to run scripts during boot instead of using this file. # # In contrast to previous versions due to parallel execution during boot # this script will NOT be run after all other services. # # Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure # that this script will be executed during boot. touch /var/lock/subsys/local /usr/sbin/caitsith-auditd /usr/sbin/caitsith-notifyd
On systems where use of init= kernel boot option causes boot failures (e.g. earlier versions of RHEL 7), you need to choose Loading CaitSith's module from initramfs. On systems where it does not cause boot failures (e.g. RHEL 6), you can choose Loading CaitSith's module from the init process.
This section assumes that you are using dracut and GRUB2.
Create /etc/dracut.conf.d/caitsith.conf like below and rebuild the initramfs:
# echo 'add_drivers+=" caitsith "' > /etc/dracut.conf.d/caitsith.conf # dracut -f
Edit your bootloader to add "rd.driver.pre=caitsith" to the kernel boot options. An example is shown below:
Before:
linux16 /boot/vmlinuz-3.10.0-123.9.3.el7.x86_64 ro root=LABEL=/
After:
linux16 /boot/vmlinuz-3.10.0-123.9.3.el7.x86_64 ro root=LABEL=/ rd.driver.pre=caitsith
It is recommended that you also modify GRUB_CMDLINE_LINUX line in /etc/default/grub file like below in case you update kernel packages in the future:
Before:
GRUB_CMDLINE_LINUX="vconsole.keymap=us crashkernel=auto vconsole.font=latarcyrheb-sun16 rhgb quiet"
After:
GRUB_CMDLINE_LINUX="vconsole.keymap=us crashkernel=auto vconsole.font=latarcyrheb-sun16 rhgb quiet rd.driver.pre=caitsith"
Edit your bootloader (e.g. GRUB) to add "init=/sbin/caitsith-init" to the kernel boot options. An example is shown below:
Before:
kernel /boot/vmlinuz-2.6.32-431.17.1.el6.x86_64 ro root=LABEL=/
After:
kernel /boot/vmlinuz-2.6.32-431.17.1.el6.x86_64 ro root=LABEL=/ init=/sbin/caitsith-init
Now you have finished all preparation. Reboot your system.
If everything was installed properly and the bootloader was correctly configured, the kernel should boot as normal and CaitSith should be activated:
Note that you won't be able to see CaitSith's messages if you are using "quiet" or "rhgb" kernel boot option because these options prevent most of kernel messages from being printed.
Although CaitSith is a LSM module, CaitSith can coexist with other LSM modules. However, you need to also add "selinux=0" to the kernel boot options if you disable SELinux by specifying SELINUX=disabled in /etc/selinux/config . This is because the init process unregisters LSM hooks which CaitSith module depends on if SELINUX=disabled is specified in /etc/selinux/config .
If your system becomes unable to boot during the course of this guide or any time in the future, it may be due to policy configuration or something related to CaitSith. If this is the case, it is possible that the kernel can still be booted by disabling CaitSith. This can be done by removing "rd.driver.pre=caitsith" or "init=/sbin/caitsith-init" from the kernel boot options.
CaitSith fortunately does not require the modification of any existing Linux binaries, libraries or applications. Thus, uninstalling CaitSith is very easy. It is simply a matter of removing "rd.driver.pre=caitsith" or "init=/sbin/caitsith-init" from the kernel boot options and uninstalling the userspace tools that you installed above.
These packages are required for compiling the kernel and the userspace tools:
These can be installed with the following commands:
RedHat distributions
# yum -y install wget patch gcc make ncurses-devel
Debian distributions
# apt-get -y install wget patch gcc make libncurses-dev
SUSE distributions
# yast -i wget patch gcc make ncurses-devel
Download the kernel source from linux-2.6 or linux-3 or linux-4 or linux-5 or linux-6.
Linux kernel 2.6.27 and later are supported from the linux-2.6 tree.
Linux kernel 3.0 and later are supported from the linux-3 tree.
Linux kernel 4.0 and later are supported from the linux-4 tree.
Linux kernel 5.0 and later are supported from the linux-5 tree.
Linux kernel 6.0 and later are supported from the linux-6 tree.
Extract the kernel source and go to the extracted directory.
In the operations below, "$VERSION" should be replaced with appropriate kernel version. For example "6.1" if using Linux kernel 6.1.1, "2.6.27" if using Linux kernel 2.6.27.62.
Also, there are several patches which can be applied to distributor's latest kernels. For example "3.10-centos-7" if using CentOS 7's latest kernel:
$ wget https://sourceforge.net/projects/tomoyo/files/caitsith-patch/0.2/caitsith-patch-0.2-20250415.tar.gz $ wget https://sourceforge.net/projects/tomoyo/files/caitsith-patch/0.2/caitsith-patch-0.2-20250415.tar.gz.asc $ wget https://tomoyo.sourceforge.net/kumaneko-key $ gpg --import kumaneko-key $ gpg caitsith-patch-0.2-20250415.tar.gz.asc $ tar -zxf caitsith-patch-0.2-20250415.tar.gz $ sed -i -e 's/CCSECURITY/CAITSITH/g' -e 's/ccsecurity/caitsith/g' -e 's/ccs_domain_info/cs_domain_info/g' -e 's/ccs_flags/cs_flags/g' -- patches/ccs-patch-*.diff $ patch -sp1 < patches/ccs-patch-$VERSION.diff
$ make -s menuconfig
Choose the following options in "Security options" section:
"Compile as loadable kernel module" is useful when there is a file size limitation for vmlinux (e.g. embedded systems).
"Disable by default" will enable CaitSith only when "caitsith=on" is passed to the kernel boot options. If this option is not selected, "caitsith=off" will disable CaitSith.
"Do not modify 'struct task_struct' in order to keep KABI" will manage "struct task_struct" variables outside "struct task_struct" in order to avoid Kernel Application Binary Interface (KABI) breakage. Choose this option if wanting to patch against distributor's kernels without breaking KABI. However, since "struct caitsith_operations" must be exported to loadable kernel modules (LKMs) in order to allow them to call CaitSith's functions, build scripts may still print warning messages.
There are two types of CaitSith's policy configuration. The former is embedded into the kernel and the latter is saved as files on the filesystems (e.g. /etc/caitsith/ directory). You will need to rebuild the kernel whenever updating the former, but allows you to load policy without using userspace policy loader (e.g. /sbin/caitsith-init). The latter is loaded by executing userspace policy loader when the access control by CaitSith is about to be activated (e.g. when /sbin/init or /usr/lib/systemd/systemd starts). "Activate without calling userspace policy loader." allows you to activate access control by CaitSith as soon as the former is loaded. This option is useful when it is difficult to call policy loader (e.g. embedded systems).
"Location of userspace policy loader" is available only when "Activate without calling userspace policy loader." is not selected. This option specifies the default pathname of the userspace policy loader. You can override this setting via the "CS_loader=" kernel boot option.
"Trigger for calling userspace policy loader" is available only when "Activate without calling userspace policy loader." is not selected. This option specifies the default pathname of the activation trigger. You can override this setting via the "CS_trigger=" kernel boot option. For example, if you pass "init=/usr/lib/systemd/systemd" option, you may also want to pass "CS_trigger=/usr/lib/systemd/systemd" option.
The policy configuration which will be embedded into the kernel needs to exist as security/caitsith/policy/policy.conf . But you can proceed without creating that file because you don't have the policy configuration to embed as of this step. (You may come back here after you developed policy configuration to embed.)
Once the kernel has been configured, compile and install the kernel with the following commands:
$ make -s $ su # make -s modules_install install
Create initrd/initramfs if required.
Make sure the dependencies described above have been installed. Compile and install the tools with the following commands. (Please use USRLIBDIR=/usr/lib or USRLIBDIR=/usr/lib32 if needed):
$ wget https://sourceforge.net/projects/tomoyo/files/caitsith-tools/0.2/caitsith-tools-0.2-20241111.tar.gz $ wget https://sourceforge.net/projects/tomoyo/files/caitsith-tools/0.2/caitsith-tools-0.2-20241111.tar.gz.asc $ gpg caitsith-tools-0.2-20241111.tar.gz.asc $ tar -zxf caitsith-tools-0.2-20241111.tar.gz $ cd caitsith-tools/ $ make -s USRLIBDIR=/usr/lib64 $ su # make -s USRLIBDIR=/usr/lib64 install
Programs listed below are main userspace tools used for administrating CaitSith.
FYI: If your system has rpm-build package installed, you can make a tools RPM package with the following commands:
$ rpmbuild -tb caitsith-tools-0.2-20241111.tar.gz
Before you can make use of CaitSith, an initialization procedure must take place. This prepares the files in which policy information will be stored. All policy files are stored in the "/etc/caitsith/" directory.
Run the following command as root user to initialize. (Please use /usr/lib/caitsith/init_policy or /usr/lib32/caitsith/init_policy if needed):
# /usr/lib64/caitsith/init_policy
Creating policy directory... OK Creating configuration directory... OK Creating default policy... OK. Creating module loader... OK. Creating configuration file for caitsith-auditd ... OK. Creating configuration file for caitsith-notifyd ... OK.
CaitSith can generate audit logs and allows you to read them via /sys/kernel/security/caitsith/audit interface. To save /sys/kernel/security/caitsith/audit automatically, start /usr/sbin/caitsith-auditd from somewhere. Default setting (specified in /etc/caitsith/tools/auditd.conf ) sends access allowed logs to /dev/null , access unmatched logs to /var/log/caitsith/unmatched.log , access denied logs to /var/log/caitsith/denied.log . (The meaning and example of allowed/unmatched/denied will be explained in Example of simple access restriction rule.)
CaitSith can ask for your decision about access requests which will be denied unless you allow them via /sys/kernel/security/caitsith/query interface. To notify immediately the occurrence of access requests which CaitSith is about to deny, start /usr/sbin/caitsith-notifyd from somewhere. Default setting (specified in /etc/caitsith/tools/notifyd.conf ) sends mails to root@localhost with subject "Notification from caitsith-notifyd" up to once per a minute.
Below example launches /usr/sbin/caitsith-auditd and /usr/sbin/caitsith-notifyd from /etc/rc.d/rc.local script:
#!/bin/bash # THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES # # It is highly advisable to create own systemd services or udev rules # to run scripts during boot instead of using this file. # # In contrast to previous versions due to parallel execution during boot # this script will NOT be run after all other services. # # Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure # that this script will be executed during boot. touch /var/lock/subsys/local /usr/sbin/caitsith-auditd /usr/sbin/caitsith-notifyd
Edit your bootloader (e.g. GRUB) to include the kernel you have just compiled. If the "Disable by default" option was selected during kernel configuration, remember to include "caitsith=on" in the kernel boot options. Consult the documentation for your distribution and bootloader to find out how to include your CaitSith kernel.
Now you have finished all preparation. Reboot your system.
If everything was installed properly and the bootloader was correctly configured, the kernel should boot as normal and CaitSith should be activated:
Note that you won't be able to see CaitSith's messages if you are using "quiet" or "rhgb" kernel boot option because these options prevent most of kernel messages from being printed.
If your system becomes unable to boot during the course of this guide or any time in the future, it may be due to policy configuration or something related to CaitSith. If this is the case, it is possible that the kernel can still be booted by disabling CaitSith. This can be done by appending "caitsith=off" to the kernel boot options.
CaitSith fortunately does not require the modification of any existing Linux binaries, libraries or applications. Thus, uninstalling CaitSith is very easy. It is simply a matter of uninstalling the kernel and userspace tools that you installed above. You can reboot with the kernel provided by your distribution and then remove the entry from your bootloader.
CaitSith's policy file consists with "Header part" and "ACL part".
Header part consists with below lines.
POLICY_VERSION=20120401 stat $stat_name $stat_value quota memory policy $max_byte_for_policy quota memory audit $max_byte_for_audit_logs quota memory query $max_byte_for_query quota audit[$audit_index] allowed=$max_logs_for_allowed_request denied=$max_logs_for_denied_request unmatched=$max_logs_for_unmatched_request string_group $string_group_name $string_group_member number_group $number_group_name $number_group_member ip_group $ip_group_name $ip_group_member
ACL part consists with 0 or more repetitions of below block.
$acl_priority acl $operation $conditions_to_filter audit $audit_index $cond_priority $decision $conditions_to_allow_or_deny
$decision lines in a block is evaluated only when the block's $acl_priority line matched.
Checking of $decision lines in a block lasts until it matches a $decision line or it reaches to the end of block.
Access requests will be denied only when "deny" line of "acl" block matched. (There are two exceptions. Regarding permission to change domains manually (i.e. acl manual_domain_transition blocks) and permission to change domains automatically (i.e. acl auto_domain_transition blocks), access requests will be granted only when "allow" line of all blocks match, in order to avoid unintended domain transition.)
$acl_priority and $cond_priority values are used for two purposes. One is for selectively deny operations using "deny" lines. For example,
10 acl read path.fsmagic=0x9FA0 audit 0 10 deny path="proc:/cmdline" 20 allow
denies opening /proc/cmdline on the proc filesystem (proc filesystem's magic number is 0x9FA0) for reading while allowing opening all other files.
The other is for controlling which "transition=" and "handler=" arguments should be used when these arguments matched more than once. This will be explained in advanced usage.
Below is an example of /etc/caitsith/policy/current file on CentOS. The content of this file varies depending on environments you are using, and will be updated as you develop policy.
POLICY_VERSION=20120401 quota memory audit 16777216 quota memory query 1048576 quota audit[1] allowed=0 denied=1024 unmatched=1024 10000 acl execute audit 0 10 allow path="/sbin/modprobe" transition="/sbin/modprobe" 10 allow path="/sbin/init" transition="/sbin/init" 10 allow path="/sbin/mingetty" transition="/sbin/mingetty" 10 allow path="/sbin/udevd" transition="/sbin/udevd" 10 allow path="/usr/sbin/anacron" transition="/usr/sbin/anacron" 10 allow path="/usr/sbin/crond" transition="/usr/sbin/crond" 10 allow path="/usr/sbin/httpd" transition="/usr/sbin/httpd" 10 allow path="/usr/sbin/logrotate" transition="/usr/sbin/logrotate" 10 allow path="/usr/sbin/nmbd" transition="/usr/sbin/nmbd" 10 allow path="/usr/sbin/smbd" transition="/usr/sbin/smbd" 10 allow path="/usr/sbin/sshd" transition="/usr/sbin/sshd" 10 allow path="/etc/rc.d/init.d/ntpd" transition="/etc/rc.d/init.d/ntpd" 10 allow path="/etc/rc.d/init.d/single" transition="/etc/rc.d/init.d/single" 10 allow path="/etc/rc.d/init.d/killall" transition="/etc/rc.d/init.d/killall" 10 allow path="/etc/rc.d/init.d/ip6tables" transition="/etc/rc.d/init.d/ip6tables" 10 allow path="/etc/rc.d/init.d/halt" transition="/etc/rc.d/init.d/halt" 10 allow path="/etc/rc.d/init.d/netfs" transition="/etc/rc.d/init.d/netfs" 10 allow path="/etc/rc.d/init.d/messagebus" transition="/etc/rc.d/init.d/messagebus" 10 allow path="/etc/rc.d/init.d/sandbox" transition="/etc/rc.d/init.d/sandbox" 10 allow path="/etc/rc.d/init.d/rsyslog" transition="/etc/rc.d/init.d/rsyslog" 10 allow path="/etc/rc.d/init.d/smb" transition="/etc/rc.d/init.d/smb" 10 allow path="/etc/rc.d/init.d/sshd" transition="/etc/rc.d/init.d/sshd" 10 allow path="/etc/rc.d/init.d/cgconfig" transition="/etc/rc.d/init.d/cgconfig" 10 allow path="/etc/rc.d/init.d/udev-post" transition="/etc/rc.d/init.d/udev-post" 10 allow path="/etc/rc.d/init.d/firstboot" transition="/etc/rc.d/init.d/firstboot" 10 allow path="/etc/rc.d/init.d/ntpdate" transition="/etc/rc.d/init.d/ntpdate" 10 allow path="/etc/rc.d/init.d/crond" transition="/etc/rc.d/init.d/crond" 10 allow path="/etc/rc.d/init.d/restorecond" transition="/etc/rc.d/init.d/restorecond" 10 allow path="/etc/rc.d/init.d/httpd" transition="/etc/rc.d/init.d/httpd" 10 allow path="/etc/rc.d/init.d/rdisc" transition="/etc/rc.d/init.d/rdisc" 10 allow path="/etc/rc.d/init.d/postfix" transition="/etc/rc.d/init.d/postfix" 10 allow path="/etc/rc.d/init.d/saslauthd" transition="/etc/rc.d/init.d/saslauthd" 10 allow path="/etc/rc.d/init.d/netconsole" transition="/etc/rc.d/init.d/netconsole" 10 allow path="/etc/rc.d/init.d/network" transition="/etc/rc.d/init.d/network" 10 allow path="/etc/rc.d/init.d/avahi-daemon" transition="/etc/rc.d/init.d/avahi-daemon" 10 allow path="/etc/rc.d/init.d/auditd" transition="/etc/rc.d/init.d/auditd" 10 allow path="/etc/rc.d/init.d/nmb" transition="/etc/rc.d/init.d/nmb" 10 allow path="/etc/rc.d/init.d/iptables" transition="/etc/rc.d/init.d/iptables" 10 allow path="/etc/rc.d/init.d/cgred" transition="/etc/rc.d/init.d/cgred" 0 acl modify_policy audit 1 1 deny task.uid!=0 1 deny task.euid!=0 100 allow task.exe="/usr/sbin/caitsith-loadpolicy" 100 allow task.exe="/usr/sbin/caitsith-queryd" 10000 deny
There are two ways to update policy configuration.
One is to use /sbin/caitsith-init which is automatically called when /sbin/init starts. /sbin/caitsith-init reads policy from /etc/caitsith/policy/current and writes to /sys/kernel/security/caitsith/policy interface. Therefore, you can update policy configuration by updating /etc/caitsith/policy/current and rebooting your system.
The other is to use /usr/sbin/caitsith-loadpolicy which is defined for loading policy after your system has booted. /usr/sbin/caitsith-loadpolicy reads policy from standard input and writes to /sys/kernel/security/caitsith/policy interface. Therefore, you can update policy configuration without updating /etc/caitsith/policy/current and rebooting your system. For example, if you want to append a "string_group mygroup1 /" line to /sys/kernel/security/caitsith/policy interface, run below command:
# echo 'string_group mygroup1 /' | /usr/sbin/caitsith-loadpolicy
If you want to delete the "string_group mygroup1 /" line from /sys/kernel/security/caitsith/policy interface, run below command:
# echo 'delete string_group mygroup1 /' | /usr/sbin/caitsith-loadpolicy
The contents in /sys/kernel/security/caitsith/policy will be lost when your system shuts down or reboots. To save /sys/kernel/security/caitsith/policy as /etc/caitsith/policy/current , run below command:
# /usr/sbin/caitsith-savepolicy
Let's experience how CaitSith restricts access using simple examples.
By default, CaitSith does not deny access requests. To restrict access requests, you need to tell CaitSith which access requests should be denied.
Below rule will check access requests which open /tmp/file1 for reading.
100 acl read path="/tmp/file1" audit 1
Append above rule using /usr/sbin/caitsith-loadpolicy . Since /usr/sbin/caitsith-loadpolicy reads policy from standard input, you can use ^D (Ctrl-D) to indicate end of input:
# /usr/sbin/caitsith-loadpolicy
100 acl read path="/tmp/file1" audit 1 ^D
You may use a temporary file if you worry typos.
# cat > ~/policy.tmp
100 acl read path="/tmp/file1" audit 1 ^D
# /usr/sbin/caitsith-loadpolicy < ~/policy.tmp # rm ~/policy.tmp
You can confirm that above rule is appended to /sys/kernel/security/caitsith/policy by reading /sys/kernel/security/caitsith/policy .
# cat /sys/kernel/security/caitsith/policy
POLICY_VERSION=20120401 stat Policy updated: 7 (Last: 2012/04/08 04:56:45) stat Requests denied: 0 stat Memory used by policy: 6048 stat Memory used by audit: 0 stat Memory used by query: 0 quota memory audit 16777216 quota memory query 1048576 quota audit[1] allowed=0 denied=1024 unmatched=1024 10000 acl execute audit 0 10 allow path="/sbin/modprobe" transition="/sbin/modprobe" 10 allow path="/sbin/init" transition="/sbin/init" 10 allow path="/sbin/mingetty" transition="/sbin/mingetty" 10 allow path="/sbin/udevd" transition="/sbin/udevd" 10 allow path="/usr/sbin/anacron" transition="/usr/sbin/anacron" 10 allow path="/usr/sbin/crond" transition="/usr/sbin/crond" 10 allow path="/usr/sbin/httpd" transition="/usr/sbin/httpd" 10 allow path="/usr/sbin/logrotate" transition="/usr/sbin/logrotate" 10 allow path="/usr/sbin/nmbd" transition="/usr/sbin/nmbd" 10 allow path="/usr/sbin/smbd" transition="/usr/sbin/smbd" 10 allow path="/usr/sbin/sshd" transition="/usr/sbin/sshd" 10 allow path="/etc/rc.d/init.d/ntpd" transition="/etc/rc.d/init.d/ntpd" 10 allow path="/etc/rc.d/init.d/single" transition="/etc/rc.d/init.d/single" 10 allow path="/etc/rc.d/init.d/killall" transition="/etc/rc.d/init.d/killall" 10 allow path="/etc/rc.d/init.d/ip6tables" transition="/etc/rc.d/init.d/ip6tables" 10 allow path="/etc/rc.d/init.d/halt" transition="/etc/rc.d/init.d/halt" 10 allow path="/etc/rc.d/init.d/netfs" transition="/etc/rc.d/init.d/netfs" 10 allow path="/etc/rc.d/init.d/messagebus" transition="/etc/rc.d/init.d/messagebus" 10 allow path="/etc/rc.d/init.d/sandbox" transition="/etc/rc.d/init.d/sandbox" 10 allow path="/etc/rc.d/init.d/rsyslog" transition="/etc/rc.d/init.d/rsyslog" 10 allow path="/etc/rc.d/init.d/smb" transition="/etc/rc.d/init.d/smb" 10 allow path="/etc/rc.d/init.d/sshd" transition="/etc/rc.d/init.d/sshd" 10 allow path="/etc/rc.d/init.d/cgconfig" transition="/etc/rc.d/init.d/cgconfig" 10 allow path="/etc/rc.d/init.d/udev-post" transition="/etc/rc.d/init.d/udev-post" 10 allow path="/etc/rc.d/init.d/firstboot" transition="/etc/rc.d/init.d/firstboot" 10 allow path="/etc/rc.d/init.d/ntpdate" transition="/etc/rc.d/init.d/ntpdate" 10 allow path="/etc/rc.d/init.d/crond" transition="/etc/rc.d/init.d/crond" 10 allow path="/etc/rc.d/init.d/restorecond" transition="/etc/rc.d/init.d/restorecond" 10 allow path="/etc/rc.d/init.d/httpd" transition="/etc/rc.d/init.d/httpd" 10 allow path="/etc/rc.d/init.d/rdisc" transition="/etc/rc.d/init.d/rdisc" 10 allow path="/etc/rc.d/init.d/postfix" transition="/etc/rc.d/init.d/postfix" 10 allow path="/etc/rc.d/init.d/saslauthd" transition="/etc/rc.d/init.d/saslauthd" 10 allow path="/etc/rc.d/init.d/netconsole" transition="/etc/rc.d/init.d/netconsole" 10 allow path="/etc/rc.d/init.d/network" transition="/etc/rc.d/init.d/network" 10 allow path="/etc/rc.d/init.d/avahi-daemon" transition="/etc/rc.d/init.d/avahi-daemon" 10 allow path="/etc/rc.d/init.d/auditd" transition="/etc/rc.d/init.d/auditd" 10 allow path="/etc/rc.d/init.d/nmb" transition="/etc/rc.d/init.d/nmb" 10 allow path="/etc/rc.d/init.d/iptables" transition="/etc/rc.d/init.d/iptables" 10 allow path="/etc/rc.d/init.d/cgred" transition="/etc/rc.d/init.d/cgred" 100 acl read path="/tmp/file1" audit 1 0 acl modify_policy audit 1 1 deny task.uid!=0 1 deny task.euid!=0 100 allow task.exe="/usr/sbin/caitsith-loadpolicy" 100 allow task.exe="/usr/sbin/caitsith-queryd" 10000 deny
Make sure that /usr/sbin/caitsith-auditd is running.
# pidof caitsith-auditd
3627
Now, create /tmp/file1 file.
# touch /tmp/file1
Then, open /tmp/file1 for reading.
# cat /tmp/file1
Check /var/log/caitsith/unmatched.log for access unmatched log of this access request. You will find an entry like below:
# grep /tmp/file1 /var/log/caitsith/unmatched.log
#2012/04/08 04:58:40# global-pid=3678 result=unmatched priority=100 / read path="/tmp/file1" task.pid=3678 task.ppid=3653 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451 path.major=8 path.minor=1 path.perm=0644 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1 path.parent.perm=01777 path.parent.type=directory path.parent.fsmagic=0xEF53
Note the result=unmatched part of the entry. This indicates that access request was checked but matched neither "allow" nor "deny" rule.
Note the priority=100 part of the entry. This indicates that this entry was generated by rules which have 100 as priority.
Note the read path="/tmp/file1" part of the entry. This indicates that this entry was generated by access request of opening /tmp/file1 for reading.
Now, let's add a rule to explicitly deny this request.
100 acl read path="/tmp/file1" 1000 deny
Append above rule using /usr/sbin/caitsith-loadpolicy :
# /usr/sbin/caitsith-loadpolicy
100 acl read path="/tmp/file1" 1000 deny ^D
Rules that have same priority (in this rule, 100) and same operation (in this rule, read) and same condition (in this rule, path="/tmp/file1") are automatically merged. Therefore, you will find
100 acl read path="/tmp/file1" audit 1 1000 deny
rather than
100 acl read path="/tmp/file1" audit 1 100 acl read path="/tmp/file1" 1000 deny
when you read /sys/kernel/security/caitsith/policy .
Then, open /tmp/file1 for reading.
# cat /tmp/file1
cat: /tmp/file1: Operation not permitted
This time, access request was denied by CaitSith.
Check /var/log/caitsith/denied.log for access denied log of this access request. You will find an entry like below:
# grep /tmp/file1 /var/log/caitsith/denied.log
#2012/04/08 04:59:53# global-pid=3682 result=denied priority=100 / read path="/tmp/file1" task.pid=3682 task.ppid=3653 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451 path.major=8 path.minor=1 path.perm=0644 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1 path.parent.perm=01777 path.parent.type=directory path.parent.fsmagic=0xEF53
Note the result=denied part of the entry. This indicates that access request was checked and matched "deny" rule.
If /usr/sbin/caitsith-notifyd is running, you will receive a notification mail. The content is same with access denied logs.
Heirloom Mail version 12.4 7/29/08. Type ? for help. "/var/spool/mail/root": 1 message 1 new >N 1 root Sun Apr 8 13:59 20/1231 "Notification from caitsith-notifyd" & Message 1: From root@ccsecurity.localdomain Sun Apr 8 13:59:53 2012 Return-Path: <root@ccsecurity.localdomain> X-Original-To: root@localhost Delivered-To: root@localhost.localdomain Date: Sun, 08 Apr 2012 13:59:53 +0900 To: root@localhost.localdomain Subject: Notification from caitsith-notifyd User-Agent: Heirloom mailx 12.4 7/29/08 Content-Type: text/plain; charset=us-ascii From: root@caitsith.localdomain (root) Status: R Q0-0 #2012/04/08 04:59:53# global-pid=3682 result=denied priority=100 / read path="/tmp/file1" task.pid=3682 task.ppid=3653 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451 path.major=8 path.minor=1 path.perm=0644 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1 path.parent.perm=01777 path.parent.type=directory path.parent.fsmagic=0xEF53
Now, let's remove a rule to explicitly deny this request.
100 acl read path="/tmp/file1" delete 1000 deny
Append above rule using /usr/sbin/caitsith-loadpolicy :
# /usr/sbin/caitsith-loadpolicy
100 acl read path="/tmp/file1" delete 1000 deny ^D
You will find
100 acl read path="/tmp/file1" audit 1
rather than
100 acl read path="/tmp/file1" audit 1 1000 deny delete 1000 deny
when you read /sys/kernel/security/caitsith/policy .
Now, open /tmp/file1 for reading.
# cat /tmp/file1
Check /var/log/caitsith/unmatched.log for access unmatched log of this access request. You will find entries like below:
# grep /tmp/file1 /var/log/caitsith/unmatched.log
#2012/04/08 04:58:40# global-pid=3678 result=unmatched priority=100 / read path="/tmp/file1" task.pid=3678 task.ppid=3653 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451 path.major=8 path.minor=1 path.perm=0644 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1 path.parent.perm=01777 path.parent.type=directory path.parent.fsmagic=0xEF53 #2012/04/08 05:01:00# global-pid=3695 result=unmatched priority=100 / read path="/tmp/file1" task.pid=3695 task.ppid=3653 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451 path.major=8 path.minor=1 path.perm=0644 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1 path.parent.perm=01777 path.parent.type=directory path.parent.fsmagic=0xEF53
The former entry was generated before adding explicit "deny" rule. The latter entry was generated after removing explicit "deny" rule. You might want to filter the output using tail command:
# grep /tmp/file1 /var/log/caitsith/unmatched.log | tail -n 1
#2012/04/08 05:01:00# global-pid=3695 result=unmatched priority=100 / read path="/tmp/file1" task.pid=3695 task.ppid=3653 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451 path.major=8 path.minor=1 path.perm=0644 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1 path.parent.perm=01777 path.parent.type=directory path.parent.fsmagic=0xEF53
Next, let's see audit logs with explicitly matching "allow" rules.
By default CaitSith does not generate audit logs with explicitly matching "allow" rules. Change policy configuration to generate such logs.
quota audit[1] allowed=1024
Append above rule using /usr/sbin/caitsith-loadpolicy :
# echo 'quota audit[1] allowed=1024' | /usr/sbin/caitsith-loadpolicy
Preferences that have same name (in this rule, audit[1]) are automatically merged. Therefore, you will find
quota audit[1] allowed=1024 denied=1024 unmatched=1024
rather than
quota audit[1] allowed=0 denied=1024 unmatched=1024 quota audit[1] allowed=1024
when you read /sys/kernel/security/caitsith/policy .
100 acl read path="/tmp/file1" 1000 allow
Append above rule using /usr/sbin/caitsith-loadpolicy :
# /usr/sbin/caitsith-loadpolicy
100 acl read path="/tmp/file1" 1000 allow ^D
Since audit logs with explicitly matching "allow" rules tend to grow rapidly, by default /usr/sbin/caitsith-auditd discards such logs by writing to /dev/null (specified in /etc/caitsith/tools/auditd.conf ). Therefore, temporarily stop /usr/sbin/caitsith-auditd process in order to read audit logs from /sys/kernel/security/caitsith/audit interface.
# killall -KILL caitsith-auditd
Then, open /tmp/file1 for reading.
# cat /tmp/file1
Check /sys/kernel/security/caitsith/audit for audit log of this access request. This time, you will find an entry like below:
# cat -v /sys/kernel/security/caitsith/audit
#2012/04/08 05:03:03# global-pid=3720 result=allowed priority=100 / read path="/tmp/file1" task.pid=3720 task.ppid=3653 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=0 path.ino=2113451 path.major=8 path.minor=1 path.perm=0644 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=2097153 path.parent.major=8 path.parent.minor=1 path.parent.perm=01777 path.parent.type=directory path.parent.fsmagic=0xEF53 ^@
Note the result=allowed part of the entry. This indicates that access request was checked and matched "allow" rule.
Restart /usr/sbin/caitsith-auditd process.
# /usr/sbin/caitsith-auditd
Also, restore the audit logs configuration:
quota audit[1] allowed=0
Append above rule using /usr/sbin/caitsith-loadpolicy :
# echo 'quota audit[1] allowed=0' | /usr/sbin/caitsith-loadpolicy
CaitSith supports writing access restriction rules from two viewpoints. One is from the point of view of "subject" (a resource which requests access on object). The other is from the point of view of "object" (a resource which subject requests access).
The advantage of the former approach is that the rules clearly explains and restricts what each subject is allowed to access which object. This approach is powerful when you can afford identifying all possible subjects and defining the rules for each subject. But the disadvantage is that it is difficult to identify all possible subjects and define the rules for each subject. Therefore, in reality, this approach tends to restrict only specific subjects. If one of subjects which is not restricted by this approach is cracked or misbehaved, nothing can protect objects you want to protect.
The advantage of the latter approach is that the rules clearly explains and restricts what object might be accessed by which subject. This approach is powerful when you can afford identifying objects you want to protect and defining rules for each object. This approach can compensate for the disadvantage of the former approach because this approach can restrict access even when it is difficult to identify all possible subjects and define the rules for each possible subject.
Below entry is an example of restricting programs which can be executed from /usr/sbin/httpd program.
0 acl execute task.exe="/usr/sbin/httpd" audit 1 1 allow path="/var/www/cgi-bin/counter.cgi" 100 deny
The 0 acl execute task.exe="/usr/sbin/httpd" line means check rules for executing programs from /usr/sbin/httpd program. Since task.exe="/usr/sbin/httpd" is specified in this line, this line tells CaitSith check rules for executing programs only if current thread's program name is /usr/sbin/httpd.
The line 1 allow path="/var/www/cgi-bin/counter.cgi" means that allow if the pathname of the program to execute is /var/www/cgi-bin/counter.cgi . This line tells CaitSith "allow execution of /var/www/cgi-bin/counter.cgi".
The line 100 deny means deny unconditionally. This tells CaitSith "unconditionally deny execution of programs".
Since the line starting with 1 allow has higher priority than the line starting with 100 deny, CaitSith will allow execution of /var/www/cgi-bin/counter.cgi .
To summarize this rule, /usr/sbin/httpd can execute only /var/www/cgi-bin/counter.cgi .
The line audit 1 means that use audit rules defined in the quota audit[1] line. This line tells CaitSith generate audit logs up to entries defined in the quota audit[1] line. The default configuration generated by executing /usr/lib64/caitsith/init_policy command is
quota audit[1] allowed=0 denied=1024 unmatched=1024
which means do not generate audit logs if matched an "allow" line and generate audit logs up to 1024 entries if matched a "deny" line and generate audit logs up to 1024 lines if matched neither an "allow" line nor a "deny" line. Though, since the block starting with 0 acl execute task.exe="/usr/sbin/httpd" is terminated with explicit 100 deny line, this block shall match either an "allow" line or a "deny" line.
Below entry is default configuration generated by executing /usr/lib64/caitsith/init_policy command.
0 acl modify_policy audit 1 1 deny task.uid!=0 1 deny task.euid!=0 100 allow task.exe="/usr/sbin/caitsith-loadpolicy" 100 allow task.exe="/usr/sbin/caitsith-queryd" 10000 deny
The 0 acl modify_policy line means check rules for modifying policy configuration via /sys/kernel/security/caitsith/policy interface. Since no additional conditions are specified in this line, this line tells CaitSith unconditionally check rules for modifying policy configuration via /sys/kernel/security/caitsith/policy interface.
The line 1 deny task.uid!=0 means that deny if current thread's user ID is not 0. This line tells CaitSith "deny modification of policy configuration via /sys/kernel/security/caitsith/policy interface if current thread's user ID is not 0".
The line 1 deny task.euid!=0 means that deny if current thread's effective user ID is not 0. This line tells CaitSith "deny modification of policy configuration via /sys/kernel/security/caitsith/policy interface if current thread's effective user ID is not 0".
Note the difference between
1 deny task.uid!=0 1 deny task.euid!=0
and
1 deny task.uid!=0 task.euid!=0
. The former conditions tell CaitSith "deny if current thread's user ID is not 0 or current thread's effective user ID is not 0", while the latter conditions tell CaitSith "deny if current thread's user ID is not 0 and current thread's effective user ID is not 0".
The line 100 allow task.exe="/usr/sbin/caitsith-loadpolicy" means that allow if current thread's program name is /usr/sbin/caitsith-loadpolicy . This tells CaitSith finish evaluation of this block starting with the 0 acl modify_policy line if current thread's program name is /usr/sbin/caitsith-loadpolicy . If there are more blocks, CaitSith will evaluate them. If there are no more blocks, CaitSith will allow modifying policy configuration via /sys/kernel/security/caitsith/policy interface.
The line 100 allow task.exe="/usr/sbin/caitsith-queryd" means that allow if current thread's program name is /usr/sbin/caitsith-queryd . This tells CaitSith finish evaluation of this block starting with the 0 acl modify_policy line if current thread's program name is /usr/sbin/caitsith-queryd . The usage of /usr/sbin/caitsith-queryd will be explained later.
The line 10000 deny means deny unconditionally. This tells CaitSith "unconditionally deny modification of policy configuration via /sys/kernel/security/caitsith/policy interface".
Since lines starting with 1 deny have higher priority than lines starting with 100 allow, CaitSith will deny modifying policy configuration via /sys/kernel/security/caitsith/policy interface if current thread's user ID is not 0 or current thread's effective user ID is not 0. In other words, only root user (where current thread's user ID and effective user ID are both 0) can modify policy configuration via /sys/kernel/security/caitsith/policy interface.
Since lines starting with 100 allow have higher priority than a line starting with 10000 deny, CaitSith will allow modifying policy configuration via /sys/kernel/security/caitsith/policy interface if current thread's program name is /usr/sbin/caitsith-loadpolicy or current thread's program name is /usr/sbin/caitsith-queryd . In other words, other programs such as /bin/sh , /bin/echo , /bin/cat are not allowed to modify policy configuration via /sys/kernel/security/caitsith/policy interface.
To summarize this rule, only /usr/sbin/caitsith-loadpolicy or /usr/sbin/caitsith-queryd command running as root user can modify policy configuration via /sys/kernel/security/caitsith/policy interface.
Note the difference between
0 acl execute task.exe="/usr/sbin/httpd" audit 1 1 allow path="/var/www/cgi-bin/counter.cgi" 100 deny
and
0 acl execute path="/var/www/cgi-bin/counter.cgi" audit 1 1 allow task.exe="/usr/sbin/httpd" 100 deny
. The former means "/usr/sbin/httpd can execute only /var/www/cgi-bin/counter.cgi", while the latter means "only /usr/sbin/httpd can execute /var/www/cgi-bin/counter.cgi".
CaitSith supports restricting other arguments such as command line arguments and environment variables. Syntax for restricting other arguments will be explained later.
It is possible to write access restriction rules like
0 acl execute task.exe="/usr/sbin/httpd" path="/var/www/cgi-bin/counter.cgi" audit 1 1 allow task.uid!=0 100 deny
and
0 acl execute task.uid!=0 audit 1 1 allow task.exe="/usr/sbin/httpd" path="/var/www/cgi-bin/counter.cgi" 100 deny
. The former means "/usr/sbin/httpd is allowed to execute /var/www/cgi-bin/counter.cgi only if current thread's user ID is not 0", while the latter means "only execution of /var/www/cgi-bin/counter.cgi from /usr/sbin/httpd is allowed if current thread's user ID is not 0".
Also, it is possible to write access restriction rules like
0 acl execute audit 1 1 allow task.exe="/usr/sbin/httpd" path="/var/www/cgi-bin/counter.cgi" 100 deny
which means "any execute requests other than execution of /var/www/cgi-bin/counter.cgi from /usr/sbin/httpd are denied" (DO NOT TRY THIS EXAMPLE, or you will no longer be able to run any commands).
An example of steps for writing access restriction rules using pathnames is shown here.
Step 1: Determine resource to restrict access.
Below example restricts opening /etc/shadow for reading.
100 acl read path="/etc/shadow" audit 1
Step 2: Gather logs of accessing resources.
As you operate the system with above example, access unmatched logs are generated and spooled in /sys/kernel/security/caitsith/audit interface when access request of opening /etc/shadow for reading happens. If /usr/sbin/caitsith-auditd is running, access unmatched logs will be moved to /var/log/caitsith/unmatched.log .
#2012/03/02 08:11:51# global-pid=2826 result=unmatched priority=100 / read path="/etc/shadow" task.pid=2826 task.ppid=2814 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/usr/bin/passwd" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=42 path.ino=33708 path.major=8 path.minor=1 path.perm=0640 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=32769 path.parent.major=8 path.parent.minor=1 path.parent.perm=0755 path.parent.type=directory path.parent.fsmagic=0xEF53
Step 3: Decide whether to allow or deny.
Examine the log and decide whether to allow this access request or not. To allow this request, add an allow line. Below example allows this request to /usr/bin/passwd program.
100 acl read path="/etc/shadow" audit 1 100 allow task.exe="/usr/bin/passwd"
Step 4: Gather again logs of accessing resources.
Operate the system again. For example, /usr/sbin/sshd program and /bin/cat program have requested opening /etc/shadow for reading.
#2012/03/02 08:13:06# global-pid=2831 result=unmatched priority=100 / read path="/etc/shadow" task.pid=2831 task.ppid=2691 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/usr/sbin/sshd" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=42 path.ino=33716 path.major=8 path.minor=1 path.perm=0640 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=32769 path.parent.major=8 path.parent.minor=1 path.parent.perm=0755 path.parent.type=directory path.parent.fsmagic=0xEF53 #2012/03/02 08:13:12# global-pid=2837 result=unmatched priority=100 / read path="/etc/shadow" task.pid=2837 task.ppid=2833 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=42 path.ino=33716 path.major=8 path.minor=1 path.perm=0640 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=32769 path.parent.major=8 path.parent.minor=1 path.parent.perm=0755 path.parent.type=directory path.parent.fsmagic=0xEF53
Step 5: Decide again whether to allow or deny.
Add an allow line with /usr/sbin/sshd program in order to allow access by /usr/sbin/sshd program. Also, add a deny line with /bin/cat program in order to deny access by /bin/cat program. Give higher priority (i.e. smaller $cond_priority value) to deny line than allow line so that deny lines are checked before allow lines are checked.
100 acl read path="/etc/shadow" audit 1 10 deny task.exe="/bin/cat" 100 allow task.exe="/usr/bin/passwd" 100 allow task.exe="/usr/sbin/sshd"
From now on, attempt to read /etc/shadow using /bin/cat should be denied and access denied logs should be generated. If /usr/sbin/caitsith-auditd is running, access denied logs will be moved to /var/log/caitsith/denied.log .
#2012/03/02 08:14:38# global-pid=2842 result=denied priority=100 / read path="/etc/shadow" task.pid=2842 task.ppid=2833 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/bin/cat" task.domain="/usr/sbin/sshd" path.uid=0 path.gid=42 path.ino=33716 path.major=8 path.minor=1 path.perm=0640 path.type=file path.fsmagic=0xEF53 path.parent.uid=0 path.parent.gid=0 path.parent.ino=32769 path.parent.major=8 path.parent.minor=1 path.parent.perm=0755 path.parent.type=directory path.parent.fsmagic=0xEF53
Step 6: Finish up a rule.
After you have finished enumerating all allow lines and deny lines, add a deny line with lowest priority (i.e. largest $cond_priority value within this block).
100 acl read path="/etc/shadow" audit 1 10 deny task.exe="/bin/cat" 100 allow task.exe="/usr/bin/passwd" 100 allow task.exe="/usr/sbin/sshd" 10000 deny
A rule for restricting /etc/shadow for opening is now completed. Please do not copy and paste this example, for there must be other programs which need to open /etc/shadow for reading.
The rule demonstrated in 3.5. Steps for writing access restriction rules alone cannot prevent diverted accesses such as creating a hard link of /etc/shadow . CaitSith supports various variables for writing access restriction rules. If the resource to protect has characteristic attribute, it is recommended to utilize such attributes. (The full list of available variables/attributes will be explained in 4. List of conditions.)
On several distributions, /etc/shadow is owned by shadow group. In that case, this rule can be modified to below. (Below example assumes that shadow group's group ID is 42.)
100 acl read path.gid=42 audit 1 10 deny task.exe="/bin/cat" 100 allow task.exe="/usr/bin/passwd" 100 allow task.exe="/usr/sbin/sshd" 10000 deny
On several distributions, /etc/shadow is owned by root user and root group and has DAC permissions 0400. In that case, you might want to use a rule like below. (You should check whether there are other files with such attributes.)
100 acl read path.uid=0 path.gid=0 path.perm=0400 audit 1 10 deny task.exe="/bin/cat" 100 allow task.exe="/usr/bin/passwd" 100 allow task.exe="/usr/sbin/sshd" 10000 deny
It is recommended to restrict other operations such as mount, link and rename. For example, a rule to deny creation of hard links which is not owned by the user would look like below. (Note that the variable which refers source pathname of link operation is "old_path" rather than "path" because the operation is "link".)
100 acl link old_path.uid!=task.uid audit 1 100 deny
If you can split files into different filesystems or different partitions, you might be able to utilize more variables. For example, rules for denying creation of hard links on tmpfs filesystem (tmpfs filesystem's magic number is 0x01021994) would look like below.
100 acl link old_path.fsmagic=0x01021994 audit 1 10 deny
Splitting into different partitions and defining rules based on partition's attributes will help preventing diverted access via creating hard links, for hard links cannot be created across partitions. Separating /home partition from / partition will be useful when protecting resources in /home partition.
Arguments such as file's pathnames and command line arguments and environment variables are handled as string argument.
All ASCII printable characters other than \ character (i.e. from 33 to 91 and from 93 to 126) are represented as is.
All other characters (i.e. from 0 to 32, 92 and from 127 to 255) are represented using \ooo style octal form.
|
0x0 |
0x1 |
0x2 |
0x3 |
0x4 |
0x5 |
0x6 |
0x7 |
0x8 |
0x9 |
0xA |
0xB |
0xC |
0xD |
0xE |
0xF |
||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0 |
\000 |
\001 |
\002 |
\003 |
\004 |
\005 |
\006 |
\007 |
\010 |
\011 |
\012 |
\013 |
\014 |
\015 |
\016 |
\017 |
||||
0x1 |
\020 |
\021 |
\022 |
\023 |
\024 |
\025 |
\026 |
\027 |
\030 |
\031 |
\032 |
\033 |
\034 |
\035 |
\036 |
\037 |
||||
0x2 |
\040 |
! |
" |
# |
$ |
% |
& |
' |
( |
) |
* |
+ |
, |
- |
. |
/ |
||||
0x3 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
: |
; |
< |
= |
> |
? |
||||
0x4 |
@ |
A |
B |
C |
D |
E |
F |
G |
H |
I |
J |
K |
L |
M |
N |
O |
||||
0x5 |
P |
Q |
R |
S |
T |
U |
V |
W |
X |
Y |
Z |
[ |
\134 |
] |
^ |
_ |
||||
0x6 |
` |
a |
b |
c |
d |
e |
f |
g |
h |
i |
j |
k |
l |
m |
n |
o |
||||
0x7 |
p |
q |
r |
s |
t |
u |
v |
w |
x |
y |
z |
{ |
| |
} |
~ |
\177 |
||||
0x8 |
\200 |
\201 |
\202 |
\203 |
\204 |
\205 |
\206 |
\207 |
\210 |
\211 |
\212 |
\213 |
\214 |
\215 |
\216 |
\217 |
||||
0x9 |
\220 |
\221 |
\222 |
\223 |
\224 |
\225 |
\226 |
\227 |
\230 |
\231 |
\232 |
\233 |
\234 |
\235 |
\236 |
\237 |
||||
0xA |
\240 |
\241 |
\242 |
\243 |
\244 |
\245 |
\246 |
\247 |
\250 |
\251 |
\252 |
\253 |
\254 |
\255 |
\256 |
\257 |
||||
0xB |
\260 |
\261 |
\262 |
\263 |
\264 |
\265 |
\266 |
\267 |
\270 |
\271 |
\272 |
\273 |
\274 |
\275 |
\276 |
\277 |
||||
0xC |
\300 |
\301 |
\302 |
\303 |
\304 |
\305 |
\306 |
\307 |
\310 |
\311 |
\312 |
\313 |
\314 |
\315 |
\316 |
\317 |
||||
0xD |
\320 |
\321 |
\322 |
\323 |
\324 |
\325 |
\326 |
\327 |
\330 |
\331 |
\332 |
\333 |
\334 |
\335 |
\336 |
\337 |
||||
0xE |
\340 |
\341 |
\342 |
\343 |
\344 |
\345 |
\346 |
\347 |
\350 |
\351 |
\352 |
\353 |
\354 |
\355 |
\356 |
\357 |
||||
0xF |
\360 |
\361 |
\362 |
\363 |
\364 |
\365 |
\366 |
\367 |
\370 |
\371 |
\372 |
\373 |
\374 |
\375 |
\376 |
\377 |
Some examples are shown below.
/bin/sh /home/demo/Documents\040and\040Settings
It is possible to use wildcards listed below in order to match string patterns.
Wildcard |
Pattern match |
Examples |
---|---|---|
\* |
0 or more repetitions of characters other than "/" |
/var/log/samba/\* |
\@ |
0 or more repetitions of characters other than "/" or "." |
/var/www/html/\@.html |
\? |
1 byte character other than "/" |
/tmp/mail.\?\?\?\?\?\? |
\$ |
1 or more repetitions of decimal digits |
/proc/\$/cmdline |
\+ |
1 decimal digit |
/var/tmp/my_work.\+ |
\X |
1 or more repetitions of hexadecimal digits |
/var/tmp/my-work.\X |
\x |
1 hexadecimal digit |
/tmp/my-work.\x |
\A |
1 or more repetitions of alphabet characters |
/var/log/my-work/\$-\A-\$.log |
\a |
1 alphabet character |
/home/users/\a/\*/public_html/\*.html |
\- |
Pathname subtraction operator (negative match) |
/\*\-proc\-sys This will match /\* except "/proc" and "/sys". |
/\{dir\}/ |
Recursive directory matching operator. Matches "/" and 1 or more repetitions of "dir/". |
/var/www/html/\{\*\}/\*.html This will match all *.html files in subdirectories under /var/www/html/ directory. Note that /var/www/html/\*.html will not match. |
/\(dir\)/ |
Recursive directory matching operator. Matches "/" and 0 or more repetitions of "dir/". |
/var/www/html/\(\*\)/\*.html This will match all *.html files under /var/www/html/ directory. Note that /var/www/html/\*.html will match. |
It is possible to define groups of string arguments using string_group keyword followed by $string_group_name and $string_group_member.
string_group TMPDIR /tmp string_group TMPDIR /tmp/\(\*\)/\*
When string argument is specified in condition part, it is quoted by " character in order to clarify that the argument is a string argument rather than name of variable.
Conditions example | Value of variable "path" | Comparison result |
path="/tmp/\*" | / | Does not match |
/tmp | Does not match | |
/tmp/ | Matches | |
/tmp/rt6bh84t | Matches | |
/tmp/349gy08t/y8024fgf | Does not match | |
path!="/tmp/\*" | / | Matches |
/tmp | Matches | |
/tmp/ | Does not match | |
/tmp/rt6bh84t | Does not match | |
/tmp/349gy08t/y8024fgf | Matches |
When string_group argument is specified in condition part, it is prefixed by @ character in order to clarify that the argument is a string_group argument rather than name of variable.
Conditions example | Value of variable "path" | Values in TMPDIR group | Comparison result |
path=@TMPDIR | / | /tmp /tmp/\(\*\)/\* | Does not match |
/tmp | Matches | ||
/tmp/rt6bh84t | Matches | ||
/tmp/349gy08t/y8024fgf | Matches | ||
path!=@TMPDIR | / | /tmp /tmp/\(\*\)/\* | Matches |
/tmp | Does not match | ||
/tmp/rt6bh84t | Does not match | ||
/tmp/349gy08t/y8024fgf | Does not match |
List of name of variables which reference string data is explained later.
Arguments such as user ID and process ID are handled as numeric argument.
Decimal form, octal form and hexadecimal form are supported. Octal form is prefixed with 0 and Hexadecimal form is prefixed with 0x. For example, 010 in octal form is equivalent with 8 in decimal form, 0x10 in hexadecimal form is equivalent with 16 in decimal form.
Since numeric data is handled using C language's "unsigned long" type, minimal value is 0 and maximal value is 0xFFFFFFFF (for 32 bit environments) or 0xFFFFFFFFFFFFFFFF (for 64 bit environments).
It is possible to specify numeric data ranges in $min_value-$max_value form. If specifying in range, $min_value has to be smaller or equals to $max_value. For example, 0-100 is valid but 100-0 is invalid.
Some examples are shown below.
0 100 0xFFFF 0777 500-1000 0x0-0xFFFFFFFF 00-07777
It is possible to define groups of numeric arguments using number_group keyword followed by $number_group_name and $number_group_member.
number_group ID_GROUP 100 number_group ID_GROUP 200-500
Comparison with numeric value is defined as below.
Conditions example | Value of variable "task.uid" | Comparison result |
task.uid=0 | 0 | Matches |
100 | Does not match | |
500 | Does not match | |
task.uid!=0 | 0 | Does not match |
100 | Matches | |
500 | Matches |
Comparison with numeric value range is defined as below.
Conditions example | Value of variable "task.gid" | Comparison result |
task.gid=0-100 | 0 | Matches |
100 | Matches | |
500 | Does not match | |
task.gid!=0-100 | 0 | Does not match |
100 | Does not match | |
500 | Matches |
It is possible to compare one variable which references numeric value with another variable which references numeric value.
Conditions example | Value of variable "task.uid" | Value of variable "task.gid" | Comparison result |
task.uid=task.gid | 0 | 0 | Matches |
0 | 100 | Does not match | |
100 | 0 | Does not match | |
100 | 100 | Matches | |
task.uid!=task.gid | 0 | 0 | Does not match |
0 | 100 | Matches | |
100 | 0 | Matches | |
100 | 100 | Does not match |
When number_group argument is specified in condition part, it is prefixed by @ character in order to clarify that the argument is a number_group argument rather than name of variable.
Conditions example | Value of variable "task.uid" | Values in ID_GROUP group | Comparison result |
task.uid=@ID_GROUP | 0 | 100 200-500 | Does not match |
100 | Matches | ||
500 | Matches | ||
1000 | Does not match | ||
task.uid!=@ID_GROUP | 0 | 100 200-500 | Matches |
100 | Does not match | ||
500 | Does not match | ||
1000 | Matches |
List of name of variables which reference numeric data is explained later.
By using current thread's attributes as part of conditions, you can write complicated access restriction rules.
Below variables are available for referring current thread's attributes.
Variable's name | Comparison method | Meaning | |
task.uid | Numeric | Current thread's user ID | |
task.gid | Numeric | Current thread's group ID | |
task.euid | Numeric | Current thread's effective user ID | |
task.egid | Numeric | Current thread's effective group ID | |
task.suid | Numeric | Current thread's saved user ID | |
task.sgid | Numeric | Current thread's saved group ID | |
task.fsuid | Numeric | Current thread's filesystem user ID | |
task.fsgid | Numeric | Current thread's filesystem group ID | |
task.pid | Numeric | Current thread's process ID | |
task.ppid | Numeric | Process ID of current thread's parent process | |
task.exe | String | Current thread's program name (the content of /proc/self/exe) | |
task.domain | String | Current thread's domainname (the content of /sys/kernel/security/caitsith/self_domain) | |
task.type | Literal | Matches execute_handler if running as an execute handler, does not match execute_handler otherwise |
Details of task.domain is explained in 6.1. Controlling domain transition and task.type is explained in 6.2. Using execute handler.
Any operation which handles IPv4/IPv6 network address can check IP address.
It is possible to handle IPv4 address and IPv6 address. IPv4 address (32 bit) is represented using dot separated decimal form. and IPv6 address (128 bit) is represented using forms defined in RFC 2373.
It is possible to specify IP address ranges in $min_address-$max_address form. If specifying in range, $min_address has to be smaller or equals to $max_address. For example, 1.2.3.4-5.6.7.8 is valid but 5.6.7.8-1.2.3.4 is invalid.
Some examples are shown below.
127.0.0.1 10.0.0.0-10.255.255.255 ::1 fd00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
It is possible to define groups of IP address arguments using ip_group keyword followed by $ip_group_name and $ip_group_member.
ip_group PRIVATE_ADDRESS 10.0.0.0-10.255.255.255 ip_group PRIVATE_ADDRESS 172.16.0.0-172.31.255.255 ip_group PRIVATE_ADDRESS 192.168.0.0-192.168.255.255 ip_group PRIVATE_ADDRESS fd00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
Comparison with IP address value is defined as below. Note that comparison between an IPv4 address and an IPv6 address does not match.
Conditions example | Value of variable "ip" | Comparison result |
ip=127.0.0.1 | 127.0.0.1 | Matches |
0.0.0.0 | Does not match | |
::1 | Does not match | |
::ffff:127.0.0.1 | Does not match | |
ip!=127.0.0.1 | 127.0.0.1 | Does not match |
0.0.0.0 | Matches | |
::1 | Does not match | |
::ffff:127.0.0.1 | Does not match | |
ip=::1 | 127.0.0.1 | Does not match |
0.0.0.0 | Does not match | |
::1 | Matches | |
::ffff:127.0.0.1 | Does not match | |
ip!=::1 | 127.0.0.1 | Does not match |
0.0.0.0 | Does not match | |
::1 | Does not match | |
::ffff:127.0.0.1 | Matches |
Comparison with IP address range is defined as below.
Conditions example | Value of variable "ip" | Comparison result |
ip=127.0.0.0-127.255.255.255 | 127.0.0.1 | Matches |
10.0.0.1 | Does not match | |
::ffff:127.0.0.1 | Does not match | |
ip!=127.0.0.0-127.255.255.255 | 127.0.0.1 | Does not match |
10.0.0.1 | Matches | |
::ffff:127.0.0.1 | Does not match | |
ip=::-::1 | ::ffff:127.0.0.1 | Does not match |
127.0.0.1 | Does not match | |
::1 | Matches | |
ip!=::-::1 | ::ffff:127.0.0.1 | Matches |
127.0.0.1 | Does not match | |
::1 | Does not match |
When ip_group argument is specified in condition part, it is prefixed by @ character in order to clarify that the argument is an ip_group argument rather than name of variable.
Conditions example | Value of variable "ip" | Values in PRIVATE_ADDRESS group | Comparison result |
ip=@PRIVATE_ADDRESS | 127.0.0.1 | 10.0.0.0-10.255.255.255 172.16.0.0-172.31.255.255 192.168.0.0-192.168.255.255 fd00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | Does not match |
10.0.0.1 | Matches | ||
192.168.0.1 | Matches | ||
::ffff:172.16.0.1 | Does not match | ||
fd01:: | Matches | ||
ip!=@PRIVATE_ADDRESS | 127.0.0.1 | 10.0.0.0-10.255.255.255 172.16.0.0-172.31.255.255 192.168.0.0-192.168.255.255 fd00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | Matches |
10.0.0.1 | Does not match | ||
::ffff:192.168.0.1 | Matches | ||
::ffff:127.0.0.1 | Matches | ||
fd01:: | Does not match |
List of operations which handles IP address is explained later.
It is possible to check command line arguments (a.k.a. argv[]) when checking permissions for program execution.
Conditions example | Comparison method | Meaning | |
argv[0]="true" | String | argv[0] matches "true" | |
argv[0]!="false" | String | argv[0] does not match "false" | |
argv[1]=@ARGV1_GROUPS | String | argv[0] matches one of strings in string_group ARGV1_GROUPS group | |
argv[1]!=@ARGV1_GROUPS | String | argv[0] matches none of strings in string_group ARGV1_GROUPS group |
Applications can pass a string data up to 32 * PAGE_SIZE bytes to each argv[]. But due to difficulty of allocating contiguous memory in the kernel, only up to 4085 bytes can be checked using variable "argv[$index]". If you want to check strictly, please consider using handler= argument of "allow " lines in "acl execute" block.
It is possible to check environment variables (a.k.a. envp[]) when checking permissions for program execution.
Conditions example | Comparison method | Meaning | |
envp["PATH"]="/" | String | Environment variable PATH is defined and its value is "/" | |
envp["PATH"]!="/" | String | Either Environment variable PATH is not defined or Environment variable PATH is defined but its value is not "/" | |
envp["PATH"]=@ENV_PATH_VALUES | String | Environment variable PATH is defined and its value matches one of strings in string_group ENVP_PATH_VALUES group | |
envp["PATH"]!=@ENV_PATH_VALUES | String | Either Environment variable PATH is not defined or Environment variable PATH is defined but its value matches none of strings in string_group ENVP_PATH_VALUES group | |
envp["PATH"]=NULL | None | Environment variable PATH is not defined | |
envp["PATH"]!=NULL | None | Environment variable PATH is defined |
Applications can pass a string data up to 32 * PAGE_SIZE bytes to each envp[]. But due to difficulty of allocating contiguous memory in the kernel, only up to 4085 bytes can be checked using variable "envp["$name"]". If you want to check strictly, please consider using handler= argument of "allow " lines in "acl execute" block.
When checking permissions for file related operations, it is possible to check its DAC permissions if the file already exists as of permission check. Below table assumes that the variable name for referencing the requested pathname is "path".
Value of DAC permissions can be referenced using variable "path.perm", and its value is between 0 and 07777. Although it is possible to do normal numeric comparison, below constants are provided in order to make it easier to compare whether specific bit is set or not.
Constant | Value ranges that match |
setuid | Values where bitwise AND between path.perm and 04000 are 04000. (i.e. 04000-07777) |
setgid | Values where bitwise AND between path.perm and 02000 are 02000. (i.e. 02000-03777 06000-07777) |
sticky | Values where bitwise AND between path.perm and 01000 are 01000. (i.e. 01000-01777 03000-03777 05000-05777 07000-07777) |
owner_read | Values where bitwise AND between path.perm and 00400 are 00400. (e.g. 00400-00777 01400-01777 02400-02777) |
owner_write | Values where bitwise AND between path.perm and 00200 are 00200. (e.g. 00200-00377 00600-00777 01200-01377) |
owner_execute | Values where bitwise AND between path.perm and 00100 are 00100. (e.g. 00100-00177 00300-00377 00500-00577) |
group_read | Values where bitwise AND between path.perm and 00040 are 00040. (e.g. 00040-00077 00140-00177 00240-00277) |
group_write | Values where bitwise AND between path.perm and 00020 are 00020. (e.g. 00020-00037 00060-00077 00120-00137) |
group_execute | Values where bitwise AND between path.perm and 00010 are 00010. (e.g. 00010-00017 00030-00037 00050-00057) |
others_read | Values where bitwise AND between path.perm and 00004 are 00004. (e.g. 00004-00007 00014-00017 00024-00027) |
others_write | Values where bitwise AND between path.perm and 00002 are 00002. (e.g. 00002-00003 00006-00007 00012-00013) |
others_execute | Values where bitwise AND between path.perm and 00001 are 00001. (e.g. 00001 00003 00005 00007 00011 00013) |
Below are some examples that use constants.
Conditions example | Permissions of file referenced by variable "path" | Comparison result |
path.perm=setuid | 04755 | Matches |
path.perm!=setuid | 04755 | Does not match |
path.perm=setuid path.perm=setgid path.perm=sticky | 0755 | Does not match |
path.perm!=setuid path.perm!=setgid path.perm!=sticky | 0755 | Matches |
When checking permissions for file related operations, it is possible to check its type if the file already exists as of permission check. Below table assumes that the variable name for referencing the requested pathname is "path".
Type of a file can be referenced using variable "path.type", and its value takes one of "file", "directory", "socket", "fifo", "block", "char", "symlink".
Possible conditions | Type of file referenced by variable "path" | Comparison result |
path.type=file | Regular file | Matches |
path.type!=file | Other than regular file | Matches |
path.type=directory | Directory | Matches |
path.type!=directory | Other than directory | Matches |
path.type=socket | Unix domain socket | Matches |
path.type!=socket | Other than Unix domain socket | Matches |
path.type=fifo | FIFO | Matches |
path.type!=fifo | Other than FIFO | Matches |
path.type=block | Block device file | Matches |
path.type!=block | Other than block device file | Matches |
path.type=char | Character device file | Matches |
path.type!=char | Other than character device file | Matches |
path.type=symlink | Symbolic link | Matches |
path.type!=symlink | Other than symbolic link | Matches |
When checking permissions for file related operations, it is possible to check its attributes if the file already exists as of permission check. Below table assumes that the variable name for referencing the requested pathname is "path".
Variable's name | Comparison method | Meaning |
path.uid | Numeric | Owner ID |
path.gid | Numeric | Group ID |
path.ino | Numeric | i-node number on the filesystem |
path.major | Numeric | Device major number on the filesystem |
path.minor | Numeric | Device minor number on the filesystem |
path.perm | Permission | DAC permissions |
path.type | File's type | Type of the file |
path.dev_major | Numeric | Device major number of the file if path.type=block or path.type=char |
path.dev_minor | Numeric | Device minor number of the file if path.type=block or path.type=char |
path.fsmagic | Numeric | Magic number of filesystem |
When checking permissions for file related operations, it is possible to also check its parent directory's attributes. Below table assumes that the variable name for referencing the requested pathname is "path".
Variable's name | Comparison method | Meaning |
path.parent.uid | Numeric | Owner ID |
path.parent.gid | Numeric | Group ID |
path.parent.ino | Numeric | i-node number on the filesystem |
path.parent.major | Numeric | Device major number on the filesystem |
path.parent.minor | Numeric | Device minor number on the filesystem |
path.parent.perm | Permission | DAC permissions |
path.parent.fsmagic | Numeric | Magic number of filesystem |
It does not make sense to use path.parent.type path.parent.dev_major path.parent.dev_minor because path.parent is always a directory.
If path refers a mount point (root of directory entry tree within that partition), path.parent refers the same path rather than referring mount point's parent.
Execute a program
path | Requested program's pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
exec | Requested program's pathname, but maybe a symbolic link |
exec.$attribute | Attributes of an object referenced by variable "exec" |
exec.parent.$attribute | Parent directory's attributes |
argc | Number of command line arguments passed to this request |
envc | Number of environment variables arguments |
argv[$index] | $index'th (0 <= $index < argc) value of command line arguments |
envp["$name"] | Value of environment variable named $name |
task.$attribute | Current thread's attributes |
handler | Pathname of a wrapper program for preprocessing (note that this assignment is optional and valid to only "allow" lines) |
transition | New domainname to transit to if operation was successful (note that this assignment is optional and valid to only "allow" lines) |
Allow everybody to execute any program.
Note that this example makes no sense except for auditing purpose.
100 acl execute audit 1 1 allow |
Allow nobody to execute any program.
Note that you should not try this example, or your system will lock up.
100 acl execute audit 1 1 deny |
Deny execution of any program by threads running with UID = 500.
100 acl execute task.uid=500 audit 1 1 deny |
Restrict execution of /sbin/init to only threads running with UID = 0 and GID = 0.
Note that both exec= and path= are checked in this example in case /sbin/init is a symbolic link.
100 acl execute exec="/sbin/init" audit 1 1 allow task.uid=0 task.gid=0 2 deny 200 acl execute path="/sbin/init" audit 1 1 allow task.uid=0 task.gid=0 2 deny |
Deny execution of programs if current thread's UID != the UID of the program to execute.
Note that both exec.uid= and path.uid= are checked in this example in case the program is not owned by current thread's UID
but the symbolic link to the program is owned by current thread's UID (or vice versa).
100 acl execute audit 1 1 deny task.uid!=exec.uid 2 deny task.uid!=path.uid 3 allow |
Deny execution of programs if current thread's UID = 0 and the UID of the program to execute != 0.
100 acl execute task.uid=0 audit 1 1 deny exec.uid!=0 2 deny path.uid!=0 3 allow |
Deny execution of /bin/true if the first command line argument is --help .
100 acl execute exec="/bin/true" argv[1]="--help" audit 1 1 deny 200 acl execute path="/bin/true" argv[1]="--help" audit 1 1 deny |
Note that above example can be written like below example. But be careful with audit log flooding.
Below example generates more audit logs than above example because the rule in below example is unconditionally checked.
100 acl execute audit 1 1 deny exec="/bin/true" argv[1]="--help" 2 deny path="/bin/true" argv[1]="--help" 3 allow |
Deny /usr/sbin/httpd to execute /bin/sh .
2000 acl execute task.exe="/usr/sbin/httpd" audit 1 100 deny exec="/bin/sh" 200 allow |
Restrict /usr/sbin/httpd to execute only /usr/sbin/suexec .
1000 acl execute task.exe="/usr/sbin/httpd" audit 1 100 allow exec="/usr/sbin/suexec" 200 deny |
Restrict execution of /usr/sbin/suexec to only /usr/sbin/httpd .
2000 acl execute exec="/usr/sbin/suexec" audit 1 100 allow task.exe="/usr/sbin/httpd" 200 deny |
execve(2)
Checking handler argument is available only when built with CONFIG_CAITSITH_EXECUTE_HANDLER=y.
Checking other arguments are always available.
Open a pathname for reading
path | Requested pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
Allow only /usr/bin/passwd and /usr/sbin/httpd to open /etc/shadow\* for reading.
Note that this rule cannot prevent diverted accesses such as creating a hard link of /etc/shadow .
100 acl read path="/etc/shadow\*" audit 1 1 allow task.exe="/usr/bin/passwd" 1 allow task.exe="/usr/sbin/sshd" 10 deny |
Restrict threads in "web-server" domain to open only files in "web-contents" group for reading.
Note that you need to append other files because this rule cannot cover all files used by web servers.
string_group web-contents /var/www/html/\(\*\)/\* string_group web-contents /home/\*/public_html/\(\*\)/\* 100 acl read task.domain="web-server" audit 1 1 allow path=@web-contents 10 deny |
Allow only threads in "web-server" domain to open files in "web-contents" group for reading.
Note that this rule cannot prevent diverted accesses such as creating a hard link of files in "web-contents" group.
string_group web-contents /var/www/html/\(\*\)/\* string_group web-contents /home/\*/public_html/\(\*\)/\* 100 acl read path=@web-contents audit 1 1 allow task.domain="web-server" 10 deny |
Allow only threads in "grub" domain to open files in /dev/sda1 partition for reading.
100 acl read path.major=8 path.minor=1 audit 1 1 allow task.domain="grub" 10 deny |
open(2)
Checking directory's permission is available only when built with CONFIG_CAITSITH_READDIR=y.
Checking non-directory's permission is always available.
Open a pathname for writing
path | Requested pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
open(2)
Always available.
Open a pathname for appending
path | Requested pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
open(2)
Always available.
Create a regular file
path | Requested pathname |
perm | DAC permissions of a new object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
open(2), mknod(2)
Always available.
Delete a non-directory pathname
path | Requested pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
unlink(2)
Always available.
Get attributes of a pathname
path | Requested pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
stat(2)
Available only when built with CONFIG_CAITSITH_GETATTR=y.
Create a directory
path | Requested pathname |
perm | DAC permissions of a new object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
mkdir(2)
Always available.
Delete a directory pathname
path | Requested pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
rmdir(2)
Always available.
Create a FIFO
path | Requested pathname |
perm | DAC permissions of a new object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
mknod(2)
Always available.
Create a Unix domain socket
path | Requested pathname |
perm | DAC permissions of a new object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
mknod(2)
Always available.
Truncate a regular file
path | Requested pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
open(2), truncate(2)
Always available.
Create a symbolic link
path | Requested pathname |
target | Symbolic link's content |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
symlink(2)
Always available.
Create a block device file
path | Requested pathname |
perm | DAC permissions of a new object referenced by variable "path" |
dev_major | Major device number of a new object referenced by variable "path" |
dev_minor | Minor device number of a new object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
mknod(2)
Always available.
Create a character device file
path | Requested pathname |
perm | DAC permissions of a new object referenced by variable "path" |
dev_major | Major device number of a new object referenced by variable "path" |
dev_minor | Minor device number of a new object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
mknod(2)
Always available.
Create a link
old_path | Link source's pathname |
new_path | Link target's pathname |
old_path.$attribute | Attributes of an object referenced by variable "old_path" |
old_path.parent.$attribute | Parent directory's attributes |
new_path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
link(2)
Always available.
Rename a pathname
old_path | Old pathname |
new_path | New pathname |
old_path.$attribute | Attributes of an object referenced by variable "old_path" |
old_path.parent.$attribute | Parent directory's attributes |
new_path.$attribute | Attributes of an existing object referenced by variable "new_path" (note that these attributes are available only when "new_path" already exists) |
new_path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
rename(2)
Always available.
Change DAC's permission
path | Requested pathname |
perm | New DAC permissions of an object referenced by variable "path" |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
chmod(2)
Always available.
Change DAC's owner ID
path | Requested pathname |
uid | New DAC owner ID of an object referenced by variable "path" |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
chown(2)
Always available.
Change DAC's group ID
path | Requested pathname |
gid | New DAC group ID of an object referenced by variable "path" |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
chown(2)
Always available.
Use ioctl request
path | Requested pathname |
cmd | Command number for ioctl request |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
ioctl(2)
Always available.
Change root directory
path | Requested pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
chroot(2)
Always available.
Mount a filesystem
source | Source name if filesystem name is one of "--bind", "--move" or a filesystem that requires device file. Unavailable otherwise. |
target | Mount point or target name |
fstype | Filesystem name, determined by below order.
|
flags | Mount flags |
data | Mount options not in mount flags argument (e.g. "errors=remount-ro"). This variable is not available to filesystems that require binary mount options (e.g."nfs", "coda", "ncpfs"). Also, this variable is available only if filesystem type is either "--remount" or name of filesystem. |
source.$attribute | Attributes of an object referenced by variable "source" when variable "source" references a valid pathname |
source.parent.$attribute | Attributes of parent directory of an object referenced by variable "source" when variable "source" references a valid pathname |
target.$attribute | Attributes of an object referenced by variable "target" |
target.parent.$attribute | Attributes of parent directory of an object referenced by variable "target" |
task.$attribute | Current thread's attributes |
Restrict mount operation to allow by only /bin/mount program with one of
combinations.
100 acl mount audit 1 1 deny task.exe!="/bin/mount" 10 allow target="/proc" fstype="proc" flags=0x0 10 allow target="/sys" fstype="sysfs" flags=0x0 10 allow target="/dev/pts" fstype="devpts" flags=0x0 10 allow target="/dev/shm" fstype="tmpfs" flags=0x0 10 allow target="/" fstype="--remount" flags=0x1 10 allow target="/" fstype="--remount" flags=0x400 10 allow target="sysfs:/kernel/security" fstype="securityfs" flags=0x0 100 deny |
Note that mount requests by other than /bin/mount program are denied.
Note that mount requests other than combinations not listed are also denied.
mount(2)
Always available.
Unmount a filesystem
path | Requested pathname |
flags | Unmount flags |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
task.$attribute | Current thread's attributes |
umount(2)
Always available.
Exchange root directory
new_root | New root directory |
put_old | Location to place old root directory |
new_root.$attribute | Attributes of an object referenced by variable "new_root" |
new_root.parent.$attribute | Attributes of parent directory of an object referenced by variable "new_root" |
put_old.$attribute | Attributes of an object referenced by variable "put_old" |
put_old.parent.$attribute | Attributes of parent directory of an object referenced by variable "put_old" |
task.$attribute | Current thread's attributes |
pivot_root(2)
Always available.
Binding PF_INET/PF_INET6+SOCK_STREAM socket
ip | IPv4 or IPv6 address |
port | Port number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
bind(2), ip(7), ipv6(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Listening PF_INET/PF_INET6+SOCK_STREAM socket
ip | IPv4 or IPv6 address |
port | Port number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
listen(2), ip(7), ipv6(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Connecting PF_INET/PF_INET6+SOCK_STREAM socket
ip | IPv4 or IPv6 address |
port | Port number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
connect(2), ip(7), ipv6(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Accepting PF_INET/PF_INET6+SOCK_STREAM socket
ip | IPv4 or IPv6 address |
port | Port number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
accept(2), ip(7), ipv6(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Binding PF_INET/PF_INET6+SOCK_DGRAM socket
ip | IPv4 or IPv6 address |
port | Port number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
bind(2), ip(7), ipv6(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Sending AF_INET/AF_INET6 datagrams
ip | IPv4 or IPv6 address |
port | Port number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
sendmsg(2), ip(7), ipv6(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Receiving AF_INET/AF_INET6 datagrams
ip | IPv4 or IPv6 address |
port | Port number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
recvmsg(2), ip(7), ipv6(7)
Available only when built with CONFIG_CAITSITH_NETWORK_RECVMSG=y.
Binding PF_INET/PF_INET6+SOCK_RAW socket
ip | IPv4 or IPv6 address |
proto | Protocol number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
bind(2), raw(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Sending AF_INET/AF_INET6 packets
ip | IPv4 or IPv6 address |
proto | Protocol number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
sendmsg(2), raw(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Receiving AF_INET/AF_INET6 packets
ip | IPv4 or IPv6 address |
proto | Protocol number |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
recvmsg(2), raw(7)
Available only when built with CONFIG_CAITSITH_NETWORK_RECVMSG=y.
Binding PF_UNIX+SOCK_STREAM socket
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
bind(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Listening PF_UNIX+SOCK_STREAM socket
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
listen(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Connecting PF_UNIX+SOCK_STREAM socket
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
connect(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Accepting PF_UNIX+SOCK_STREAM socket
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
accept(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Binding PF_UNIX+SOCK_DGRAM socket
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
bind(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Sending AF_UNIX datagrams
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
sendmsg(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Receiving AF_UNIX datagrams
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
recvmsg(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK_RECVMSG=y.
Binding PF_UNIX+SOCK_SEQPACKET socket
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
bind(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Listening PF_UNIX+SOCK_SEQPACKET socket
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
listen(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Connecting PF_UNIX+SOCK_SEQPACKET socket
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
connect(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Accepting PF_UNIX+SOCK_SEQPACKET socket
addr | Unix domain socket address |
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is valid to only "allow" lines) |
accept(2), unix(7)
Available only when built with CONFIG_CAITSITH_NETWORK=y.
Call ptrace() system call
cmd | Command number |
domain | Target process's domainname |
task.$attribute | Current thread's attributes |
ptrace(2)
Available only when built with CONFIG_CAITSITH_PTRACE=y.
Send signals
sig | Signal number |
task.$attribute | Current thread's attributes |
kill(2), tkill(2), tgkill(2), rt_sigqueueinfo(2), rt_tgsigqueueinfo(2)
Available only when built with CONFIG_CAITSITH_SIGNAL=y.
Receive environment variables upon program execution
name | Environment variable's name |
value | Environment variable's value |
path | Requested program's pathname |
path.$attribute | Attributes of an object referenced by variable "path" |
path.parent.$attribute | Parent directory's attributes |
exec | Requested program's pathname, but maybe a symbolic link |
exec.$attribute | Attributes of an object referenced by variable "exec" |
exec.parent.$attribute | Parent directory's attributes |
argc | Number of command line arguments passed to this request |
envc | Number of environment variables arguments |
argv[$index] | $index'th (0 <= $index < argc) value of command line arguments |
envp["$name"] | Value of environment variable named $name |
task.$attribute | Current thread's attributes |
execve(2)
Available only when built with CONFIG_CAITSITH_ENVIRON=y.
Modify policy configuration
task.$attribute | Current thread's attributes |
none
Always available.
Create PF_NETLINK socket
task.$attribute | Current thread's attributes |
socket(2), netlink(7)
Available only when built with CONFIG_CAITSITH_CAPABILITY=y.
Create PF_PACKET socket
task.$attribute | Current thread's attributes |
socket(2), packet(7)
Available only when built with CONFIG_CAITSITH_CAPABILITY=y.
Call reboot() system call
task.$attribute | Current thread's attributes |
reboot(2)
Available only when built with CONFIG_CAITSITH_CAPABILITY=y.
Call vhangup() system call
task.$attribute | Current thread's attributes |
vhangup(2)
Available only when built with CONFIG_CAITSITH_CAPABILITY=y.
Set system's time
task.$attribute | Current thread's attributes |
stime(2), settimeofday(2), adjtimex(2)
Available only when built with CONFIG_CAITSITH_CAPABILITY=y.
Change process's priority
task.$attribute | Current thread's attributes |
nice(2), setpriority(2)
Available only when built with CONFIG_CAITSITH_CAPABILITY=y.
Set host's name
task.$attribute | Current thread's attributes |
sethostname(2), setdomainname(2)
Available only when built with CONFIG_CAITSITH_CAPABILITY=y.
Load or unload kernel modules
task.$attribute | Current thread's attributes |
init_module(2), delete_module(2)
Available only when built with CONFIG_CAITSITH_CAPABILITY=y.
Load a new kernel
task.$attribute | Current thread's attributes |
kexec_load(2)
Available only when built with CONFIG_CAITSITH_CAPABILITY=y.
Change domains by writing to /sys/kernel/security/caitsith/self_domain
domain | Domainname to allow transition to |
task.$attribute | Current thread's attributes |
none
Available only when built with CONFIG_CAITSITH_MANUAL_DOMAIN_TRANSITION=y.
Change domains automatically upon conditions are met
task.$attribute | Current thread's attributes |
transition | New domainname to transit to if conditions are met (note that this assignment is mandatory and valid to only "allow" lines) |
none
Available only when built with CONFIG_CAITSITH_AUTO_DOMAIN_TRANSITION=y.
Below are some hints for utilizing CaitSith more powerfully.
Domains can be used instead of program's pathnames for grouping purpose. For example,
100 acl read path="/etc/shadow" audit 1 10 deny task.exe="/bin/cat" 100 allow task.exe="/usr/bin/passwd" 100 allow task.exe="/usr/sbin/sshd" 10000 deny
can be written like below if you manage domains appropriately.
100 acl read path="/etc/shadow" audit 1 100 allow task.domain="passwd" 100 allow task.domain="sshd" 10000 deny
You can control domain transition in the acl execute blocks.
The priority controls which "transition=" argument should be used when this argument matched more than once. In the example below, 2 "acl execute" blocks with 5 transition= arguments are defined. (Note that conditional expressions such as path.uid=task.uid and path.uid!=task.uid are simplified as conditions$X for the purpose of illustration.)
10 acl execute conditions1 audit 0 10 allow conditions2 transition="domainname1" 20 allow conditions3 20 allow conditions4 transition="domainname2" 20 acl execute conditions5 audit 0 10 allow conditions6 transition="domainname3" 20 allow conditions7 transition=NULL 20 allow conditions8 transition="domainname4"
Domain transition is determined from the first matching transition= argument of allow lines, and keeps current domain if none of matching transition= argument was found. In other words,
Although variables for inspecting command line arguments and environment variables are available, sometimes it is too complicated to check them. Also, sometimes you may want to do some preprocessing operations before starting specific programs.
You can apply execute handler in the acl execute blocks.
The priority controls which "handler=" argument should be used when this argument matched more than once. In the example below, 2 "acl execute" blocks with 5 handler= arguments are defined. (Note that conditional expressions such as path.uid=task.uid and path.uid!=task.uid are simplified as conditions$X for the purpose of illustration.)
10 acl execute conditions1 audit 0 10 allow conditions2 handler="/path/to/handler1" 20 allow conditions3 20 allow conditions4 handler="/path/to/handler2" 20 acl execute conditions5 audit 0 10 allow conditions6 handler="/path/to/handler3" 20 allow conditions7 handler=NULL 20 allow conditions8 handler="/path/to/handler4"
Execute handler is determined from the first matching handler= argument of allow lines, and does not use it if none of matching handler= argument was found. In other words,
Please see usr_lib_caitsith/audit-exec-param.c included in the caitsith-tools-0.2-20241111.tar.gz as an example of using execute handler program.