SELinux Policy Management Infrastructure Design
Introduction
As SELinux has matured it has become apparent that there are three important and much needed additional capabilities. First, there are only coarse grained, all or nothing permissions controlling changes and updates to the policy. A domain with permission to load a policy into a running system has permission to completely change the policy in arbitrary ways. This makes it difficult to securely divide policy administration among several administrators or create automated policy management tools. Second, there is a need for more robust support for user-space applications and daemons that integrate SELinux as a security model. This includes support for dynamically registering object classes and creating a scalable architecture for providing access control decisions. Finally, more infrastructure is needed for policy management, both local and networked. The recent policy module work begins to address some of the management issues, but more work is needed.
The solution to these challenges is to create a policy management and protection infrastructure, including an enhanced SELinux policy language and user-space policy server. The policy server will manage and protect the policy, communicating with the SELinux kernel, user-space object managers, and eventually other network policy servers. The explicit goals for the policy server are:
- enforce fine-grained access control and delegation of policy access;
- support user-space object managers integrating SELinux support; and
- enable coherent administration of all policy, both locally and networked.
This document presents a design for a policy server. It contains a description of the policy object model, its associated policy language requirements, a high level functional description of the server, and a discussion of what will be accomplished with the initial prototype.
Technical Overview
First is a policy management server that encapsulates all access to the policy, including policy updates and queries. Second is an abstraction of the policy into SELinux object classes with some additional policy language syntax that allows access to the policy to be specified in terms of type enforcement (TE) policy. The result will be an infrastructure that manages and protects the policy, increasing both functionality and security.
The policy server will have two distinct functions: policy management and access decision computation for user-space object managers. The policy management functionality is referred to as the policy management server and the access decision computation in the userspace security server. The userspace security server is, for the most part, a copy of the kernel security server made into a userspace daemon. The policy management server will:
- Manage the policy by mediating all policy access by encapsulating the policy;
- Enforce fine-grained access control over policy changes;
- Provide enhanced policy management infrastructure.
The security server will:
- Provide access decisions for user-space object managers;
- Facilitate user-space object managers by providing a mechanism to dynamically query object classes.
Initially, the servers will communicate with user-space applications and daemons over standard inter-process communications (IPC) mechanisms. In the future, network access could allow for the secure management of policies across multiple systems.
The policy abstraction allows the creation of a TE policy that includes access control statements defining access to the policy in a fine-grained manner. This allows a policy to, in essence, protect itself from unwanted change through the creation of a policy about the policy, called the meta policy. The meta policy is enforced by the policy management server, which implements a set of object classes that represent the policy (though it queries the security server for access permissions). The meta policy object classes represent all components of the policy including users, roles, types, and object classes. The object class permissions control the specific use of the components.
Technical Details
This section examines the proposed architecture in more detail. The discussion covers the design at a high level, with very few of the implementation details included. This section begins with terminology and then examines policy encapsulation, policy access control, the policy servers, and labeling.
Terminology
SELinux has several components and concepts that need further description and delineation in the context of the policy servers. The policy, though generally referred to as a whole, contains many distinct parts. Also, the definition of policy logic and its enforcement is separated into several components as well.
Policy Subdivisions
For the scope of this project the entire SELinux policy, including labeling instructions in the form of file context specifications, is defined as the system policy. The system policy includes several distinct parts, which are further differentiated based on two criteria: content and intended enforcer.
The system policy can be separated into three types of content. The Role Based Access Control (RBAC) policy includes all statements pertaining to users and roles and their relationships with each other and other system policy components. The RBAC policy does not directly specify access, but rather organizes users in groups, or roles, and assigns a set of authorized types to those roles. The Type Enforcement (TE) policy statements define types and object classes. This includes both their specification and statements defining access and auditing in terms of relationships between them. This also includes type transition and type change statements. The TE policy is the only policy component that directly specifies access. The label policy specifies initial labels for object instances. For the purpose of this paper, label policy is defined to be file context specifications and genfs, fs_use, initial sid, nodecon, portcon, and netifcon statements.
The system policy can also be separated into three parts based on the intended policy enforcer. The kernel policy includes all policy statements relating to kernel object classes that will be enforced by the SELinux kernel. The user-space policy includes all policy statements relating to user-space object classes that will be enforced by user-space applications. This distinction is not completely clear. For example, a trusted user-space application may enforce access to kernel object classes. Finally, the meta policy is an instance of a user-space policy that relates to access control on the policy. The meta policy will be covered in more detail below.
SELinux Components
SELinux cleanly separates the enforcement of policy from the definition of policy logic. Object managers enforce policy decisions on a set of object classes based on policy decisions obtained from a separate component, called a security server. In this project the object managers are further defined. The SELinux kernel is an object manager that enforces access to resources that it controls. Object managers that execute user-space are called user-space object managers. User-space object managers may enforce decisions on object classes defined in the kernel, by mirroring the object class on its own objects or they must create new object classes to represent internal abstractions and resources.
SELinux Policy Components
| Role Based Access Control | The policy statements dealing with user and roles and their relationships with each other and types. |
| Type Enforcement | The policy statements dealing with types and object classes. This includes all object class definitions and access, auditing, type transition, and constraint rules. |
| Label Policy | The policy statements dealing with initial object labeling. This includes file contexts specifications, genfs, fs_use, nodecon, portcon, and netifcon, but not type transition rules. |
| System Policy | The system policy represents the entire SELinux policy. This includes the RBAC, TE, and labeling policies for both kernel and user-space. |
| Kernel Policy | The portion of the policy enforced by the SELinux kernel. |
| User-space Policy | The portion of the policy enforced by user-space object managers. |
| Meta Policy | The portion of the policy pertaining to access control on the policy. This is an instance of user policy. |
| User-space Object Manager | A software component executing in user-space that abstracts its resources as SELinux object classes. All user-space object managers are user-space enforces over at least their internal object classes. |
| User-space Security Server | A user-space daemon that has a copy of the policy and can fulfill access decision requests. |
Encapsulation
The primary goal of the policy servers is to encapsulate all access to the system policy. No other goals can be achieved unless the policy server is a non-bypassable mediator between user-space processes and the system policy for both updates and access decisions. The encapsulation will be achieved by:
- Protecting all of the policy server's resources with an appropriate kernel policy;
- Limiting the permission to load a policy into the SELinux kernel to the policy server; and
- Leveraging the meta policy to prevent modifications to the policy that would violate the encapsulation.
Initially the policy management infrastructure will be an optional component of an SELinux system. The existing kernel policy loading mechanism will remain unchanged and the current management practices will continue to work. However, if the policy management infrastructure is in use it must maintain complete control over the policy.
Policy Access Control
Enabling fine-grained access control on the SELinux policy serves two closely related purposes. Enhanced access control will allow the application of least privilege to policy changes. The current coarse permissions mean, for example, that a SELinux user management application must be given full access to the policy when it only needs sufficient access to add, remove, or update users. The fine-grained control will also make it possible to distribute administration of the policy to multiple admistrative domains. This allows the distribution of policy adminstration of important subsystems, like a database or webserver, to a separate administrative domain without giving that domain access to policy for other subsystems.
Background and Previous Work
Current convention is that a policy is built from multiple source files into a monolithic binary file that is loaded into the kernel. The binary kernel policy may be built on its host machine or it may be built on a separate machine that may not even be an SELinux machine. The common public SELinux policies dictate that, on an SELinux machine running in enforcing mode, a domain that has direct write access to the binary policy file type, typically policy_config_t, may add, modify, or delete any portion of the system policy. This superuser-like access has become even more problematic as more application domains in the standard public policies are granted write access to the binary kernel policy. Primary examples of this are domains defined for package manager software.
Our work that developed an initial capability to manage binary policy modules was the first step in establishing the infrastructure necessary to control and delegate access to a system's policy in a proper and consistent manner. The policy module infrastructure created a policy management system that defined a model for maintaining policy coherency when adding or building a system's TE policy. The model introduced a defined procedure for creating the binary policy in a manner that is easily controlled by a general TE policy for itself. The next step is to define and implement a model that allows for fine-grained access control and the ability to delegate that control on different portions of the policy.
General Approach
There are two primary elements necessary to implement access control on the policy: a policy object model and an additional implicit constraint model to preserve the intent of the policy. We are introducing the concept of a meta policy that defines access control to the system policy components. The meta policy enforces access control based on the domain of the process requesting policy changes and the types of the policy resources being added or changed. The user space policy enforcement mechanism makes it possible to develop an object model for the policy components themselves. This object model abstracts the policy into a set of SELinux object classes, which can be used for relatively fine-grained access control. The implicit constraint mechanism refines the access control further by introducing additional policy syntax and semantics to allow the maximum permissions of a group of types to be limited without requiring verbose policy statements.
Policy Language Changes
Both the policy object model and implicit constraints necessitate the addition of policy syntax for subdividing namespaces for types, users, roles, bools, and object classes. The current syntax has a flat namespace with limited wildcard capabilities. The proposed syntax creates hierarchical namespaces, similar to those used in object oriented programming languages, using '.' as a delimiter. For example, this allows for the creation of the type apache, with the types apache.daemon and apache.cgi as children. The other policy components work in a similar way. This hierarchy allows one to refer to groups of components by labeling them based on the hierarchy. by labeling symbols based off the hierarchy it is possible to create equivalence classes of users, roles, types and so on. Additionally a language addition to declare that a specific type is only a container and not for use with kernel object classes may be added.
Policy Object Model
The policy object model abstracts the policy into a set of SELinux object classes that can be used to enforce access control. These object classes, like the existing kernel object classes, represent resources with the object class permissions representing possible access methods to those resources. Policy resources consist primarily of policy components that require declaration, such as types or users. Instances of these object classes, like other object instances, must have an associated security context. Currently in SELinux, explicit policy statements determine the security context of an object. The number of objects in an SELinux policy would make explicit labeling very verbose, however. We propose determining the security context of a policy object instance implicitly, based on the name of the instance. In order to avoid collisions between explicitly and implicitly defined symbols, portions of the type namespace are reserved. For example each role will have a type associated with it in the "role." type namespace matching its identifier. The resultant type for the role user_r would be role.user_r. Each object type in the policy including classes, roles, users and booleans have their own reserved namespace. Types are a special case in that they are labeled with their own identifier so the type "user_t" is represented as "user_t" in the meta policy object classes.
The meta policy defines object classes over which the policy management server enforces access. The following table enumerates the meta policy object classes and permissions roughly estimated to be necessary for policy access control. Details descriptions may be found in the appendix to this document.
| Class | Permission | Description |
|---|---|---|
| Common policy | add | Add this type of object. |
| remove | Remove this type of object. | |
| policy.type | use | Permission to use a type. |
| policy.attribute | add_type | Allow adding another type to this attribute. |
| policy.user | add_role | Permission to add another role to this user. |
| add_seuser | The add_seuser permission is checked each time an seuser is added that maps to this user. | |
| policy.role | use | Use this role in the source or target of a role allow or as the destination of a role transition rule. |
| add_type | Permission to add another type to a role. | |
| policy.fcontext (not yet implemented) | relabel_from | Permission to change a context from the old value. |
| relabel_to | Permission to change a context to the new value. | |
| policy.bool | (no class specific permissions) | |
| policy.class | use | Use this class in a type_transition, allow, dontaudit or neverallow rule, accordingly. |
| add_perm | Add a permission to the class specified. | |
Meta policy rules use one of the above defined object classes. For example
allow rpm_t etc_t : policy.type use;
states that the rpm_t domain is allowed to add rules to the policy that use etc_t in the target of an allow rule. This rule alone is not sufficient for permitting rpm_t to add an allow rule. The rpm_t domain also needs permission to use at least one type as a source type in an allow rule as well as permission to use one or more object classes. So, the meta policy might contain:
allow rpm_t httpd_t : policy.type use; allow rpm_t policy.class_file_t : policy.class use;
Protecting the policy intent
The policy object model provides only coarse-grained access control. For example, the privilege to use a type is expressed only in terms of a single type making it impossible to restrict the use of types to only certain pairs of types. It is also difficult to express meta policy for unknown types, roles, users, or classes. Extending the policy object model to address these challenges would require significant changes to the existing policy language and result in a complex and verbose meta policy.
To address these challenges, further additions to the policy language and an additional enforcement model is required. These additions add the concept of hierarchy to the policy and enforce constraints on policy statements based on this hierarchy. These additions provide a powerful semantic model that helps to preserve policy intent during policy change without requiring verbose meta policy statements. There are two main components to this change: policy language syntax for declaring hierarchical policy elements and a set of additional constraints enforced on policy statements.
The SELinux policy contains separate namespaces for users, roles, types, and object classes. Currently, these namespaces are flat. The hierarchy syntax introduces the "." character as a delimiter into the role, type, and object class namespaces. Using this delimiter it is possible to declare an element in a namespace that is a child of another element. For example, declaring the type apache.daemon creates a new type that is a child of the type apache. See Figure 1 for a more complete example. Each of the child elements is completely separate from the parent; no attributes or allowed access is inherited from the parent. There is no limit on the number of children a type can have or the depth of the hierarchy. Also, the declaration of a child does not implicitly declare the parent, though it is possible to declare a parent after the child. Using this syntax, it is possible to create complex trees of roles, types, or object classes.
Example type hierarchy
Note that the users namespace cannot be changed until the mechanism that maps Linux users to SELinux users is changed. Linux usernames can contain a ".", making it impossible to use that as the hierarchy delimiter until the implicit mapping between Linux and SELinux usernames is removed.
In addition to the policy syntax, the hierarchy feature creates additional policy semantics in the form of implicit constraints on roles and types. These constraints, which will be enforced by the compiler and the policy management server, create a policy semantic that can be combined with the policy object model to enable efficient delegation of policy administration while ensuring that the policy is not changed in a way that changes the intent of the policy. The constraints limit the access of a child to no more access than that of the parent. For types, this means that a child type cannot have an attribute that the parent does not have and cannot have an allowed access relationship with another type and object class that the parent does not have. For roles, this means that a child role cannot be authorized for a type for which the parent is not authorized. Only the immediate parent is considered in these constraints. Policy Servers
The goal of this project is not to change the kernel at all to adapt this architecture. The kernel will continue to load and enforce a policy in the same way it does now. The kernel may no longer contain the entire policy, however. User-space policy statements, including types and object classes not required to enforce kernel access control, will be removed from the kernel policy before loading. This could potentially significantly reduce the use of non-swappable kernel memory for the policy and remove the need for changes to the kernel to add additional object classes. Policy Management Server
The policy management server will provide an infrastructure for managing the system policy and act as a user-space object manager for meta policy objects. This server will be based on the policy module work and will perform the existing functions that the policy module store performs. The policy management server has three main functions: mediation of all policy access, enforcement of fine-grained access conrol over policy changes, and enhancing and facilitating policy management.
The policy management server will maintain the connonocal copy of the system policy, much like the SELinux kernel does currently. Other components, including the security server, the SELinux kernel, and user-space object managers will have cached copies of portions of the policy, but the policy management server will retain the single authoritative copy. This means that the policy management server must:
- Mediate all policy updates and access;
- Maintain a consistent and coherent system policy at all times; and
- Provide notification to other SELinux components that the policy has changed.
It is not clear what methods will be provided for policy updates. At a minimum the current notion of installing policy modules will be retained, but an additional API may also be provided for policy management tools that wish to make smaller incremental changes to the policy. The definition of policy change and providing appropriate interfaces to allow convenient updates in a transactional manner will be an area of ungoing work.
Security Server
The security server will provide access decisions to the user-space object managers based on a policy provided by the policy management server. This design retains the separation between policy enforcement and access decision computation in the current SELinux architecture without forcing the entire policy to be stored in kernel memory. The user-space object managers will connect to the security server over IPC and request access control decisions. Each user-space object manager will have a cache of access decisions, mitigating much of the overhead of the IPC associated with querying security server.
Label Policy
Labeling in SELinux is handled in two distinct fashions. There is a definition of an initial system state and there are policy rules that state how new objects are labeled and if and how existing objects' labels may change. The initial system state is currently embodied in separate file context files. There are some direct declarations in the policy regarding how to label objects in filesystem types that do not support extended attributes (i.e., the current SELinux mechanism for filesystem labels). The second portion of the label policy is embodied in the type_* rules in the system policy.
The policy server needs to address several aspects of labeling. It needs to be able to make decisions on whether or not to allow the introduction of file context specifications to the system policy. It needs to evaluate whether or not genfs statements can be accepted into the policy. It needs to be able to know if it can accept type_* rules. The prototype version of the policy server will most likely only address type_* rules.
Other Issues
To take full advantage of the new ability to delegate policy updates to other people (and applications) the next step should be to create a full API for making such updates. A low level API for doing simple updates in the same format as the source (or binary) policy followed by a high level API for making abstract changes to the policy (such as policy duplication, unique type generation, and templating. Augmenting the policy language to facilitate these abstractions, possibly replacing m4 is also a possibility.
Further, updating and expanding the policy server to enable network policy propagation and security 'events' such as a network wide boolean toggle would also be a useful and interesting addition.
Prototype Scope and Goals
Developing the policy server will be a large and complicated task. The overall goal for the initial period of work is to produce a prototype server that demonstrates fine-grained delegation access over the policy through the use of a user-space policy enforcer. The initial example of an SELinux aware user space server will be the policy server itself. The policy server will use the binary module infrastructure as a back end policy management tool. The base policy will be written to enforce the notion that all policy changes must go through the policy server and only the policy server will be permitted to introduce policy into the policy module store, build, and load new policies.
The policy for the policy server (meta policy) will initially be stored in the kernel policy for ease of implementation. This will result, among other things, in the addition of multiple new object classes to the base kernel policy. Particularly for this reason the prototype is not meant to be integrated into the mainline SELinux code tree. However, it is a goal that the policy server will be a completely self-contained architecture. The policy server will not obviate the current policy management model unless enabled. Once enabled the policy server must encapsulate all policy access in order to function properly.
The bulk of the prototype work will be in creating the internal architecture to support the policy server. The compiler, checkpolicy, will be modified to support the policy language changes. The language changes are envisioned to be relatively minor with no or little effect on the current language. New APIs will be added to libselinux to support the interface to the policy server. The binary policy module infrastructure will be further refined to mesh with the required functionality of the policy server. Policy will be written to protect in the strictest fashion the policy server and module architecture. The policy will be written so that if the policy server is not used, the current policy update model will be preserved.
All of the work will be released as open source under a GPL license. Feedback will be sought during the development from the SELinux development community via release of documentation and code on the SELinux mailing list. An effort will be made to thoroughly document the language, the management model, development decisions, and how the prototype differs from what is envisioned as an operational, upstreamed architecture.
Appendix: Metapolicy Permission Descriptions
Below are descriptions of all metapolicy permissions. A policy consists of six policy components: permission classes, users, roles, types, attributes, and booleans. In terms of metapolicy enforcement attributes are distinct from types. These six components are labelled by the policy management server. Their representative types are then checked using normal allow rules. The permission for the check is based upon how the component is being utilized.
common policy
All policy components inherit from the policy permission class.
- add
- An add permission is checked for every policy component definition. A definition is any location where a component may be created. Statements within a module's require and optional blocks are considered declarations, not definitions, as they simply advertise the existence of a component but do not actually allocate entries within the policy's symbol tables.
- remove
- The remove permission is checked for all components that cease or potentially cease to exist in the final policy. A catalog of all identifiers from all modules is generated during metapolicy checking. The new catalog is compared against the previous one to find components that have been removed. Furthermore, all components defined in optional statements have their remove permissions checked, for one can effectively remove portions of a policy by eliminating the optionals' dependencies.
class policy.class inherits policy
As the policy server currently relies on the kernel for access decisions, policies may neither add nor remove classes, nor may they add permissions to existing classes. In preparation for when the policy server switches to a user-land enforcer, the {add_perm permission is included here but are not currently enforced.
- use
- The use permission is checked against the class specified in type transition statements, AV allow statements, AV dontaudit statements, and AV neverallow statements.
- add_perm
- The add_perm is checked when a module attempts to add permissions to existing object classes. This permission is not currently enforced.
class policy.user inherits policy
The class policy.user governs permissions associated with adding and removing users from a policy. Since users may be authorized for multiple roles there is no atomic "modify" permission. To effect a modify, the new role should be added and the old one removed. Be aware that granting add but not add_role permission effectively creates a user with no login permission.
- add_role
- The add_role permission is checked each time a role is added to a user's authorized list.
- add_seuser
- The add_seuser permission is checked each time an seuser is added that maps to the specified SELinux user.
class policy.role inherits policy
- use
- The use permission is checked against the source or target role in role allow statements. It is also checked against the destination role in role_transition statements.
- add_type
- The add_type permission is checked whenever a new type is added to a role.
class policy.fcontext inherits policy
The class policy.fcontext governs permissions associated with adding, changing and removing mappings of a path to a file security context. Since we do not wish to label the paths themselves, the implementation shall require the use of FCGlob-style patterns to determine whether one fcontext would override another for the relabelfrom and relabelto permissions. This will prevent a user from defining an overly broad file context that supercedes an existing file context that the user is not authorized to modify. Not yet implemented.
- relabelfrom
- The relabelfrom permission is checked each time a file context is changed to verify that the caller is permitted to change a context from the old value.
- relabelto
- The relabelto permission is checked each time a file context is changed to verify that the caller is permitted to change a context to the new value.
class policy.type inherits policy
The class policy.type governs both the addition and removal of types but also their use within AV rules. Note that within AV rules attributes are expanded into their component types; those types are then checked for appropriate use permissions.
- use
- The use permission is checked when a type is used in type_transition, allow, dontaudit and neverallow statements.
class policy.attribute inherits policy
The metapolicy treats attributes differently from types even though they share the same namespace. Attributes have their own add and remove permissions which govern their creation and removal. Although they are just a grouping mechanism, it was deemed imperative that policies be able to limit the addition of attributes. For example, a malicious module might attempt to elevate its privileges by adding itself to privuser. Therefore there is a permission that controls how one may add types to existing attributes.
- add_type
- The add_type permission is checked whenever a type is being added to an attribute, either by declaring a new type and its attributes or appending to an existing attribute by way of typeattribute statements.
class policy.bool inherits policy
Like users and roles, booleans are created and set using the same declaration. Booleans may not be further modified; thus they have no class-specific permissions.
Attachments
- policy-management-design.dia (1.8 kB) - added by tmiller on 09/20/07 15:05:14.
- policy-management-design.png (7.7 kB) - added by tmiller on 09/20/07 15:05:36.

