Permissive and Restricted Policies
By Glenn Faden-Oracle on Mar 31, 2013
Recently I posted two entries about the new Extended Policy functionality in Oracle Solaris 11.1. One demonstrated how to create application sandboxes, and the other how to confine services, like MySQL. Both of these are examples of restrictive policies, whereas privileges have traditionally been used to implement permissive policies, hence the term privilege escalation. The basic functionality and terminology first appeared in Trusted Solaris in 1991, and was later adopted by AIX and HP-UX. Unfortunately, a draft of the POSIX 1.e Security Specification (withdrawn), used the term capabilities for this functionality, which was subsequently used by Linux developers. Oracle Solaris privileges do share some common terminology with Linux capabilities , including the permitted, effective, and inheritable privilege sets. But almost everything else is different.
For example, the term unprivileged doesn't apply in Oracle Solaris, since every process has at least some privileges. Instead, we use the term basic privileges to refer to the set that are traditionally granted to all UNIX processes. This set includes:
Removing some of these privileges, or enumerating the objects to which they apply is a powerful containment mechanism which I've previously described. But even normal users may choose to limit their basic privileges. For example, my .bash_profile contains the following line, which limits my view of processes on the system to just the ones I own by removing PRIV_PROC_INFO from my login shell. It makes programs like ps(1) and prstat(1) more friendly.
Another difference is that recent versions of Linux allow the setting of file capabilities in the extended attributes of executable files, as an alternative to using the setuid-to-root permission bit. That's what Trusted Solaris did, too, but now Oracle Solaris uses a special rights profile called Forced Privilege, to specify the process privileges for setuid-to-root programs. The Forced Privilege profile is unique in that it is always in effect regardless of who is executing these programs.
Both the AppArmor and SELinux security modules plug into the LSM framework, so they can restrict access to specific objects. But these modules are not invoked when such access requires a capability (privilege) which was not already granted to the process, so a permissive mechanism is also needed. Although file capabilities can be used to elevate process privileges, they must be used carefully because they apply to any user who executes that file. So most Linux user's rely on sudo(1M), which grants them additional access.
Although Solaris supports sudo, it isn't hooked into the kernel like rights profiles are. The sudo command needs to run as root with all privileges so that it can grant the attributes specified for each program in the /etc/sudoers file for the current user. But it cannot specify the attributes of any subsequent child processes. The best it can do is block their execution. For example, the Solaris version of sudo prevents this by removing the PRIV_PROC_EXEC privilege from the process.
Instead Solaris provides an integrated execution environment in which every program invoked by the user runs with the process attributes specified in the user's hierarchical set of rights profiles. Following the principle of least privilege, both restrictive and permissive policies are implemented using a single framework. This environment can be made completely transparent to users when their accounts are created, in which case their available programs are determined by their rights profile assignments. Alternatively, users may explicitly request profile-based execution by prepending the prefix pf to their favorite shell names, or via pfexec. Unlike the sudo command, these shells do not run with elevated privileges. Instead, they set a process flag, PRIV_PFEXEC, which is inherited by their child processes. When programs are executed the kernel checks this flag; if set it queries a policy server, pfexecd, for the appropriate process attributes and applies them to the new process credential.
Unlike AppArmor and SELinux, the entire policy is not loaded into the kernel. Instead, the policy is cached in user space by the Name Service Cache Daemon, nscd. So the policy can be maintained in an LDAP directory, and updated at any time. Those aspects of the policy that apply to currently executing processes are maintained in their kernel credential structures. When programs are executed for which no explicit attributes are specified, the parent's process credential structure is shared with the child.
Here's a flowchart of how it all works: