Info: Version 1.8.x is available.

Japanese Page

Last modified: $Date: 2024-03-30 11:25:00 +0000 (Sat, 30 Mar 2024) $

Policy Specifications of TOMOYO Linux

Index

1. Keywords Index

2. Introduction

2.1 Word Expression Rules

2.2 Wildcard Expression Rules

2.3 Memory Usage Information

3. Policy Files

3.1 Policy File's Location

3.2 Policy File's Modification

4. Domain Rules

4.1 Domain Definition

4.2 Domain Transition

4.3 Access Logs

5. Syntax Details

6. Advanced Features

6.1 Allowing policy modification by non root user.

6.2 Using conditional ACL.

6.3 Using stateful ACL.

6.4 Sleep penalty for policy violation.

6.5 Judging execute request outside the kernel.

6.6 Invoking alternative program for execute requests that are not permitted by policy.


1. Keywords Index

Used by /proc/ccs/profile and /etc/ccs/profile.conf

Used by /proc/ccs/exception_policy and /etc/ccs/exception_policy.conf

Used by /proc/ccs/domain_policy and /etc/ccs/domain_policy.conf

Used by /proc/ccs/manager and /etc/ccs/manager.conf

2. Introduction

2.1 Word Expression Rules

TOMOYO Linux performs pathname based access control. A pathname may contain not only alphabet and number but also space and carriage return and multibyte (e.g. kanji) characters. Thus, to be able to handle any characters correctly, TOMOYO Linux follows the rules shown below to represent a word. A word means all tokens that are treated as string data, such as pathnames, comments, environment variable's names, parameters for program execution.

Lower 4 bits
Higher 4 bits
0x00x10x20x30x40x50x60x70x80x90xA0xB0xC0xD0xE0xF
0x0\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!"#$%&'()*+,-./
0x30123456789:;<=>?
0x4@ABCDEFGHIJKLMNO
0x5PQRSTUVWXYZ[\\]^_
0x6`abcdefghijklmno
0x7pqrstuvwxyz{|}~\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.

WordCorrect expressionWrong expression
Hello world!Hello\040world!"Hello world!"
/home/user/Documents and Settings//home/user/Documents\040and\040Settings//home/user/Documents and Settings/

Pathname must start with / character. Pathnames that end with / character are interpreted as directories, and that don't end with / character are interpreted as non-directories.

PathnameInterpretation
/A directory
/tmp/A directory
/tmpNot a directory
tmp/Invalid pathname

Exceptions are pipes and sockets. Pipes begin with "pipe:" and sockets begin with "socket:" when these pathnames are accessed via /proc/PID/fd/ directory.

2.2 Wildcard Expression Rules

Like temporary files, pathnames may contain randomly selected characters. Thus, you often need to define pathnames using wildcards. TOMOYO Linux supports wildcards shown below.

WildcardMeaningExample
\*Zero or more repetitions of characters other than '/'./var/log/samba/\*
\@Zero or more repetitions of characters other than '/' or '.'./var/www/html/\@.html
\?1 byte character other than '/'./tmp/mail.\?\?\?\?\?\?
\$One or more repetitions of decimal digits./proc/\$/cmdline
\+1 decimal digit./var/tmp/my_work.\+
\XOne or more repetitions of hexadecimal digits./var/tmp/my-work.\X
\x1 hexadecimal digit./tmp/my-work.\x
\AOne or more repetitions of alphabet characters./var/log/my-work/\$-\A-\$.log
\a1 alphabet character./home/users/\a/\*/public_html/\*.html
\-Pathname subtraction operator.
  • /etc/\* for all files in /etc/ directory.
  • /etc/\*\-\*shadow\* for /etc/\* other than /etc/\*shadow\*
  • /\*\-proc\-sys/ for /\*/ other than /proc/ /sys/
/\{dir\}/Recursive directory matching operator which matches '/' + one or more repetitions of 'dir/'. (Valid only in 1.7.1 and later.)
  • /var/www/html/\{\*\}/\*.html for /var/www/html/\*/\*.html /var/www/html/\*/\*/\*.html /var/www/html/\*/\*/\*/\*.html etc.
  • /home/\*/\{\*\-.\*\}/\* for /home/\*/\*\-.\*/\* /home/\*/\*\-.\*/\*\-.\*/\* /home/\*/\*\-.\*/\*\-.\*/\*\-.\*/\* etc.

2.3 Memory Usage Information

The memory used by TOMOYO Linux can be obtained via /proc/ccs/meminfo . The unit is byte.

# cat /proc/ccs/meminfo
Policy:          377376
Audit logs:           0
Query lists:          0
Total:           377376

TOMOYO Linux supports memory quota for limiting maximum memory used by TOMOYO Linux.

You can set memory quota by writing to /etc/ccs/meminfo.conf .

# cat /etc/ccs/meminfo.conf
Policy: 16777216
Audit logs: 1048576
Query lists: 1048576

3. Policy Files

3.1 Policy File's Location

Policy files are files that contain access permissions. These files are automatically loaded into the kernel upon boot.

When a system boots, /sbin/init is executed. When the execution of /sbin/init is requested and if /sbin/ccs-init exists, /sbin/ccs-init is executed, and /sbin/init is executed after /sbin/ccs-init terminates.

/sbin/ccs-init loads policy files in /etc/ccs/ directory via the kernel's /proc/ccs/ interface.

The kernel's interfacePolicy fileContents
/proc/ccs/profile/etc/ccs/profile.confProfiles (Collection of access control levels)
/proc/ccs/manager/etc/ccs/manager.confManagers (Programs that can modify policy via /proc/ccs/ interface)
/proc/ccs/exception_policy/etc/ccs/exception_policy.confException policy (Collection of exceptions for domain policy)
/proc/ccs/domain_policy/etc/ccs/domain_policy.confDomain policy (Access permissions given to individual domains)
/proc/ccs/meminfo/etc/ccs/meminfo.confMemory usage and quota.

There are more interfaces for obtaining information. These interfaces don't have corresponding policy files.

The kernel's interfaceMeaning
/proc/ccs/queryAccess requests that are waiting for administrator's decision.
/proc/ccs/.domain_statusThe list of domainnames and profile numbers currently defined in domain policy.
/proc/ccs/grant_logAccess requests that didn't violate domain policy.
/proc/ccs/reject_logAccess requests that violated domain policy.
/proc/ccs/self_domainThe name of domain the current process belongs to.
/proc/ccs/.process_statusThe list of domainnames and profile numbers currently running processes belongs to.
/proc/ccs/versionVersion of TOMOYO Linux.

3.2 Policy File's Modification

Register the name of programs or domains that can modify policy via the kernel's /proc/ccs/ interface. Only

can modify policy via the kernel's /proc/ccs/ interface. Some examples are show below.

# cat /proc/ccs/manager
/usr/sbin/ccs-loadpolicy
/usr/sbin/ccs-editpolicy
/usr/sbin/ccs-setlevel
/usr/sbin/ccs-setprofile
/usr/sbin/ccs-ld-watch
/usr/sbin/ccs-queryd
<kernel> /sbin/mingetty /bin/login /bin/bash

By default, only processes with UID = 0 and EUID = 0 can modify policy via this interface. But by doing configurations described in Allowing policy modification by non root user., non root user can modify policy via this interface.

Exception is, processes that belong to domains with profiles for learning mode can append access permissions to /proc/ccs/domain_policy by simply requesting the access.

4. Domain Rules

4.1 Domain Definition

TOMOYO Linux gives access permissions as per a domain. It is managed via /proc/ccs/domain_policy.

In TOMOYO Linux, every process belongs to a single domain, and all programs belong to different domain. Even the two processes are executing the same program, if their previous domains differ, they belong to different domain.

All domains are defined originating from "<kernel>" domain, which the kernel process belongs to. Since /sbin/init is invoked by the "<kernel>" domain, the domain for /sbin/init is defined as "<kernel> /sbin/init". Since /etc/rc.d/rc is invoked by /sbin/init invoked by the kernel, the domain for /etc/rc.d/rc is defined as "<kernel> /sbin/init /etc/rc.d/rc".

4.2 Domain Transition

When a process tries to execute a program, the steps shown below are performed.

StepProcedure
Getting program's name

Get the name of program that the process is going to execute and keep it as "Candidate". This procedure does not solve symbolic link if the program is a symbolic link.

Aggregating similar programs

Search exception policy for

  • aggregator "Candidate" "aggregated name"

and if found one, replace "Candidate" with "aggregated name".

Checking permission

Search domain policy for

  • allow_execute "Candidate"
  • allow_execute @"a pathname group containing Candidate"

and deny the execute request if not found one.

Deciding destination domain

(1) Search exception policy for

  • no_initialize_domain "Candidate" from "the name of the domain the current process belongs to"
  • no_initialize_domain "Candidate" from "the last part of the name of the domain the current process belongs to"
  • no_initialize_domain "Candidate"

and if found one, jump to (3).

(2) Search exception policy for

  • initialize_domain "Candidate" from "the name of the domain the current process belongs to"
  • initialize_domain "Candidate" from "the last part of the name of the domain the current process belongs to"
  • initialize_domain "Candidate"

and if found one, concatenate "the name of the domain that the kernel belongs to (i.e. <kernel>)" and "Candidate" and keep the result as destination domain, then jump to (6).

(3) Search exception policy for

  • no_keep_domain "Candidate" from "the name of the domain the current process belongs to"
  • no_keep_domain "Candidate" from "the last part of the name of the domain the current process belongs to"
  • no_keep_domain "the name of the domain the current process belongs to"
  • no_keep_domain "the last part of the name of the domain the current process belongs to"

and if found one, jump to (5).

(4) Search exception policy for

  • keep_domain "Candidate" from "the name of the domain the current process belongs to"
  • keep_domain "Candidate" from "the last part of the name of the domain the current process belongs to"
  • keep_domain "the name of the domain the current process belongs to"
  • keep_domain "the last part of the name of the domain the current process belongs to"

and if found one, set "the name of the domain the current process belongs to" as destination domain, then jump to (6).

(5) Concatenate "the name of the domain the current process belongs to" and "Candidate" and keep the result as destination domain.

(6) Check whether the destination domain is defined, and deny the execute request if not.

Checking environment variable names

(1) Examine all environment variables' names are granted in the destination domain, and deny the execute request if more than one of them are not granted.

(2) Perform regular steps for executing program. If successfully completed, the process transits to destination domain.

There is an exception. If either

and

the steps shown below are performed instead for the steps shown above. The usage of this exception is explained in "Judging execute request outside the kernel." and "Invoking alternative program for execute requests that are not permitted by policy."

StepProcedure
Getting program's name

Keep the pathname of the program specified by denied_execute_handler or execute_handler and keep it as "Candidate".

Appending information

Append all environment variables to the tail of arguments, and delete all environment variables.

Insert "Candidate" "the domainname the process that issued execute request belongs to" "the pathname of the process that issued execute request" "state of the process that issued execute request" "the pathname of the requested program" "number of arguments" "number of environment variables" to the top of arguments.

Deciding destination domain

(1) Search exception policy for

  • no_initialize_domain "Candidate" from "the name of the domain the current process belongs to"
  • no_initialize_domain "Candidate" from "the last part of the name of the domain the current process belongs to"
  • no_initialize_domain "Candidate"

and if found one, jump to (3).

(2) Search exception policy for

  • initialize_domain "Candidate" from "the name of the domain the current process belongs to"
  • initialize_domain "Candidate" from "the last part of the name of the domain the current process belongs to"
  • initialize_domain "Candidate"

and if found one, concatenate "the name of the domain that the kernel belongs to (i.e. <kernel>)" and "Candidate" and keep the result as destination domain, then jump to (6).

(3) Search exception policy for

  • no_keep_domain "Candidate" from "the name of the domain the current process belongs to"
  • no_keep_domain "Candidate" from "the last part of the name of the domain the current process belongs to"
  • no_keep_domain "the name of the domain the current process belongs to"
  • no_keep_domain "the last part of the name of the domain the current process belongs to"

and if found one, jump to (5).

(4) Search exception policy for

  • keep_domain "Candidate" from "the name of the domain the current process belongs to"
  • keep_domain "Candidate" from "the last part of the name of the domain the current process belongs to"
  • keep_domain "the name of the domain the current process belongs to"
  • keep_domain "the last part of the name of the domain the current process belongs to"

and if found one, set "the name of the domain the current process belongs to" as destination domain, then jump to (6).

(5) Concatenate "the name of the domain the current process belongs to" and "Candidate" and keep the result as destination domain.

(6) Check whether the destination domain is defined, and deny the execute request if not.

Execute program

Perform regular steps for executing program. If successfully completed, the process transits to destination domain.

4.3 Access Logs

TOMOYO Linux generates two types of access logs. One contains access requests that didn't violate domain policy. The other contains access requests that violated domain policy. The former is called grant log and is readable via /proc/ccs/grant_log . The latter is called reject log and is readable via /proc/ccs/reject_log . A utility program /usr/sbin/ccs-auditd is included for reading these logs and saving the logs as files.

Some examples are shown below. The first log is generated by execute request.

#2010-01-13 21:00:50# profile=1 mode=learning (global-pid=2908) task={ pid=2908 ppid=2879 uid=0 gid=0 euid=0 egid=0 suid=0 sgid=0 fsuid=0 fsgid=0 state[0]=0 state[1]=0 state[2]=0 type!=execute_handler } path1={ uid=0 gid=0 ino=852049 major=8 minor=1 perm=0755 type=file } path1.parent={ uid=0 gid=0 ino=851969 perm=0755 } exec={ realpath="/bin/cat" argc=2 envc=20 argv[]={ "cat" "/etc/fstab" } envp[]={ "HOSTNAME=tomoyo" "TERM=vt100" "SHELL=/bin/bash" "HISTSIZE=1000" "SSH_CLIENT=192.168.1.2\0402845\04022" "SSH_TTY=/dev/pts/0" "USER=root" "LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:" "MAIL=/var/spool/mail/root" "PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/sbin:/root/bin" "PWD=/root" "LANG=C" "SHLVL=1" "HOME=/root" "LOGNAME=root" "CVS_RSH=ssh" "SSH_CONNECTION=192.168.1.2\0402845\040192.168.1.7\04022" "LESSOPEN=|/usr/bin/lesspipe.sh\040%s" "G_BROKEN_FILENAMES=1" "_=/bin/cat" } }
<kernel> /usr/sbin/sshd /bin/bash
allow_execute /bin/cat

This log shows that a process that belongs to "<kernel> /usr/sbin/sshd /bin/bash" domain attempted to execute /bin/cat , and the arguments were "cat" and "/etc/fstab", environment variables were "HOSTNAME=tomoyo" "TERM=vt100" "SHELL=/bin/bash" "HISTSIZE=1000" "SSH_CLIENT=192.168.1.2\0402845\04022" "SSH_TTY=/dev/pts/0" "USER=root" "LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:" "MAIL=/var/spool/mail/root" "PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/sbin:/root/bin" "PWD=/root" "LANG=C" "SHLVL=1" "HOME=/root" "LOGNAME=root" "CVS_RSH=ssh" "SSH_CONNECTION=192.168.1.2\0402845\040192.168.1.7\04022" "LESSOPEN=|/usr/bin/lesspipe.sh\040%s" "G_BROKEN_FILENAMES=1" "_=/bin/cat". Also, process information such as PID, UID are shown.

The next log is generated by opening a file for reading.

#2010-01-13 21:00:50# profile=1 mode=learning (global-pid=2908) task={ pid=2908 ppid=2879 uid=0 gid=0 euid=0 egid=0 suid=0 sgid=0 fsuid=0 fsgid=0 state[0]=0 state[1]=0 state[2]=0 type!=execute_handler } path1={ uid=0 gid=0 ino=901920 major=8 minor=1 perm=0644 type=file } path1.parent={ uid=0 gid=0 ino=901121 perm=0755 }
<kernel> /usr/sbin/sshd /bin/bash /bin/cat
allow_read /etc/fstab

This log shows that a process that belongs to "<kernel> /usr/sbin/sshd /bin/bash /bin/cat" domain opened /etc/fstab for reading.

The next log is generated when a new domain is created.

#2010-01-13 21:05:22# profile=1 mode=learning (global-pid=3007) task={ pid=3007 ppid=2991 uid=0 gid=0 euid=0 egid=0 suid=0 sgid=0 fsuid=0 fsgid=0 state[0]=0 state[1]=0 state[2]=0 type=execute_handler }
<kernel> /usr/sbin/sshd /bin/bash /bin/bash /bin/audit-exec-param /bin/cat
use_profile 1

This log shows that a domain named "<kernel> /usr/sbin/sshd /bin/bash /bin/bash /bin/audit-exec-param /bin/cat" was created and profile 1 was assigned. TOMOYO Linux automatically creates domains as needed. When a domain is automatically created, the profile number of the domain the process that requested program execution belongs to is inherited.

The next log is generated when a program that is different from the program being requested was executed because of Judging execute request outside the kernel.

#2010-01-13 21:05:22# profile=1 mode=learning (global-pid=3007) task={ pid=3007 ppid=2991 uid=0 gid=0 euid=0 egid=0 suid=0 sgid=0 fsuid=0 fsgid=0 state[0]=0 state[1]=0 state[2]=0 type!=execute_handler } path1={ uid=0 gid=0 ino=360482 major=8 minor=1 perm=0755 type=file } path1.parent={ uid=0 gid=0 ino=851969 perm=0755 } exec={ realpath="/bin/audit-exec-param" argc=29 envc=0 argv[]={ "/bin/audit-exec-param" "<kernel>\040/usr/sbin/sshd\040/bin/bash\040/bin/bash" "/bin/bash" "pid=3007\040uid=0\040gid=0\040euid=0\040egid=0\040suid=0\040sgid=0\040fsuid=0\040fsgid=0\040state[0]=0\040state[1]=0\040state[2]=0" "/bin/cat" "2" "20" "cat" "/etc/fstab" "HOSTNAME=tomoyo" "SHELL=/bin/bash" "TERM=vt100" "HISTSIZE=1000" "SSH_CLIENT=192.168.1.2\0402845\04022" "SSH_TTY=/dev/pts/0" "USER=root" "LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:" "PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/sbin:/root/bin:/usr/sbin" "MAIL=/var/spool/mail/root" "PWD=/root" "LANG=C" "HOME=/root" "SHLVL=2" "LOGNAME=root" "CVS_RSH=ssh" "SSH_CONNECTION=192.168.1.2\0402845\040192.168.1.7\04022" "LESSOPEN=|/usr/bin/lesspipe.sh\040%s" "G_BROKEN_FILENAMES=1" "_=/bin/cat" } envp[]={ } }
<kernel> /usr/sbin/sshd /bin/bash /bin/bash
execute_handler /bin/audit-exec-param

This log shows that a process that belongs to a domain named "<kernel> /usr/sbin/sshd /bin/bash /bin/bash" attempted to execute a program, but since the execute_handler keyword is specified to the domain, /bin/audit-exec-param was executed, and arguments passed to /bin/audit-exec-param were "/bin/audit-exec-param" "<kernel>\040/usr/sbin/sshd\040/bin/bash\040/bin/bash" "/bin/bash" "pid=3007\040uid=0\040gid=0\040euid=0\040egid=0\040suid=0\040sgid=0\040fsuid=0\040fsgid=0\040state[0]=0\040state[1]=0\040state[2]=0" "/bin/cat" "2" "20" "cat" "/etc/fstab" "HOSTNAME=tomoyo" "SHELL=/bin/bash" "TERM=vt100" "HISTSIZE=1000" "SSH_CLIENT=192.168.1.2\0402845\04022" "SSH_TTY=/dev/pts/0" "USER=root" "LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:" "PATH=/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/sbin:/root/bin:/usr/sbin" "MAIL=/var/spool/mail/root" "PWD=/root" "LANG=C" "HOME=/root" "SHLVL=2" "LOGNAME=root" "CVS_RSH=ssh" "SSH_CONNECTION=192.168.1.2\0402845\040192.168.1.7\04022" "LESSOPEN=|/usr/bin/lesspipe.sh\040%s" "G_BROKEN_FILENAMES=1" "_=/bin/cat". To avoid /bin/audit-exec-param affected by environment variables such as LD_PRELOAD, environment variables are moved to arguments.

In this way, an access log consists of 3 lines (or 4 lines since /usr/sbin/ccs-auditd inserts an empty line), and they are in the domain policy format and appendable to the domain policy. Pick up portions you want to permit from reject log and save (for example, /var/log/tomoyo/diff.txt) and you can add to domain policy by doing

# /usr/sbin/ccs-loadpolicy -d < /var/log/tomoyo/diff.txt

Therefore, you don't need to use "learning mode" from the beginning. If you wish, you can use "permissive mode" from the beginning and let reject logs generated, then edit reject logs and append to domain policy when developing domain policy. When domain policy is generated by "learning mode", process state (the first line of an access logs) is not taken into account. But when domain policy is generated from reject logs, you can use Using conditional ACL. from the beginning. For example, generate a reject log by not using "learning mode" and append like

<kernel> /usr/sbin/sshd /bin/bash
allow_execute /bin/cat if exec.argc=2 exec.realpath="/bin/cat" exec.argv[0]="cat" exec.argv[1]="/etc/fstab"

then, you can give more precise permission compared to the permission appended by "learning mode"'s log (shown below).

<kernel> /usr/sbin/sshd /bin/bash
allow_execute /bin/cat if exec.realpath="/bin/cat" exec.argv[0]="cat"

5. Syntax Details

/proc/ccs/profile

TOMOYO Linux can perform several MACs besides MAC for files, but to reduce the load of policy managements, you can disable MACs you think unnecessary.

List up functions and their modes in "$number-$variable=$value" format. The $number is profile number between 0 and 255. To modify profile, use "ccs-setlevel" or "ccs-loadpolicy" commands.

Each domain is assigned one profile. To assign profile to domains, use "ccs-setprofile" or "ccs-editpolicy" or "ccs-loadpolicy" commands.

You can see profiles currently assigned to domains using "ccs-editpolicy" command.
You can see profiles currently assigned to processes using "ccs-pstree" command.
If you saved current policy using "ccs-savepolicy" command, the currently assigned profile number is saved as use_profile line of domain policy.

To read or modify current profiles, operate like below.

(Example)
cat /proc/ccs/profile
ccs-savepolicy -p
ccs-setlevel 1-CONFIG::file::execute=learning
echo 1-CONFIG::file::execute=learning | ccs-loadpolicy -p

See also: Policy File's Modification

You can specify one of modes shown below for functionalities that start with "CONFIG".

ConfigurationMeaning
mode=disabledDisabled. Works as if regular kernel.
mode=learningLearning mode. An access request is not rejected even if the request violates policy. Also, the permission to allow the request is automatically added to policy so that the same request no longer violates policy.
mode=permissivePermissive mode. An access request is not rejected even if the request violates policy. But, the permission to allow the request is not added to policy.
mode=enforcingEnforcing mode. An access request is rejected if the request violates policy.
grant_log=yesGenerate grant logs. The max entries are controlled via "max_grant_log=" parameter of "PREFERENCE::audit" line.
grant_log=noDon't generate grant logs.
reject_log=yesGenerate reject logs. The max entries are controlled via "max_reject_log=" parameter of "PREFERENCE::audit" line.
reject_log=noDon't generate reject logs.

CONFIG::file::execute

Specifies access control level regarding program execution and domain transition.

CONFIG::file::transit

Specifies access control level regarding domain transition without program execution. (Valid only in 1.7.2 and later.)

CONFIG::file::open

Specifies access control level regarding file open for reading and/or writing.

CONFIG::file::create

Specifies access control level regarding file create.

CONFIG::file::unlink

Specifies access control level regarding file delete.

CONFIG::file::mkdir

Specifies access control level regarding directory create.

CONFIG::file::rmdir

Specifies access control level regarding directory delete.

CONFIG::file::mkfifo

Specifies access control level regarding fifo create.

CONFIG::file::mksock

Specifies access control level regarding UNIX domain socket create.

CONFIG::file::truncate

Specifies access control level regarding file truncate.

CONFIG::file::symlink

Specifies access control level regarding symlink create.

CONFIG::file::rewrite

Specifies access control level regarding file overwrite.

CONFIG::file::mkblock

Specifies access control level regarding block device file create.

CONFIG::file::mkchar

Specifies access control level regarding character device file create.

CONFIG::file::link

Specifies access control level regarding link create.

CONFIG::file::rename

Specifies access control level regarding rename.

CONFIG::file::chmod

Specifies access control level regarding chmod.

CONFIG::file::chown

Specifies access control level regarding chown.

CONFIG::file::chgrp

Specifies access control level regarding chgrp.

CONFIG::file::ioctl

Specifies access control level regarding ioctl.

CONFIG::file::chroot

Specifies access control level regarding chroot.

CONFIG::file::mount

Specifies access control level regarding mount.

CONFIG::file::umount

Specifies access control level regarding umount.

CONFIG::file::pivot_root

Specifies access control level regarding pivot_root.

CONFIG::misc::env

Specifies access control level regarding environment variable names (a.k.a. envp[]).

CONFIG::capability::inet_tcp_create

Specifies access control level regarding creation of TCP sockets.

CONFIG::capability::inet_tcp_listen

Specifies access control level regarding TCP socket's listen operation.

CONFIG::capability::inet_tcp_connect

Specifies access control level regarding TCP socket's connect operation.

CONFIG::capability::use_inet_udp

Specifies access control level regarding use of UDP sockets.

CONFIG::capability::use_inet_ip

Specifies access control level regarding use of RAW sockets.

CONFIG::capability::use_route

Specifies access control level regarding use of ROUTE sockets.

CONFIG::capability::use_packet

Specifies access control level regarding use of PACKET sockets.

CONFIG::capability::use_kernel_module

Specifies access control level regarding use of create_module(2) init_module(2) delete_module(2) syscall.

CONFIG::capability::create_fifo

Specifies access control level regarding creation of FIFO using mknod(2) syscall.

CONFIG::capability::create_block_dev

Specifies access control level regarding creation of block device file using mknod(2) syscall.

CONFIG::capability::create_char_dev

Specifies access control level regarding creation of character device file using mknod(2) syscall.

CONFIG::capability::create_unix_socket

Specifies access control level regarding creation of UNIX domain socket using mknod(2) syscall.

CONFIG::capability::SYS_MOUNT

Specifies access control level regarding use of mount(2) syscall.

CONFIG::capability::SYS_UMOUNT

Specifies access control level regarding use of umount(2) syscall.

CONFIG::capability::SYS_REBOOT

Specifies access control level regarding use of reboot(2) syscall.

CONFIG::capability::SYS_CHROOT

Specifies access control level regarding use of chroot(2) syscall.

CONFIG::capability::SYS_KILL

Specifies access control level regarding use of kill(2) tkill(2) tgkill(2) syscall with non 0 signal.

CONFIG::capability::SYS_VHANGUP

Specifies access control level regarding use of vhangup(2) syscall.

CONFIG::capability::SYS_TIME

Specifies access control level regarding use of stime(2) settimeofday(2) adjtimex(2) syscall.

CONFIG::capability::SYS_NICE

Specifies access control level regarding use of nice(2) setpriority(2) syscall.

CONFIG::capability::SYS_SETHOSTNAME

Specifies access control level regarding use of sethostname(2) setdomainname(2) syscall.

CONFIG::capability::SYS_LINK

Specifies access control level regarding use of link(2) syscall.

CONFIG::capability::SYS_SYMLINK

Specifies access control level regarding use of symlink(2) syscall.

CONFIG::capability::SYS_RENAME

Specifies access control level regarding use of rename(2) syscall.

CONFIG::capability::SYS_UNLINK

Specifies access control level regarding use of unlink(2) syscall.

CONFIG::capability::SYS_CHMOD

Specifies access control level regarding use of chmod(2) fchmod(2) syscall.

CONFIG::capability::SYS_CHOWN

Specifies access control level regarding use of chown(2) fchown(2) lchown(2) syscall.

CONFIG::capability::SYS_IOCTL

Specifies access control level regarding use of ioctl(2) compat_sys_ioctl(2) syscall.

CONFIG::capability::SYS_KEXEC_LOAD

Specifies access control level regarding use of kexec_load(2) syscall.

CONFIG::capability::SYS_PIVOT_ROOT

Specifies access control level regarding use of pivot_root(2) syscall.

CONFIG::capability::SYS_PTRACE

Specifies access control level regarding use of ptrace(2) syscall.

CONFIG::capability::conceal_mount

Specifies access control level regarding mount requests that shadow existent mounts.

CONFIG::network::inet_udp_bind

Specifies access control level regarding UDP socket's local address restriction.

CONFIG::network::inet_udp_connect

Specifies access control level regarding UDP socket's remote address restriction.

CONFIG::network::inet_tcp_bind

Specifies access control level regarding TCP socket's bind() operation.

CONFIG::network::inet_tcp_listen

Specifies access control level regarding TCP socket's listen() operation.

CONFIG::network::inet_tcp_connect

Specifies access control level regarding TCP socket's connect() operation.

CONFIG::network::inet_tcp_accept

Specifies access control level regarding TCP socket's accept() operation.

CONFIG::network::inet_raw_bind

Specifies access control level regarding RAW socket's local address restriction.

CONFIG::network::inet_raw_connect

Specifies access control level regarding RAW socket's remote address restriction.

CONFIG::ipc::signal

Specifies access control level regarding signal transmission requests.

PREFERENCE::audit

Specifies preference on auditing.

"max_grant_log=" limits the max number of grant logs that the kernel can hold.

"max_reject_log=" limits the max number of reject logs that the kernel can hold.

PREFERENCE::learning

Specifies preference on learning mode.

"verbose=" controls whether to print policy violation messages or not.

"max_entry=" controls the max number of ACL entries that are automatically appended.

"exec.realpath=" controls whether the dereferenced pathname of the requested program should be learned when adding an "allow_execute" entry.

"exec.argv0=" controls whether the invocation name should be learned when adding an "allow_execute" entry.

"symlink.target=" controls whether the content of the symbolic link should be learned when adding an "allow_symlink" entry.

PREFERENCE::permissive

Specifies preference on permissive mode.

"verbose=" controls whether to print policy violation messages or not.

PREFERENCE::enforcing

Specifies preference on enforcing mode.

"verbose=" controls whether to print policy violation messages or not.

"penalty=" controls how long (in units of 0.1 second) should the process that violated policy sleep for.

/proc/ccs/domain_policy

This file contains definition of all domains and permissions that are granted to each domain.

Lines from the next line to a domain definition ( any lines starting with "<kernel>") to the previous line to the next domain definitions are interpreted as access permissions for that domain.

You can specify additional conditions as needed. The syntax for specifying additional conditions are described in Using conditional ACL. Also, how to switch process's state as needed and use the process's state for conditions is described in Using stateful ACL.

To read or modify current domain policy, operate like below.

(Example) Selecting specific domain and appending ACLs. The domain will be created if nonexistent.
printf "<kernel> /sbin/init\nallow_read /etc/passwd\n" | ccs-loadpolicy -d

(Example) Selecting specific domain and appending ACLs. The domain won't be created if nonexistent.
printf "select <kernel> /sbin/init\nallow_read /etc/passwd\n" | ccs-loadpolicy -d

(Example) Selecting specific domain and removing ACLs.
printf "select <kernel> /sbin/init\ndelete allow_read /etc/passwd\ndelete allow_read /etc/shadow\n" | ccs-loadpolicy -d

(Example) Deleting specific domain.
printf "delete <kernel> /sbin/init\n" | ccs-loadpolicy -d

(Example) Reading current domain policy.
cat /proc/ccs/domain_policy

See also: Policy File's Modification

allow_execute

This keyword grants execution of the specified pathname. No wildcards are permitted for the pathname. If you have to use wildcards, use aggregator keyword before granting execute permission using this keyword.

(Example) allow_execute /bin/ls

See also: Domain Transition aggregator

allow_transit

This keyword grants domain transition to the specified pathname without executing program. No wildcards are permitted for the pathname. (Valid only in 1.7.2 and later.)

(Example) allow_transit //app=cgi1\040id=10000

allow_write

This keyword grants the specified pathname to be opened for writing.

(Example) allow_write /dev/null

See also: path_group

allow_read

This keyword grants the specified pathname to be opened for reading.

(Example) allow_read /proc/meminfo

See also: path_group

allow_read/write

This keyword grants the specified pathname to be opened for reading and writing.

(Example) allow_read/write /dev/null

See also: path_group

allow_create

This keyword grants the specified pathname to be created.

(Example) allow_create /var/lock/subsys/crond 0644

See also: path_group

allow_unlink

This keyword grants the specified pathname to be deleted.

(Example) allow_unlink /var/lock/subsys/crond

See also: path_group

allow_mkdir

This keyword grants the specified pathname to be created. The pathname must be a directory.

(Example) allow_mkdir /tmp/logwatch.\*/ 0755

See also: path_group

allow_rmdir

This keyword grants the specified pathname to be deleted. The pathname must be a directory.

(Example) allow_rmdir /tmp/logwatch.\*/

See also: path_group

allow_mkfifo

This keyword grants creation of FIFO by the specified pathname.

(Example) allow_mkfifo /dev/initctl 0600

See also: path_group

allow_mksock

This keyword grants creation of UNIX domain socket by the specified pathname.

(Example) allow_mksock /dev/log 0700

See also: path_group

allow_mkblock

This keyword grants creation of block device file by the specified pathname.

(Example) allow_mkblock /dev/hdc 0640 22 0

See also: path_group

allow_mkchar

This keyword grants creation of character device file by the specified pathname.

(Example) allow_mkchar /dev/null 0644 1 3

See also: path_group

allow_truncate

This keyword grants the specified pathname to be truncated or extended.

(Example) allow_truncate /etc/mtab

See also: path_group

allow_symlink

This keyword grants creation of symbolic link by the specified pathname.

(Example) allow_symlink /dev/cdrom

See also: path_group

allow_link

This keyword grants creation of hard link by the specified pathnames.

(Example) allow_link /etc/mtab~\$ /etc/mtab~

See also: path_group

allow_rename

This keyword grants renaming of the specified pathnames.

(Example) allow_rename /etc/mtab.tmp /etc/mtab

See also: path_group

allow_rewrite

This keyword grants the specified pathname to be rewritten when the pathname is specified by deny_rewrite keyword.

(Example) allow_rewrite /var/log/messages

See also: path_group deny_rewrite

allow_chmod

This keyword grants changing DAC's permissions.

(Example) allow_chmod /dev/mem 0644

See also: path_group number_group

allow_chown

This keyword grants changing DAC's owner.

(Example) allow_chown /dev/sda 0

See also: path_group number_group

allow_chmod

This keyword grants changing DAC's group.

(Example) allow_chgrp /dev/audio 92

See also: path_group number_group

allow_ioctl

This keyword grants doing IOCTL request with the specified command numbers and the specified pathnames.

ExamplePermitted access
allow_ioctl socket:[family=2:type=2:protocol=17] 35093Allow sockets with protocol family 2, type 2, protocol 17 to do IOCTL request with command number 35093.
allow_ioctl /dev/null 10000-20000Allow /dev/null to do IOCTL request with command number between 10000 and 20000.

Regarding the meaning of IOCTL request's command numbers, please refer manuals provided by each module with IOCTL functionality. For example, IOCTL request with command number 21585 means, on i386 platform, FIOCLEX command which turns on the file's close-on-exec flag. For example, IOCTL request with command number 35088 means SIOCGIFNAME command which retrieves the name of network interface.

See also: Using conditional ACL.

allow_mount

To grant mount permission, use allow_mount keyword followed by "$devicefile $mountpoint $filesystem $options". The $devicefile need to be a canonicalized file if the $filesystem requires device file. The $mountpoint must be a canonicalized file. The $options is a hexadecimal integer expression.

To grant "mount -o remount $mountpoint" permission, use allow_mount keyword followed by "any $mountpoint --remount $options".

To grant "mount --bind $source_dir $dest_dir", use "allow_mount $source_dir $dest_dir --bind $options".
To grant "mount --move $source_dir $dest_dir" permission, use "allow_mount $source_dir $dest_dir --move $options".
The $source_dir and $dest_dir must be canonicalized directory.

Kernel 2.6.15 and later supports "Shared Subtree" functionality.
To grant "mount --make-unbindable $mountpoint" permission, use allow_mount keyword followed by "any $mountpoint --make-unbindable $options".
To grant "mount --make-private $mountpoint" permission, use allow_mount keyword followed by "any $mountpoint --make-private $options".
To grant "mount --make-slave $mountpoint" permission, use allow_mount keyword followed by "any $mountpoint --make-slave $options".
To grant "mount --make-shared $mountpoint" permission, use allow_mount keyword followed by "any $mountpoint --make-shared $options".

(Example)
allow_mount none /dev/pts/ devpts 0x0
allow_mount /proc /proc/ proc 0x0
allow_mount usbdevfs /proc/bus/usb/ usbdevfs 0x0
allow_mount none /data/ tmpfs 0xE
allow_mount none /dev/shm/ tmpfs 0xE
allow_mount /dev/hdc /var/www/ ext2 0xF
allow_mount any / --remount 0x0

allow_unmount

To grant unmount request, use allow_unmount keyword followed by a canonicalized directory.

(Example)
allow_unmount /mnt/cdrom/

allow_chroot

To grant chroot permission, use allow_chroot keyword followed by a canonicalized directory.
Usually, grant /var/empty/sshd/ that sshd uses. In addition, if you have applications that runs in the chroot'ed environment or applications that uses chroot (for example, /usr/share/empty/ is used by vsftpd), grant such directories too.

(Example)
allow_chroot /var/empty/sshd/
allow_chroot /usr/share/empty/
allow_chroot /var/www/html/
allow_chroot /

allow_pivot_root

To grant pivot_root permission, use allow_pivot_root keyword followed by the new root's canonicalized directory and the previous root's canonicalized directory.
Usually, you don't need this keyword.

allow_env

To restrict the name of environment variables, use allow_env keyword followed by "the name of environment variable".

The execve() system call, which is used to execute a program, accepts filename and argv[] and envp[]. Many programs behave differently depending on envp[].

The purpose of this keyword is to restrict the environment variables passed to an executed programs.

See also: allow_env

allow_capability

To grant capability permission, use allow_capability keyword followed by a capability. The following capabilities are applicable.

allow_capability inet_tcp_createPermit creation of TCP sockets.
allow_capability inet_tcp_listenPermit TCP socket's listen operation.
allow_capability inet_tcp_connectPermit TCP socket's connect operation.
allow_capability use_inet_udpPermit use of UDP sockets.
allow_capability use_inet_ipPermit use of RAW sockets.
allow_capability use_routePermit use of ROUTE sockets.
allow_capability use_packetPermit use of PACKET sockets.
allow_capability use_kernel_modulePermit use of create_module(2) init_module(2) delete_module(2) syscall.
allow_capability create_fifoPermit creation of FIFO using mknod(2) syscall.
allow_capability create_block_devPermit creation of block device using mknod(2) syscall.
allow_capability create_char_devPermit creation of character device using mknod(2) syscall.
allow_capability create_unix_socketPermit creation of UNIX domain sockets using mknod(2) syscall.
allow_capability SYS_MOUNTPermit use of mount(2) syscall.
allow_capability SYS_UMOUNTPermit use of umount(2) syscall.
allow_capability SYS_REBOOTPermit use of reboot(2) syscall.
allow_capability SYS_CHROOTPermit use of chroot(2) syscall.
allow_capability SYS_KILLPermit use of kill(2) tkill(2) tgkill(2) syscall with non 0 signal.
allow_capability SYS_VHANGUPPermit use of vhangup(2) syscall.
allow_capability SYS_TIMEPermit use of stime(2) settimeofday(2) adjtimex(2) syscall.
allow_capability SYS_NICEPermit use of nice(2) setpriority(2) syscall.
allow_capability SYS_SETHOSTNAMEPermit use of sethostname(2) setdomainname(2) syscall.
allow_capability SYS_LINKPermit use of link(2) syscall.
allow_capability SYS_SYMLINKPermit use of symlink(2) syscall.
allow_capability SYS_RENAMEPermit use of rename(2) syscall.
allow_capability SYS_UNLINKPermit use of unlink(2) syscall.
allow_capability SYS_CHMODPermit use of chmod(2) fchmod(2) syscall.
allow_capability SYS_CHOWNPermit use of chown(2) fchown(2) lchown(2) syscall.
allow_capability SYS_IOCTLPermit use of ioctl(2) compat_sys_ioctl(2) syscall.
allow_capability SYS_KEXEC_LOADPermit use of kexec_load(2) syscall.
allow_capability SYS_PIVOT_ROOTPermit use of pivot_root(2) syscall.
allow_capability SYS_PTRACEPermit use of ptrace(2) syscall.
allow_capability conceal_mountPermit use of mount(2) syscall that will hide existing mounts.

The purpose of allow_capability keyword is to restrict system calls that a program can call. You can restrict more strictly with other keyword and policy files for some system calls.

allow_network

To grant permission for socket operations, use allow_network keyword followed by protocol(TCP or UDP or RAW) and IP address and port number (for TCP or UDP) / protocol number (for RAW). This permission is applicable to IPv4 and IPv6.

KeywordPermitted operationExample
allow_network TCP bind Bind to local TCP address/port.allow_network TCP bind 0.0.0.0 80
allow_network TCP listenListen to local TCP address/port.allow_network TCP listen 0.0.0.0 80
allow_network TCP acceptAccept from and communicate with remote TCP address/port.allow_network TCP accept 10.0.0.0-10.255.255.255 1024-65535
allow_network TCP connectConnect to and communicate with remote TCP address/port.allow_network TCP connect 127.0.0.1 1024-65535
allow_network UDP bindBind to local UDP address/port.allow_network UDP bind 0.0.0.0 53
allow_network UDP connectCommunicate with remote UDP address/port.allow_network UDP connect 127.0.0.1 53
allow_network RAW bindBind to local IP address/protocol.allow_network RAW bind 127.0.0.1 255
allow_network RAW connectCommunicate with remote IP address/protocol.allow_network RAW connect 10.0.0.1 1

Use of "::" for IPv6 address representation is not supported. You need to use "0:0:0:0:0:0:0:1" for "::1".

To reduce the labor of repeating same IP addresses, you can define groups like pathnames.

See also: address_group

allow_signal

To grant permissions for signals, use allow_signal keyword followed by signal number and target domain.
There are two exceptions. If signal number is 0, it is always granted. If the target domain and the source domain are the same, it is always granted.

In other cases, signals are granted only when the signal number matches and the target domain starts with the target domain declared with this keyword.

If only <kernel> is declared as a target domain, the source domain can send signals to any domain with that signal number.

use_profile

This keyword indicates the profile number currently assigned to this domain. The profile number is an integer between 0 and 255.

ignore_global_allow_read

This keyword ignores pathnames specified by allow_read keyword in exception policy. You can use this keyword for domains you want to ignore globally readable files.

See also: allow_read

ignore_global_allow_env

This keyword ignores environment variables names specified by allow_env keyword in exception policy. You can use this keyword for domains you want to ignore globally acceptable environment variable names.

See also: allow_env

execute_handler

This domain executes only one program specified by this keyword. You can use this keyword for domains you want to validate parameters before executing the requested program.

If this keyword is specified, only one program specified by this keyword regardless of the mode specified by CONFIG::file::execute. Thus, if the pathname specified by this program cannot be executed, no programs can be executed from this domain.

See also: denied_execute_handler CONFIG::file::execute allow_execute

denied_execute_handler

This domain executes this program only when execute request was rejected and the mode of CONFIG::file::execute is enforcing. If this keyword is not specified and the mode of CONFIG::file::execute is enforcing, execute request is rejected.

Exception is, if the execute_handler keyword is specified, denied_execute_handler keyword is ignored.

quota_exceeded

This keyword indicates that this domain has failed to append entry in learning mode since the number of entries reached to the limit specified by PREFERENCE::learning keyword. You need to reduce the number of entries for this domain by tuning policy.

See also: PREFERENCE::learning

transition_failed

This keyword indicates that some process in this domain was not able to transit to new domain when processing the execute request.

If this domain was assigned a profile with CONFIG::file::execute=enforcing , the execute request was rejected.

Otherwise, the execute request was not rejected. In that case, the process continued execution without domain transition. Since the reason of transition failure is either "the name of the domain was too long" or "the kernel was unable to allocate memory", you need to consider "suppressing domain transitions" or "increasing memory quota" if you are planning to assign a profile with CONFIG::file::execute=enforcing to this domain.

See also: keep_domain Memory Usage Information

/proc/ccs/exception_policy

To read or modify current exception policy, operate like below.

(Example)
echo 'file_pattern /proc/\$/status' | ccs-loadpolicy -e
echo 'delete file_pattern /proc/\$/status' | ccs-loadpolicy -e
cat /proc/ccs/exception_policy

See also: Policy File's Modification

file_pattern

To declare pathname pattern, use file_pattern keyword followed by pathname pattern. The pathname pattern must be a canonicalized Pathname. This keyword is not applicable to neither granting execute permissions nor domain definitions.
For example, canonicalized pathname that contains a process ID (i.e. /proc/PID/ files) needs to be grouped in order to make access control work well.

path_group

To declare pathname group, use path_group keyword followed by name of the group and pathname pattern.
For example, if you want to group all files under home directory, you can define

path_group HOME-DIR-FILE /home/\*/\*
path_group HOME-DIR-FILE /home/\*/\{\*\}/\*

in the exception policy and use like

allow_read @HOME-DIR-FILE

to grant file access permission.

number_group

To declare number group, use number_group keyword followed by name of the group and number ranges.
For example, if you want to group 0644 and 0664, you can define

number_group CREATE_MODES 0644
number_group CREATE_MODES 0664

in the exception policy and use like

allow_create /tmp/file @CREATE_MODES

to grant access permission.

address_group

To declare address group, use address_group keyword followed by name of the group and IP address pattern.
For example, if you want to group all local addresses, you can define

address_group local-address 10.0.0.0-10.255.255.255
address_group local-address 172.16.0.0-172.31.255.255
address_group local-address 192.168.0.0-192.168.255.255

in the exception policy and use like

allow_network TCP accept @local-address 1024-65535

to grant network access permission.

allow_read

To grant unconditionally readable permissions, use allow_read keyword followed by canonicalized file. This keyword is intended to reduce size of domain policy by granting read access to library files such as GLIBC and locale files. Exception is, if ignore_global_allow_read keyword is given to a domain, entries specified by this keyword are ignored.

See also: allow_read ignore_global_allow_read

allow_env

To grant unconditionally acceptable environment variables' names, use allow_env keyword followed by the name of environment variables. This keyword is intended to reduce memory usage for commonly granted environment variables (e.g. PATH and HOME). You should not grant dangerous environment variables like LD_PRELOAD . Exception is, if ignore_global_allow_env keyword is given to a domain, entries specified by this keyword are ignored.

See also: ignore_global_allow_env allow_env

deny_rewrite

To deny overwriting already written contents of file (such as log files) by default, use deny_rewrite keyword followed by pathname pattern. Files whose pathname match the patterns are not permitted to open for writing without append mode or truncate unless the pathnames are explicitly granted using allow_rewrite keyword in domain policy.

See also: allow_rewrite

aggregator

To deal multiple programs as a single program, use aggregator keyword followed by name of original program and aggregated program. This keyword is intended to aggregate similar programs.

For example, /usr/bin/tac and /bin/cat are similar. By specifying "aggregator /usr/bin/tac /bin/cat", you can run /usr/bin/tac in the domain for /bin/cat .

For example, /usr/sbin/logrotate for Fedora Core 3 generates programs like /tmp/logrotate.\?\?\?\?\?\? and run them, but TOMOYO Linux doesn't allow using patterns for granting execute permission and defining domains. By specifying "aggregator /tmp/logrotate.\?\?\?\?\?\? /tmp/logrotate.tmp", you can run /tmp/logrotate.\?\?\?\?\?\? as if /tmp/logrotate.tmp is running.

See also: allow_execute

initialize_domain

To initialize domain transition when specific program is executed, use initialize_domain directive.

If the part "from" and after is not given, the entry is applied to all domain. If the "domain" doesn't start with "<kernel>", the entry is applied to all domain whose domainname ends with "the last program part of domain".

This directive is intended to aggregate domain transitions for daemon program and program that are invoked by the kernel on demand, by transiting to different domain.

See also: Domain Transition no_initialize_domain

no_initialize_domain

To deny the effect of "initialize_domain" directive, use "no_initialize_domain" directive.

Use this directive when you don't want to initialize domain transition.

See also: Domain Transition initialize_domain

keep_domain

To prevent domain transition when program is executed from specific domain, use keep_domain directive.

If the part "from" and before is not given, this entry is applied to all program. If the "domain" doesn't start with "<kernel>", the entry is applied to all domain whose domainname ends with "the last program part of domain".

This directive is intended to reduce total number of domains and memory usage by suppressing unneeded domain transitions.

See also: Domain Transition no_keep_domain

no_keep_domain

To deny the effect of "keep_domain" directive, use "no_keep_domain" directive.

Use this directive when you want to escape from a domain that is kept by "keep_domain" directive.

See also: Domain Transition keep_domain

deny_autobind

To prevent specific local port from being selected automatically, use deny_autobind keyword followed by local port number.
This keyword is intended to prevent specific local port from being bound for temporary use. For example, some proxy server uses local port 8080, so port 8080 should not be bound by other programs for temporary use.

(Example)
deny_autobind 1-1023
deny_autobind 8080

/proc/ccs/query

This file is used to manually grant or reject individual access requests when the policy violation occurs in enforcing mode. If a policy violation occur in a process whose domain is assigned a profile for enforcing mode, the administrator can judge interactively using "ccs-queryd" command.

/proc/ccs/manager

This file is used to read or append the list of programs or domains that can write to /proc/ccs/ interface.

manage_by_non_root

By default, only processes with both UID = 0 and EUID = 0 can modify policy via /proc/ccs/ interface. You can use this keyword to allow policy modification by non root user.

/proc/ccs/.domain_status

This is a view (of a DBMS) that contains only profile number and domainnames of domain so that "ccs-setprofile" command can do line-oriented processing easily.

/proc/ccs/meminfo

This file is to show the total RAM used to keep policy in the kernel by TOMOYO Linux.

(Example)
cat /proc/ccs/meminfo

/proc/ccs/grant_log

This file holds the granted log. The reader process returns immediately if no granted logs exists. To wait until a granted log is generated, use select(2) for readability. The max number of logs that the kernel can hold is limited to max_grant_log parameter of PREFERENCE::audit, so read out timely.

(Example)
cat /proc/ccs/grant_log

/proc/ccs/reject_log

This file holds the rejected log. The reader process returns immediately if no violation logs exists. To wait until a violation log is generated, use select(2) for readability. The max number of logs that the kernel can hold is limited to max_reject_log parameter of PREFERENCE::audit, so read out timely.

(Example)
cat /proc/ccs/reject_log

/proc/ccs/self_domain

This file is to show the name of domain the caller process belongs to.

(Example)
cat /proc/ccs/self_domain

/proc/ccs/.process_status

This file is used by "ccs-pstree" command to show "list of processes currently running" and "domains which each process belongs to" and "profile number which the domain is currently assigned" like "pstree" command. This file is writable by programs that aren't registered as policy manager.

/proc/ccs/version

This file is used for getting TOMOYO Linux's version.

(Example)
cat /proc/ccs/version

6. Advanced Features

6.1 Allowing policy modification by non root user.

By default, only processes with both UID = 0 and EUID = 0 can modify policy via /proc/ccs/ interface. But if you want to permit policy modification via /proc/ccs/ interface by non root user, you can write this keyword like

# echo manage_by_non_root | /usr/sbin/ccs-loadpolicy -m

to disable UID and EUID checks. Also, you can write this keyword like

# echo delete manage_by_non_root | /usr/sbin/ccs-loadpolicy -m

to enable UID and EUID checks again. Use chown/chmod as needed since the owner of /proc/ccs/ interface is root.
To be able to do this steps, /sbin/ccs-init also executes /etc/ccs/ccs-post-init if /etc/ccs/ccs-post-init is executable. Therefore, to allow access to /proc/ccs/ interface by user demo, create /etc/ccs/ccs-post-init with

#! /bin/sh
echo manage_by_non_root > /proc/ccs/manager
chown -R demo /proc/ccs/

and initialize like

# chmod 755 /etc/ccs/ccs-post-init
# chown -R demo /etc/ccs/

Then, user demo will be able to access policy directories and policy editors.

6.2 Using conditional ACL.

You can add conditions (e.g. UID and GID) as needed. The condition clause are appended to the tail of each permission using "if" directive.

ExampleMeaning
allow_read /etc/passwdAllow opening /etc/passwd for reading.
allow_read /etc/passwd if task.uid=0Allow opening /etc/passwd for reading only if the process's UID is 0.
allow_read /etc/passwd if task.uid!=0Allow opening /etc/passwd for reading only if the process's UID is not 0.
allow_network TCP connect 10.0.0.1 80Allow connecting TCP socket to 10.0.0.1 port 80.
allow_network TCP connect 10.0.0.1 80 if task.uid=100Allow connecting TCP socket to 10.0.0.1 port 80 only if the process's UID is 100.
allow_capability SYS_KILLAllow using kill(2) syscall.
allow_capability SYS_KILL if task.ppid=1 task.uid=0 task.euid=0Allow using kill(2) syscall only if the parent process is /sbin/init and the process's UID is 0 and the process's EUID is 0.

The following variables are available.

VariableMeaning
task.uidUID of current process
task.euidEffective UID of current process
task.suidSaved UID of current process
task.fsuidFile System UID of current process
task.gidGID of current process
task.egidEffective GID of current process
task.sgidSaved GID of current process
task.fsgidFile System GID of current process
task.pidPID of current process
task.ppidPID of parent process
path1.uidUID of object.
path1.gidGID of object.
path1.inoi-node number of object.
path1.parent.uidUID of object's parent directory.
path1.parent.gidGID of object's parent directory.
path1.parent.inoi-node number of object's parent directory.
path2.parent.uidUID of object's parent directory.
path2.parent.gidGID of object's parent directory.
path2.parent.inoi-node number of object's parent directory.

"path1" corresponds to the first pathname of operations that requires pathnames, and "path2" corresponds to the second pathname of operations that requires pathnames. For example, the case of "allow_rename file1 file2", path1 corresponds to file1 and path2 corresponds to file2.

"path1" except "path1.parent" is not available for pathnames that don't exist. Thus, you can't use when creating pathnames (such as allow_create keyword).

"path1.parent" is always available.

"path2.parent" is available only for operations that require 2 pathnames (i.e. allow_link and allow_rename keywords).

"path2" is available only for mount operations.

"path1" is not supported when accessing via "sysctl" (i.e. accessing files under /proc/sys/ directories using "sysctl" instead for "open").

The following variables and conditions are available for allow_execute keyword.

VariableMeaning
exec.realpathDereferenced pathname of the requested program.
exec.argcNumber of argv[] passed for execute request.
exec.envcNumber of envp[] passed for execute request.
ConditionMeaning
exec.realpath="value"Dereferenced pathname of the requested program matches "value".
exec.realpath!="value"Dereferenced pathname of the requested program does not match "value".
exec.argv[index]="value"argv[index] (where 0 <= index < exec.argc) matches "value".
exec.argv[index]!="value"argv[index] (where 0 <= index < exec.argc) does not match "value".
exec.envp["name"]="value"Environment variable "name" is defined and matches "value".
exec.envp["name"]!="value"Environment variable "name" is not defined or does not match "value".
exec.envp["name"]!=NULLEnvironment variable "name" is defined.
exec.envp["name"]=NULLEnvironment variable "name" is not defined.

The following conditions are also available.

Type of process

ConditionMeaning
task.type=execute_handlerCurrent process is a program specified by execute_handler keyword.
task.type!=execute_handlerCurrent process is not a program specified by execute_handler keyword.

Type of file.

ConditionMeaning
path1.type=filepath1 is a regular file.
path1.type=directorypath1 is a directory.
path1.type=fifopath1 is a FIFO.
path1.type=socketpath1 is a socket.
path1.type=symlinkpath1 is a symbolic link.
path1.type=blockpath1 is a block device file.
path1.type=charpath1 is a character device file.
path1.type!=filepath1 is not a regular file.
path1.type!=directorypath1 is not a directory.
path1.type!=fifopath1 is not a FIFO.
path1.type!=socketpath1 is not a socket.
path1.type!=symlinkpath1 is not a symbolic link.
path1.type!=blockpath1 is not a block device file.
path1.type!=charpath1 is not a character device file.

Since path1.parent and path2.parent are always directory, TOMOYO Linux does not support path1.parent and path2.parent for type of file.

Device numbers of a device file where the file resides.

ConditionMeaning
path1.major=num1-num2Device major number of a device file which path1 resides is between num1 and num2.
path1.minor=num1-num2Device minor number of a device file which path1 resides is between num1 and num2.
path1.major!=num1-num2Device major number of a device file which path1 resides is not between num1 and num2.
path1.minor!=num1-num2Device minor number of a device file which path1 resides is not between num1 and num2.

Since a device file where path1.parent and path2.parent reside is always same as the device file where path1 resides (because cross device operation is not permitted), TOMOYO Linux does not support path1.parent and path2.parent for device numbers.

If num1 and num2 is the same value, you can omit -num2 part.

Device numbers of the device file itself.

ConditionMeaning
path1.dev_major=num1-num2Device file's major number is between num1 and num2.
path1.dev_minor=num1-num2Device file's minor number is between num1 and num2.
path1.dev_major!=num1-num2Device file's major number is not between num1 and num2.
path1.dev_minor!=num1-num2Device file's minor number is not between num1 and num2.

These conditions are valid only for path1.type=block or path1.type=char cases.

If num1 and num2 is the same value, you can omit -num2 part.

DAC's permissions

ConditionMeaning
path1.perm=num1-num2path1's permission is between num1 and num2.
path1.perm!=num1-num2path1's permission is not between num1 and num2.
path1.perm=setuidpath1's setuid bit is on.
path1.perm!=setuidpath1's setuid bit is off.
path1.perm=setgidpath1's setgid bit is on.
path1.perm!=setgidpath1's setgid bit is off.
path1.perm=stickypath1's sticky bit is on.
path1.perm!=stickypath1's sticky bit is off.
path1.perm=owner_readpath1's owner read bit is on.
path1.perm!=owner_readpath1's owner read bit is off.
path1.perm=owner_writepath1's owner write bit is on.
path1.perm!=owner_writepath1's owner write bit is off.
path1.perm=owner_executepath1's owner execute bit is on.
path1.perm!=owner_executepath1's owner execute bit is off.
path1.perm=group_readpath1's group read bit is on.
path1.perm!=group_readpath1's group read bit is off.
path1.perm=group_writepath1's group write bit is on.
path1.perm!=group_writepath1's group write bit is off.
path1.perm=group_executepath1's group execute bit is on.
path1.perm!=group_executepath1's group execute bit is off.
path1.perm=others_readpath1's others read bit is on.
path1.perm!=others_readpath1's others read bit is off.
path1.perm=others_writepath1's others write bit is on.
path1.perm!=others_writepath1's others write bit is off.
path1.perm=others_executepath1's others execute bit is on.
path1.perm!=others_executepath1's others execute bit is off.

These conditions are applicable for path1.parent and path2.parent as well as path1 .

If num1 and num2 is the same value, you can omit -num2 part.

To specify value in octal format, start from 0 (e.g. path1.perm=0644 ).

Example:

will allow opening /dev/null for reading and writing only if /dev/null's type is character device file and /dev/null's major number is 1 and /dev/null's minor number is 3 and /dev/null's permission is 0666.

The following conditions for allow_symlink keyword are also available.

ConditionMeaning
symlink.target="value"The content of a symlink to be created matches "value".
symlink.target!="value"The content of a symlink to be created does not match "value".

6.3 Using stateful ACL.

Since TOMOYO Linux doesn't require modification of userland applications, it is impossible to change the range of accessible resources without domain transition. But there are cases you wish to change the range of accessible resources without domain transition. For example, you might wish to change the range of accessible resources depending on the client's IP address. To support such cases, you can assign state variables to each processes and you can use the state variables in Using conditional ACL.

VariableMeaning
task.state[0]Current process's state variable 0
task.state[1]Current process's state variable 1
task.state[2]Current process's state variable 2

Each task.state can take an integer value between 0 and 255. To change state variable, append " ; set " part after an ACL.

ExampleMeaning
allow_network TCP accept @TRUSTED_HOSTS 1024-65535 ; set task.state[0]=1If a TCP connection is accepted from an IP address included in an address group @TRUSTED_HOSTS, set 1 to state[0].
allow_network TCP accept @UNTRUSTED_HOSTS 1024-65535 ; set task.state[0]=0If a TCP connection is accepted from an IP address included in an address group @UNTRUSTED_HOSTS, set 0 to state[0].
allow_execute /bin/bash if task.state[0]=1Allow execution of /bin/bash if state[0] is 1.
allow_execute /sbin/nologin if task.state[0]=0Allow execution of /sbin/nologin if state[0] is 0.
allow_execute /etc/passwd if task.state[2]=0 ; set task.state[2]=1If state[2] is 0, allow opening /etc/passwd for reading and then, set 1 to state[2].

When using the state variables, please be careful with the following points.

6.4 Sleep penalty for policy violation.

You can make the process which violated policy in enforcing mode sleep for specified period.

Example of /proc/ccs/profileMeaning
3-PREFERENCE::enforcing={ penalty=1 }Make the process which violated policy in enforcing mode and which belongs to a domain with profile 3 sleep for 0.1 second.
4-PREFERENCE::enforcing={ penalty = 10 }Make the process which violated policy in enforcing mode and which belongs to a domain with profile 4 sleep for 1 second.

This feature is a safeguard to avoid that the CPU usage remains 100% when policy violation occurs in an infinite loop. Usually, making processes sleep for 0.1 second is enough.

This feature is not applied against network's receive operation so that attackers cannot make services sleep for long time (in other words, delay your system's response) by intentionally sending TCP connection requests and UDP packets from unwanted sources.

6.5 Judging execute request outside the kernel.

Basically, TOMOYO Linux controls whether to execute a program or not according to the domain policy. You can check parameters using exec.argv and exec.envp described in Using conditional ACL. But this approach support only simple pattern matching and you need to specify what programs are permitted to be executed beforehand.

Therefore, TOMOYO Linux supports a mechanism named execute_handler. If this mechanism is used, the kernel no longer controls whether to execute a requested program or not, and the kernel merely executes the program specified by execute_handler, and the program specified by execute_handler determines whether to execute the requested program or not, and the program specified by execute_handler executes the requested program only if the program specified by execute_handler considers it is appropriate.

In Linux, the behavior "execute a program" means "overwrite the process which requested to execute a program with the requested program's image" and "the process which requested to execute a program cannot regain control if the execute request was succeeded". Therefore, the process which requested to execute a program can receive a notification only when the execute request was failed.
For example, let's consider a situation where a process running as program-A attempts to execute program-B.
When the process running as program-A requests the execution of program-B, the kernel checks the domain policy for "whether it is appropriate to execute program-B from a process running as program-A or not" and the kernel overwrites the process running as program-A with program-B if the kernel considers it is appropriate, and the kernel doesn't overwrite the process running as program-A with program-B and notifies the process running as program-A that execution of program-B is not permitted if the kernel considers it is not appropriate.

When execute_handler is specified, a different program program-C specified as execute_handler mediates this behavior.
When the process running as program-A requests the execution of program-B, the kernel overwrites the process running as program-A with program-C to let the program-C judge whether it is appropriate to execute program-B from a process running as program-A or not. The process now running as program-C determines whether it is appropriate to execute program-B from a process running as program-A or not, and the process now running as program-C requests the execution of program-B (and the kernel will overwrite the process now running as program-C with program-B) if the process now running as program-C considers it is appropriate, and the process now running as program-C terminates without executing program-B if the process now running as program-C considers it is not appropriate.

As stated above, this mechanism has a side effect that it becomes impossible to notify the process running as program-A that the requested program (i.e. program-B) was not executed since program-C abandons a mean to notify the process running as program-A that the execute request of program-B was not accepted.
But, even if execute_handler is not specified, there are various factors that cause "the execute request was accepted but the program terminated before starting the expected behavior" such as "the process was unable to read shared libraries", "the process received KILL signal", "the system became out of memory and the process was killed by OOM killer". In other words, there are uncertainties between "the execute request did not fail" and "the executed program starts the expected behavior".
Viewing in this light, there is no guarantee that "the program starts expected behavior unless the process receives a notification that the execution of the program failed" from the beginning. And, it is possible to say that it is an acceptable result that the program-C specified by execute_handler failed to notify the process previously running as program-A that the execution of program-B failed.

TOMOYO Linux's assumes that the administrator knows what programs needs to be executed from what programs beforehand and permits execution of minimal programs. Thus, assuming that unexpected execute request which are not permitted by policy won't occur as long as the system is running properly, it is OK to accept all execute requests. If an execute request that should not be accepted occurs, you can take different actions such as terminating the process instead of rejecting the request by using denied_execute_handler mechanism. So, you don't have to let the kernel judge whether to execute the program or not alone.

Thus, you can let external userland program judge whether to execute the requested program or not occurred from a domain by specifying execute_handler keyword to the domain.

If you try to judge inside the kernel, there are few library functions available and it is more likely to fail when allocating contiguous memory area. But if you try to judge outside the kernel, there are many library functions available and it is less likely to fail when allocating contiguous memory area, and you can do more detailed checking. So, you can let external userland program specified by execute_handler keyword examine parameters and let the program execute the requested program only if parameters are appropriate.

The side effect of this approach is that there is no mean to notify the process that the execute request was not accepted when it is not appropriate to execute the requested program. But since you can freely customize the program for execute_handler keyword, you can even judge using ssh to ask remotely.

To use this feature, specify like below.

Example of /proc/ccs/domain_policyMeaning
execute_handler /usr/sbin/check-and-execWhenever a process which belongs to this domain requests execution of a program, execute /usr/sbin/check-and-exec instead for the requested program. /usr/sbin/check-and-exec checks parameters and executes the requested program if /usr/sbin/check-and-exec considers it is appropriate to execute.

The program specified by execute_handler keyword receives the following parameters. Compare with allow_execute log described in Access Logs.

Be careful with the following notes when you use this feature.

A source code named audit-exec-param.c is included as a sample program of how to use this mechanism in the ccs-tools source package. You can customize freely.

This mechanism is just providing a hook. How to utilize this hook is up to you.

6.6 Invoking alternative program for execute requests that are not permitted by policy.

TOMOYO Linux's approach is "know what programs needs to be executed from what programs beforehand and create policy that permits execution of minimal programs". Thus, you can not only reject unnecessary execution requests but also do different behavior.

By default, if an execute request of a program which is not permitted by allow_execute keyword occurs in enforcing mode, the kernel rejects the execute request. But assuming that you know what programs needs to be executed from what programs beforehand, an execute request of a program which is not permitted by allow_execute keyword will not occur as long as the process is keeping control, and you can regard that the process is not keeping control (in other words, the process already lost control) if such request occurs.

Attackers steal control of a process by attacking security holes such as buffer overflow and attempt to execute commands such as shells. If the process does not need to execute the shell (in other words, you needn't to give permission like "allow_execute /bin/bash"), it is considered that the process has already lost control at the moment of the execution request of shells.

Normally, when execution of a program which is not permitted by the policy is requested, the kernel merely reject the request. But it is unlikely that the process gets back control (in other words, the process resumes proper operations) by just rejecting the request if the request is issued by the process that has lost control.
In Linux, "execute a program" means that the current process is overwritten by the requested program and transfer control to the requested program. This means that a process gets back control by overwriting the process with different program even if the process has lost control because of buffer overflow.

The control of a process which has once lost control by the attacker and is overwritten by a program requested by the attacker depends on the program used for overwriting. If a program like shells is executed, the control remains on the attacker's side (in other words, the owner of the process) because shells accept whatever the user requested. But if a program which terminates silently (e.g. /bin/true) is executed, the control will not remains on the attacker's side because the process owned by the attacker will terminate immediately.

As described above, an event that "an execute request of an unnecessary program is issued by an attacker" depending on how you look at it. You can consider that "the attacker is giving the system a chance to get back control on the system's side".
Thus, TOMOYO Linux provides a mechanism that executes different program instead of merely rejecting the request when an execute request of a program which is not permitted by policy occurs. How to utilize this mechanism is up to you.

For example, you can replace the execute request of a program which is not permitted by the policy with /bin/true so that the process which requested the execution of a program which is not permitted by the policy will terminate immediately.

For example, you can replace the execute request of shells with a honey pot client's program and observe what requests the attacker issues.

For example, you can forcibly terminate the login session.

For example, you can show warning message like "You are not permitted to execute this program." which is similar to Ubuntu's command-not-found package (which tells the user in what package the requested command is included).

For example, you can change a firewall's configuration if you succeeded to derive the IP address of the attacker.

To use this feature, specify like below.

Example of /proc/ccs/profileExample of /proc/ccs/domain_policyMeaning
3-CONFIG::file::execute=enforcinguse_profile 3
denied_execute_handler /bin/true
If a process which belongs to a domain with profile 3 requested execution of a program which is not permitted by the domain policy, execute /bin/true instead of rejecting the execute request.

Notes on this feature is the same as Judging execute request outside the kernel.


Return to index page.

sflogo.php