System Security in SolarisTM 10: Privileges and Zones in Perspective -- Part 1
Peter van der Weerd
In Unix distributions through the ages, security has been based on two entities: IDs and file permissions. Every file has a UID (user id) and a GID (group id), which determine ownership of the file; and permissions, which determine the rights a user, a group, and the rest of the world will have. Whether a particular user is allowed to read, write, or execute a file depends upon the IDs and permissions that are stored in the file's inode.
At a certain point, Access Control Lists were introduced, but it still is a matter of connecting IDs and permissions. A regular user wanting to perform a particular task that requires superuser rights must acquire the superuser's UID. This will allow the user to perform not only one particular task but all tasks. So, in the old model, a user is unable to do any real admin tasks until he acquires UID 0 (root). But from that moment on, he will be able to do all admin tasks.
Then, in Solaris 8, came Role Based Access Control. RBAC interconnects roles, profiles, authorizations, and users in such a way to allow certain users to perform certain actions, like rebooting a machine and performing other administrative actions, without having to be aware of the root password. Clearly, this has been an improvement. What used to be an "all or nothing approach" changed into a finer-grained security model. But it still is a matter of UIDs and permissions.
In Solaris 10, the concept of privileges was introduced. The concept of privileges (or Least Privilege, as it is officially called) is not new. At the end of the twentieth century, the National Security Agency began developing a way to make operating systems more secure. This new concept included changes to the kernel in combination with RBAC. Linux was chosen as the platform for development. In 2000, the first public release became available, based on kernel 2.2.12. Because this article focuses on Sun Microsystems' implementation, refer to:
for more information on Security Enhanced Linux.
What Is RBAC Again?
A user has two UIDs: a Real UID and an Effective UID. This is not entirely true because Posix and System V Unixes introduced a third UID, the Saved UID. We don't need the Saved UID for this discussion, though.
At login time, both UIDs are identical, based on the entry in the passwd-file. When a user starts a second process, the Effective UID may differ from the Real UID. To accomplish this, a user would typically run the su command. When a regular user with, say UID 2001, runs su, he will be asked for the superuser password, and a new process will be created. This process has Real UID 2001 and Effective UID 0. This means that for the lifetime of this new process, the user runs all his instructions with Effective UID 0. The user will have to know the password of the UID he wants to switch to. Root would be the only one that can switch to a regular user without knowing that user's password. Having to know the other user's password is a major flaw in the use of su.
RBAC combines users, roles, profiles, authorizations, and execute attributes. A user can su to a role, thus enabling himself to perform certain instructions based on the role's profile. The profile is connected to an "execute" right. This execute right is a specific command that will be executed with a specific Effective UID.
It is good practice to connect multiple profiles to one role so as to allow a user to do multiple administration tasks once he has su-ed to that role. As with su, the user must know the password of the role he wants to su to, but his execute rights will be much more limited on the basis of the exec attributes he is entitled to:
User -> Role -> Profile -> Exec Attribute (command with EUID)
Here's an example:
First, a regular user called "baseuser" is created on an x86 machine called "solx":
solx# useradd -m -d /export/home/baseuser baseuser
solx# passwd baseuser
New Password: Re-enter new Password: passwd: password successfully changed for baseuser
solx# grep baseuser /etc/passwd
Second, a role is added to the system:
solx# roleadd -m -d /export/home/reboot reboot 64 blocks
solx# passwd reboot
New Password: Re-enter new Password: passwd: password successfully changed for reboot
solx# grep reboot /etc/passwd
Notice the shell (/bin/pfsh). This shell enables a user to execute a command in a profile. This is not a shell you can login to.
Connect the user "baseuser" to the role "reboot":
solx# usermod -R reboot baseuser
solx# grep baseuser /etc/user_attr
Create a profile:
solx# echo "REBOOT:::profile to reboot:help=reboot.html" > \
Connect the profile "REBOOT" to the role "reboot":
solx# rolemod -P REBOOT reboot
solx# grep reboot /etc/user_attr
So, there is a user called "baseuser" connected to the role "reboot". The role "reboot" has a profile called "REBOOT". All that is left to do is to make sure that the profile (REBOOT) will allow the role (reboot) to execute /usr/sbin/reboot with the correct EUID of 0:
solx# echo "REBOOT:suser:cmd:::/usr/sbin/reboot:euid=0" > \
Now, the baseuser can log in, su to the role "reboot" and run /usr/sbin/reboot to reboot the machine. Whether in fact you would want to allow anybody to run reboot to reset a machine instead of running shutdown is beyond the scope of this article.
All of this is still based on being somebody as a Unix user. A user that is not connected to a role will not be able to assume that role; a role not connected to a profile will not be able to run that profile; and a profile not connected to the proper execute attribute will not be able to run the command that it has in mind. A lot of files with a lot of colons.
Privileges work on a different level -- the process level, which is maintained by the kernel. This is a big difference: RBAC works in userland, related to UIDs and permissions; privileges work on a kernel level; UIDs and file permissions are by-passed. This means that a regular user can, if his process is granted the privilege, read a file that is only readable by root on account of the UID in the file's inode. Or, on the other hand, a user that has read access to a directory may not be able to read anything anymore because the privilege to fork has been revoked from the process privilege list.
To list the total amount of privileges, you can run ppriv:
solx# ppriv -l | wc -l
Any of these 48 privileges can be connected to any single process on your system. To make things easier, Sun Microsystems grouped these privileges in the following sets: Effective set, Permitted set, Inheritable set, and Limit set.
The Effective set is the set of privileges that are currently in effect. It holds the privileges that a process has at runtime. If you must, you can compare it to the Effective UID.
The Permitted set is the set of privileges a process can maximally obtain. This resembles the Real UID. A privilege can be added to the Effective set only if it is part of the Permitted set.
The Inheritable set is the set of privileges that will be inherited by, or passed on to, sub-processes. A privilege not in the Inheritable set will neither be in the Effective nor in the Permitted set of a sub-process.
The Limit set is the set of privileges that a process and its children may obtain. These privileges can be "promoted" to the Permitted set of a process, and from there on upwards, to both the Effective and Inherited sets.
To query the sets and privileges at your disposal, run ppriv again:
solx$ ppriv $$
flags = none
solx$ ppriv -v $$
flags = none
Changing the privileges of processes doesn't seem to be very functional, because when the user exits and logs in again, all changes will be gone. Nevertheless, some examples to get the idea of changing privilege sets.
Here is an example of revoking PRIV_PROC_FORK from the Effective set of PID 1774:
solx# ppriv -s E-proc_fork 1774
solx# ppriv 1774
flags = none
In this example, process 1774 will get a permission denied message every time it tries to fork. Try typing ls, for example.
You can allow PID 1882 to read any file on the system by adding PRIV_FILE_DAC_READ to the sets:
solx# ppriv -s EIP+file_dac_read 1882
solx# ppriv 1882
flags = none
The process with PID 1882 is allowed to read any file on the system, irrespective of the EUID and file permissions.
What we really want is to make these privileges more permanent for particular users of applications. We want these privileges to be set for the user at login time to make sure that every process created by that user will have a desired set of privileges. To achieve that goal, we can add them to /etc/user_attr next to roles entry:
solx# usermod -K defaultpriv=basic,-file_link_any baseuser
solx# grep baseuser /etc/user_attr
In this example, user "baseuser" will not be able to create any hardlinks to files that he does not own. The reduced privilege set will be in effect at login time of the user:
solx# su - baseuser
Sun Microsystems Inc. SunOS 5.10 Generic January 2005
$ln /etc/hosts myhosts
ln: cannot create link myhosts: Not owner
The user can get another confirmation of the lack of a privilege by using the debug option of ppriv:
$ ppriv -eD ln /etc/hosts myhost
ln: missing privilege "file_link_any"
So far so good. Apparently RBAC and privileges are two different concepts that work on different levels with "System Security" as a binding factor.
But what about zones? We should talk about the place of zones in all this. Next month, in Part 2 of this article, I will show how to combine privileges and zones to create a secure environment for Apache Web server.