DOMAIN TYPE ENFORCEMENT


Overview

 

Under the Domain Type Enforcement (DTE) abstraction, each process executes within a domain and objects are assigned a type.   A domain definition specifies the rights each domain has to objects of a given type.  All processes executing within the same domain have the same set of access rights.

 

The assignment of processes to domains provides a flexible mechanism to implement a security policy.  A domain might represent all processes associated with ordinary users, or it might represent a system daemon such as the network time protocol daemon.   A domain need not be associated with the rights of any single user.  Most other security models assign rights based on some characteristic of a user, for example her security clearance (Multilevel Security), his role (i.e., job) in the organization (Role Based Access Control), or his identity (standard UNIX access control).  

 

A primary advantage of DTE is that it allows the administrator to find an appropriate balance between security (POLP) and policy complexity.  For example, from the perspective of a system administrator, the access requirements of all users may be sufficiently similar that they would be collected into a single domain.  While this might violate the principle of least privilege, the domain definition could disallow processes in this domain from modifying the files associated with system configuration and operation.  This likely meets the overall security goals for a system in which user data is not critical, but maintenance of a working platform is important.  An educational setting might have these security goals. If a more fine-grained approach is required, the domain could be subdivided, for example into domains that correspond to each major area of study: computer science, history, etc.



Domain and Type Enforcement (DTE) was developed by Badger, et al. with the goal to improve simplicity and compatibility of the flexible and strong type enforcement (TE) access control mechanism (Badger, et al. 1996). In relation to TE, Domain Type Enforcement provided a high-level language for expressing policies and maintained file security attributes in a concise human-readable format within a runtime DTE database.

 

Specification

 

We will look at DTE by example.  Consider Policy 1 below.  It gives each process all possible permissions to every file on the system.[1] The policy is written in Simplified Domain Type Enforcement Language (SDTEL).[2] 

 

A DTE policy is composed of four statement types: type, domain, initial_domain and assign.  At least one statement of each of these four types must appear in the policy.  In SDTEL, the type statement should appear first.  Next the domain statement(s) should appear.  The initial_domain statement comes next, followed by one or more assign statements.

 

Policy 1: Unrestricted Access

 

A type statement enumerates the set of all types that are part of the policy.  There is only one type in Policy 1: unrestricted_t.    

 

The initial_domain statement causes the initial process to run in the specified domain, unrestricted_d in this case.  

 

A domain statement specifies one or more entry point programs as well as the access processes running in the domain have to objects of each type.  The entry point program must be invoked in order for an executing process to enter the domain. In this policy there is one domain: unrestricted_d.   The entry point program is /sbin/init.  

 

Processes in the unrestricted_d domain have c,d,r,w, and x permissions to files of type unrestricted_t.   The d permission applies to directories and is similar to the x permission to directories on UNIX.  The r, w, and x permissions are similar to r, w, and x on UNIX.  The c permission indicates the default type for objects created by processes in the domain.  

There is only one object type in Policy 1, so the domain statement for unrestricted_d explicitly specifies the access this domain has to all system objects.  When there is more than one object type, the default is for processes to have no access.  A domain statement must explicitly grant access to each type that is required by processes in that domain. 

 

The assign statement specifies exactly one type for each file in the system.  More specifically, it associates a type with a path.  A recursive assignment, indicated by  -r, applies to all files whose path has the indicated prefix.  In Policy 1, there is only one assign statement.  It assigns the type unrestricted_t to every file on the system whose path begins with /.  Hence, all files in the directory tree rooted at / have the same type: unrestricted_t.  

 

The single domain unrestricted_d in Policy 1 is allowed all permissions to the only file type unrestricted_t.   In implementation, DTE is layered over the standard UNIX permissions.  Once a request passes the DTE restrictions, it will be subject to a UNIX permissions check.  Hence, under Policy 1, the UNIX permissions contain all the restrictions on running processes.  In order to simplify the discussion, from this point we will not consider the UNIX restrictions imposed in addition to a DTE policy.

 

 

 

Policy 1 illustrates important DTE and SDTEL basics, but does not impose any real restrictions on access to system objects.  For our next example, we suppose that we want to restrict the files accessible to an application called simpleDaemon.  The application is implemented by the binary /bin/simpleDaemon. This application only requires read and write access to the file /etc/simpleDaemon.txt. It does not require access to any other files on the system.  We want to add these restrictions to those of Policy 1 without making any other changes to the access processes have to objects.

Abstractly, we can create a new domain for the application.  Processes in the domain will only have read and write access to /etc/simpleDaemon.txt and /bin/simpleDaemon will run in this new domain.

 

 


Policy 2: Simple Daemon

 

 

Policy 2 implements these additional restrictions.  (Line numbers have been

added as a convenience.)  Policy 2 contains an additional type simpleDaemon_t (line 01).  This type is associated with the file that the simpleDaemon application is allowed to access.  Notice that the assign statement (line 14) is not recursive.  Longer path associations override shorter ones.  Hence, the assignment to Ò/etc/simpleDaemonÓ will override the association to Ò/Ó. We have also added a second domain, simpleDaemon_d , which represents the simpleDaemon application.  This domain only has read and write access (rw) to simpleDaemon_t. 

 

Under DTE, the domain determines the access that is allowed.  So we define multiple domains that grant access to different sets of processes.  A relevant question then is how a process begins execution in a particular domain and whether a process can move from one domain to another. 

 

By default, when a process in domain X creates a new process, the new process also runs on domain X.  In order for a process to be created in DNEW we specify a set of domain transitions.  The transition contains three parts: (1) the set of binaries that may be executed in order to enter domain DNEW (the entry point programs),  (2) the set of domains from which DNEW can be entered, and (3) whether a transition from DOLD to DNEW is mandatory or optional.  Policy 2 (line 08) specifies that domain simpleDaemon_d can only be entered through execution of the binary /bin/simpleDaemon.  Components (2) and (3) are defined via the subject-to-subject permissions definition within a domain statement.  An example is line 6 of Policy 2.  This statement gives domain unrestricted_d  the auto permission to domain simpleDaemon_d.  The auto permission indicates that when the entry point program of the specified domain (simpleDaemon_d in line 6) is executed, the process will transition to that domain.  Policy 2 specifies that whenever /bin/simpleDaemon is executed from the unrestricted_d domain, the process will run in the simpleDaemon_d domain.  The other subject-to-subject permission is exec, which specifies that the transition is optional. 

          

 

Description: :dteTransition.png   

Figure 1: Example Transition into simpleDaemon_d

 

LetÕs look at domain transitions in a little more detail.  Remember that on UNIX systems, a new process can only be created via the fork system call.  When a process running under DTE in domain X executes this call, the new process will also run in domain X.  The child process from a fork is essentially a copy of the parent process at the time of the fork.  In order to run a different binary, the child must make a call to some variant of the exec system call.  The point at which the call to exec is executed is the point at which a decision is made on whether a domain transition takes place.  This is illustrated in Figure 1.  It shows an example transition from unrestricted_d into simpleDaemon_d.  Initially, a process created from /bin/tcsh is executing in unrestricted_d (part (a)).  This process calls fork, which creates a child process executing in the same domain (part (b)).  Finally, the child process calls execle with parameters that specify execution of /bin/simpleDaemon.  Since this is the entry point program for simpleDaemon_d and the subject-to-subject permissions for unrestricted_d specify auto for simpleDaemon_d, the child process executes in simpleDaemon_d.  If the exec permission were specified instead of auto, then the child process could execute in either unrestricted_d or simpleDaemon_d. Note that an additional parameter to exec would be required to indicate the domain the process should execute within and, in the case of an optional transition via the exec flag, whether the transition should take place.[3]

 

Policy 3: User Account Restriction

 

 

Under Policy 2, the binary /bin/simpleDaemon can only be executed from the unrestricted_d domain.  Whenever this binary is executed, the process transitions to the simpleDaemon_d domain.  A process in simpleDaemon_d can only read and write the file /etc/simpleDaemon.txt.  Hence, the only access allowed by any process created from /bin/simpleDaemon is read and write to /etc/simpleDaemon.txt.   

Notice that we added an additional type access statement to the unrestricted_d domain definition (line 05).   If we had not added this statement, processes running in the unrestricted_d domain would have no access to /etc/simpleDaemon.txt. Recall that our goal was to restrict access by the simpleDaemon application, but to leave all the other accesses allowed by Policy 1.  If we had not added this to the domain definition for unrestricted_d, then our policy would not be correct. We would have removed access to /etc/simpleDaemon.txt that is given to processes other than /bin/simpleDaemon which is allowed within Policy 1.

 


Figure 2: Shell Execution Under Policy 3

 

Larger Example

 

Policy 3 aims to disallow the system binaries from being written by certain accounts.  This policy is taken from ÒComputer Security: Art and ScienceÓ, by Matt Bishop.   The first process created on UNIX systems, /sbin/init, runs in daemon_d. All the daemons the system spawns during startup will also run in daemon_d.   On a UNIX system, some variant of getty will run on specified terminals to present the login prompt.  When a user logs in, getty will spawn login so that a user can authenticate.  This policy assumes that users login via the /usr/bin/login binary.  The auto transition will cause this process to execute in the login_d domain.  When a user authenticates successfully, the specified shell will be spawned.  This policy assumes that one of sh, csh, or ksh will be spawned.  Through the exec subject-to-subject permission, the shell can run in either user_d or admin_d.  This is depicted in Figure 2. The login process is trusted to run the shell in the appropriate domain based on the user authentication.


Notice that once a process enters the
user_d domain, neither the process or any of its descendants can transition out of this domain.  Further, this domain does not have write permission to sysbin_t.  Hence users cannot write to the system binaries.  Even if a process in this domain were to acquire UID 0 or GID 0, it can only write to files to which the domain is allowed write access.   Notice that processes in the daemon_d are also disallowed write access to the system binaries.  Hence, a compromised daemon running as root in this domain could not insert a Trojan horse or virus into the system binaries.


 

Bibliography

Badger, L., D.F. Sterne, D.L. Sherman, K.M. Walker, and S.A. Haghighat. "A Domain and Type Enforcement UNIX prototype." Proceedings of the 5th USENIX UNIX Seucrity Symposium. Berkeley, CA: USENIX Association, 1996. 127-140.

Walker, K.M., Sterne, D.F.,Badger, M.L., Petkac, M.J.,Oostendorp, K.A. "Confining Root Programs with Domain Type Enforcement (DTE)." Proceedings of the Sixth USENIX UNIX Security Symposium. San Jose, CA: USENIX Association, 1996. 21-36.

 

 

 



[1] DTE is typically used in conjunction with the UNIX access controls. A request is first checked against the DTE policy.  If the DTE policy allows the request, then it is checked against the UNIX permissions.  On a real system, the UNIX permissions would likely impose additional constraints on every process.

[2] SDTEL implements a subset of DTEL and is intended for use with the DTEvisual system for learning DTE.

[3] In Policy 2, the source domain unrestricted_d has permission to execute the entry point program /bin/simpleDaemon.  The destination domain simpleDaemon_d does not.  An implementation could require either or both the source and destination domains to have execute permission.  We assume that execute permission is granted automatically to the source domain for any entry point program without requiring explicit execute access to the type of the entry point program binary.