Check out the new USENIX Web site.

next up previous
Next: Conclusions Up: Comparison of Implementations Previous: Handing Off Control to

Adding Security Servers for New Tasks

 

The final method for changing the security policy is to create a set of task-based Security Servers. In the three previously described methods, all tasks operate under a single, monolithic policy. With this method there may be more than one Security Server computing access decisions for the microkernel and other clients, each defining a separate set of security rules. While the microkernel is enforcing multiple policies, each task on the system is associated with one and only one Security Server which serves as its primary Security Server. In fact, each task is associated with a list of Security Servers ordered by precedence. There is a well-defined policy for each task because there is only one way for each access request to be computed by the entire set of Security Servers.

For this method we introduce a new global variable: the Security Server stack. Each entry in the stack consists of a data structure containing the security and client ports for each Security Server. At boot time, the initial Security Server uses the set_special_port command to enter the security and client ports to the initial entry in the stack. Another global variable, curr_ss, points to that entry in the stack to indicate that the initial Security Server is the current Security Server. When another Security Server is created, it also enters its ports to the stack at the first available entry, and curr_ss is incremented to the next position in the stack.

 

Figure 3: Security Server Stack Before ``Push''

 

Figure 4: Security Server Stack After ``Push''

Each task has a pointer labeled ss_ptr that identifies the Security Server that defines the policy under which the task is running. When tasks are created, ss_ptr is set to curr_ss by default, though the parent task may cause the value of ss_ptr for the new task to be set to the parent's Security Server. Like any other process, each new Security Server itself operates under the policy defined by a Security Server which precedes it in the stack (the Security Server immediately preceding it would be the default). If each Security Server in the stack refers to its immediate predecessor in the stack, then it is truly a stack-like implementation. If the Security Servers in the ``stack'' refer to servers older than their immediate predecessors, then a graph of the dependencies could be more accurately described as a ``tree.'' This tree-like structure for the dependencies between the Security Servers give this implementation an interesting set of properties.

 

Figure 5: The tree-like dependency among a set of Security Servers

When the microkernel receives a request, it checks its cache for the permission. If the permission is not in the cache, it sends a request to the Security Server assigned to the requesting task. The Security Server computes the requested security access, unless it receives a request with a context that it does not understand. If the Security Server cannot resolve the SIDs into security contexts, it forwards the request to its own Security Server. The request is passed down the tree until some Security Server, possibly the ``root'' Security Server, is able to resolve the SIDs into contexts and a security computation can be made.

This method for changing the security policy is the most robust and possibly the most flexible method of the four methods discussed in this paper. However, the additional flexibility and reliability of enforcing multiple security policies may come with an increased cost for assuring the security of the system.

Policy Flexibility

This method for changing policy provides the capability for considerable flexibility for changing the policy. However, as new Security Server s are created, only new tasks operate under the new policy rules; so changes to the system-wide policy are local rather than global. In other words: you can't teach an old dog new tricks, because old tasks will continue to run under the policy defined by the old Security Server.

There is the possibility that the stack could be augmented by using one of the other policy changing mechanisms to force old tasks to run under a new policy. For example, if there are two servers in the stack at positions 0 and 1, the Security Server at position 0 could hand off to a third Security Server which is identical to the Security Server in position 1. Thus, both servers operating would define the same policy, and the microkernel would be enforcing only one policy rather than two. [In fact, the first two servers could then exit, all tasks with pointers to the second Security Server would be re-directed to the server at position 0 (the third server), and the system would only have one Security Server as well as one policy.]

Functional Flexibility

Functional flexibility is the greatest strength of the Security Server stack. Allowing running processes to run under their original policy is a way of ``grandfathering'' in their allowed accesses. Thus, in our banking example, if some user is actively working on a process at 5:00 PM which must be completed, but the bank's security policy is set to change to a more restrictive policy at that time, the user would be allowed to continue his task because the task is operating under the less restrictive policy. However, any attempt by a user to create new tasks after 5:00 pm would be subject to the new, more restrictive policy.

Security

This method is a double-edged sword. It is possible that certain tasks which need to be highly constrained could operate under more restrictive policies than is generally required. This could be an advantageous design for increasing security. However, coordinating the necessary elements could be a nightmare for system designers and for any attempts to provide formal assurance evidence. In effect there would be multiple, overlapping security policies. One could not make broad global statements about the behavior of the system and the rules in place at any given time.

Also, once a task is granted a permission to perform some operation, it is allowed to keep that permission, even if another more restrictive Security Server is pushed onto the stack. Thus, in the event of an intrusion, a rogue process which has gained unauthorized access to system resources may be able to continue unchecked. Thus, the gains made for functional flexibility allow for a loss of security. In order to harden the defenses of a system like this, it would be necessary to graft another method of policy change on top of this one.

Reliability

This method improves upon the hand-off for reliability because there is no vulnerable moment when the rights for the security port are in transit. It is also more reliable than the Reload Policy Method because the top Security Server in the stack will still be able to make security computations even if new Security Servers fail to initialize due to corrupted security databases.

Performance

Explicit performance numbers are not available for this method. However, it is anticipated to be as fast or faster than the hand-off, and expected transition times should be between four and five seconds. The greatest factor in the performance for the stack is the loading of the large executable for creating a new server to push onto the stack, which is also true of the hand-off. The hand-off is slower because the rights to the security port have to be transferred from one server to the other. The Security Server stack is quicker than loading the executable for the new server, but adds an extra wait.



next up previous
Next: Conclusions Up: Comparison of Implementations Previous: Handing Off Control to



Brian Loe
Tue Dec 9 09:16:53 CST 1997