Info: Version 1.8.x is available.
Last modified: $Date: 2024-03-30 11:25:00 +0000 (Sat, 30 Mar 2024) $
In this installment, I explain "conditional ACL" which utilizes TOMOYO Linux's powerful parameter checking functionality.
TOMOYO Linux does not support RBAC ( Role Based Access Control ). But you can specify conditions based on user ID in the policy configuration. Therefore, you can use access control based on system account's user ID. Conditions are appended at the tail of individual permissions in the form of "if condition". Available conditions are listed in Fig. 1 and usage examples are listed in Fig. 2.
♦ Fig. 1 Parameters which can be used as conditions
|
♦ Fig. 2 Example of conditions
|
I explain steps for allowing browsing user's own files only for users logged in from console using /bin/cat command as an example. I use "user1" user and "user2" user for this purpose. Login from console and do below operations. Firstly, create 2 accounts. (Fig. 3)
♦ Fig. 3 Create 2 accounts
# useradd -s /bin/bash user1 # useradd -s /bin/bash user2 |
Set some passwords for these accounts. (Fig. 4)
♦ Fig. 4 Set passwords for created accounts
# passwd user1 # passwd user2 |
Run /bin/cat command in order to create domain for cat command. In addition, let's print the domain of cat command. (Fig. 5)
♦ Fig. 5 Print domain which cat command belongs to
# cat /proc/ccs/self_domain <kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat |
Assign a profile for learning mode to /bin/cat command's domain. In this series, the profile for learning mode is profile 1, thus do like Fig. 6.
♦ Fig. 6 Assign a profile for learning mode to the domain which cat command belongs to
# /usr/sbin/ccs-setprofile 1 '<kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat' |
Logout and re-login as "user1" user. Then, do operations listed in Fig. 7.
♦ Fig. 7 Login as "user1" user and create /tmp/testfile1
$ echo "This file was created by user1" > /tmp/testfile1 $ cat /tmp/testfile1 This file was created by user1 |
Logout and re-login as "user2" user. Then, do operations listed in Fig. 8.
♦ Fig. 8 Login as "user2" and create /tmp/testfile2
$ echo "This file was created by user2" > /tmp/testfile2 $ cat /tmp/testfile2 This file was created by user2 |
Logout and re-login as "root" user. Run ccs-editpolicy command and check "<kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat" domain's permissions. There should be entries listed in Fig. 9.
♦ Fig. 9 Permissions given to "<kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat" domain
allow_read /tmp/testfile1 allow_read /tmp/testfile2 |
As of now, everyone can read these files if granted by DAC (Discretionary Access Control) permission. Press "A" key on the keyboard and enter lines listed in Fig. 10.
♦ Fig. 10 Adding permissions with conditions (♦ You may specify "allow_read /tmp/testfile\+ if task.uid=path1.uid" instead for these lines.) allow_read /tmp/testfile1 if task.uid=path1.uid allow_read /tmp/testfile2 if task.uid=path1.uid |
Then, delete entries listed in Fig. 11 using "D" key on the keyboard.
♦ Fig. 11 Deleting permissions without conditions
allow_read /tmp/testfile1 allow_read /tmp/testfile2 |
Press "Q" key on the keyboard to quit ccs-editpolicy command. Then, assign a profile for enforcing mode to /bin/cat command's domain. In this series, the profile for enforcing mode is profile 3, thus do like Fig. 12.
♦ Fig. 12 Assign a profile for enforcing mode to the domain which cat command belongs to
# /usr/sbin/ccs-setprofile 3 '<kernel> /sbin/mingetty /bin/login /bin/bash /bin/cat' |
Logout and re-login as "user1" user. Then, try to print /tmp/testfile1 and /tmp/testfile2 using /bin/cat command. You can see that access to /tmp/testfile2 is forbidden. (Fig. 13)
♦ Fig. 13 Access to /tmp/testfile2 is forbidden
$ cat /tmp/testfile1 This file was created by user1 $ cat /tmp/testfile2 cat: /tmp/testfile2: Operation not permitted |
Logout and re-login as "user2" user. Do the same operations like "user1" user. You can see that access to /tmp/testfile1 is forbidden. You may specify constant user ID instead of variables. For example, you can forbid "root" user's login if you change like Fig. 14 in the "<kernel> /sbin/mingetty /bin/login" domain (which authenticates user and executes login shell).
♦ Fig. 14 Deny login as "root" user
[Before modification] allow_execute /bin/bash [After modification] allow_execute /bin/bash if task.uid!=0 |
You can allow login of users with user ID between 500 and 1000 if you change like Fig. 15. You can use it for restricting logins via SSH.
♦ Fig. 15 Allow login of users with user ID between 500 and 1000
[Before modification] allow_execute /bin/bash [After modification] allow_execute /bin/bash if task.uid=500-1000 |
Now, I've finished explanation of conditional permissions. Delete accounts created for this explanation. (Fig. 16)
♦ Fig. 16 Delete accounts created at Fig. 3
# userdel user1 # userdel user2 |
Getting sidetracked a bit. I'd like to show you change of behavior by how the program is executed which can become a pitfall when doing access control. Login to a system (needn't to use TOMOYO Linux kernel) and save the program listed in Fig. 17 as /tmp/argv0.c .
♦ Fig. 17 A C program which prints the invocation name
#include <stdio.h> int main(int argc, char *argv[]) { printf("I am running as %s\n", argv[0]); return 0; } |
Then, compile and create symbolic links (or hard links) like Fig. 18.
♦ Fig. 18 Compile and create symbolic links
# gcc -o /tmp/argv0 /tmp/argv0.c # ln -s /tmp/argv0 /tmp/cat # ln -s /tmp/argv0 /tmp/passwd |
Then, execute these symbolic links (or hard links), and you will see the name of symbolic links (or hard links) are printed. (Fig. 19).
♦ Fig. 19 Execute via symbolic links
# /tmp/cat I am running as /tmp/cat # /tmp/passwd I am running as /tmp/passwd |
Some programs are designed to behave differently depending on the invocation name (called argv[0]). For example, in CentOS 5, /sbin/pidof is a symbolic link to /sbin/killall5 . If /sbin/killall5 is executed as "pidof", the program prints process ID of specified program. If /sbin/killall5 is executed as "killall5", the program sends signals to all processes except processes running in the same session.
In TOMOYO Linux, the process runs in "/tmp/cat" domain if the program is executed as "/tmp/cat" and the process runs in "/tmp/passwd" domain if the program is executed as "/tmp/passwd". Then, what will happen if /tmp/passwd is executed as /tmp/cat like Fig. 20? (Guess the result.)
♦ Fig. 20 Executing "passwd" command as "cat"
# sh -c 'exec -a /tmp/cat /tmp/passwd' |
The result of Fig. 20 is Fig. 21. This means that allowing Fig. 20 is equal to allowing Fig. 22. However, note that Fig. 22 allows running as /tmp/cat in the /tmp/cat domain whereas Fig. 20 allows running as /tmp/cat in the /tmp/passwd domain.
♦ Fig. 21 Behave as "cat" command
I am running as /tmp/cat |
♦ Fig. 22 Consequence of Fig. 20
# sh -c 'exec /tmp/cat' |
Suppose /usr/bin/passwd command and /bin/cat command are provided using symbolic links (or hard links) to /sbin/busybox command. In this case, TOMOYO Linux transits to /bin/cat domain if /bin/cat is executed and transits to /usr/bin/passwd domain if /usr/bin/passwd is executed. To allow changing password, you need to allow access to /etc/shadow to the /usr/bin/passwd domain. But you don't want to allow access to /etc/shadow to the /bin/cat domain to print the password file. Then, what will happen if /usr/bin/passwd is executed as "/bin/cat" like Fig. 23?
♦ Fig. 23 Executing "passwd" command as "cat"
# sh -c 'exec -a /bin/cat /usr/bin/passwd /etc/shadow' |
By doing Fig. 23, /usr/bin/passwd will run in the /usr/bin/passwd domain. But since the invocation name was /bin/cat , /usr/bin/passwd behaves like /bin/cat . As a result, you allowed behavior like Fig. 24.
♦ Fig. 24 Allowing "cat" to read password file
# sh -c 'exec /bin/cat /etc/shadow' |
To avoid such threat, TOMOYO Linux provides ability to check combination of program's pathname and argv[0] , and the dereferenced pathname ( exec.realpath ) and invocation name ( exec.argv[0] ) are automatically checked against the execute permission. Thus, you can avoid threat like Fig. 23 by forbidding execution of /usr/bin/passwd command as /bin/cat .
Permissions generated using learning mode contains only exec.realpath and exec.argv[0] and symlink.target as conditions. But access logs contain all variables listed in Fig. 1. Thus, by generating policy from access logs rather than using learning mode, you can define permissions with strictest conditions.
In learning mode, once a policy violation occurs, permissions needed for avoiding that violation are automatically appended to the policy configuration in order to avoid future policy violation. But permissions automatically appended do not contain all information listed in Fig. 1. Thus, configure profile not to automatically append permissions. (Fig. 25)
♦ Fig. 25 Changes in /etc/ccs/profile.conf
[Before modification] PREFERENCE::learning={ verbose=no } [After modification] PREFERENCE::learning={ verbose=no max_entry=0 } |
Save the profile, and then run the command in Fig. 26 in order to reflect the changes.
♦ Fig. 26 Reflect the changes
# /usr/sbin/ccs-loadpolicy p |
Run the programs. All policy violations are saved as "access rejected logs".
A lot of messages like Fig. 27 will be printed since you specified max_entry=0 in Fig. 25, but you can ignore these messages.
♦ Fig. 27 Message when reached the upper limit for learning mode
WARNING: Domain 'domainname' has so many ACLs to hold. Stopped learning mode. |
Pick up lines containing " mode=learning " using grep command. (Fig. 28) Note the leading and trailing spaces. If you forget to specify these spaces, it might match the filename (e.g. "allow_read /path/to/file/mode=learning/and/so/on ).
♦ Fig. 28 Pick up only learning mode's access logs
# grep -F -A 2 " mode=learning " /var/log/tomoyo/reject_log.conf > /var/log/tomoyo/learning_log.txt |
Then, convert to conditional permissions. (Fig. 29)
♦ Fig. 29 Convert to permissions with conditions
# /usr/lib/ccs/convert-audit-log < /var/log/tomoyo/learning_log.txt > /var/log/tomoyo/policy.tmp |
Then, compress by sorting by domainnames. (Fig. 30)
♦ Fig. 30 Sort by domainnames
# /usr/sbin/ccs-sortpolicy < /var/log/tomoyo/policy.tmp > /var/log/tomoyo/policy.txt |
You may append the contents of /var/log/tomoyo/policy.txt to /etc/ccs/domain_policy.conf as domain policy. But the contents of /var/log/tomoyo/policy.txt will be too strict to use as policy configuration (like Fig. 31). For example, you should not specify process ID and i-node number because they will change every time. Thus, prune unnecessary conditions using text editor before appending to /etc/ccs/domain_policy.conf .
♦ Fig. 31 Permission which is too strict to apply
allow_execute /usr/bin/id if task.pid=4641 task.ppid=4637 task.uid=48 task.gid=48 task.euid=48 task.egid=48 task.suid=48 task.sgid=48 task.fsuid=48 task.fsgid=48 task.state[0]=0 task.state[1]=0 task.state[2]=0 task.type!=execute_handler path1.uid=0 path1.gid=0 path1.ino=603159 path1.major=8 path1.minor=1 path1.perm=0755 path1.type=file path1.parent.uid=0 path1.parent.gid=0 path1.parent.ino=589834 path1.parent.perm=0755 exec.realpath="/usr/bin/id" exec.argc=1 exec.envc=7 exec.argv[0]="id" exec.envp["TERM"]="linux" exec.envp["PATH"]="/sbin:/usr/sbin:/bin:/usr/bin" exec.envp["PWD"]="/usr/share/horde/admin" exec.envp["LANG"]="en_US.UTF-8" exec.envp["SHLVL"]="3" exec.envp["LANGUAGE"]="en_US.UTF-8" exec.envp["_"]="/usr/bin/id" |
In this installment, I explained conditional permissions. In the next installment, I explain countermeasure for SSH bruteforce attacks which is recently burgeoning and steps to splitting administrative operations, using TOMOYO Linux's characteristic hierarchized domain transitions. Don't miss it!
Go back to the fourth installment. Proceed to the sixth installment.