• No results found

3.5 Architecture of the MAC Framework

3.5.3 Entry point design considerations

The kernel service entry point KPI is the means by which kernel subsystems, such as file systems and the network stack, engage the reference monitor in security-relevant events and decisions. Wherever possible, the MAC Framework takes the perspective that kernel subsystems implement objects whose instances may be labelled, and that policies may be adequately enforced through controls on method invocation.

This approach is often a natural fit for the kernel architecture, which often (despite a lack of formal language support for object-oriented programming) takes on an object- oriented structure. In most cases, selection of the objects to protect is a straight-forward result of analysing the APIs offered to userspace via system calls: sockets, pipes, and files, as well as the system calls that invoke methods on them seems natural. In other cases, the design choice is less clear: should all sysctl MBI nodes be independent

objects with labels, or should they collectively be treated as a single object with read and write methods? The MAC Framework takes the latter approach on the basis that many policies require fine-grained consideration of files and directories, but not of

sysctlnodes.

Once objects have been identified, selecting and placing entry points also requires careful design: the more granular the KPI, the more expressive policies can be – how- ever, this is also at the cost of policy complexity. Similarly, a consistent philosophy to

placing entry point invocations is important: the fewer the invocations, the easier they are to validate – however, too few invocations leads to inadequate protection. MAC Framework entry point invocation is necessarily somewhat subjective, but generally re- volves around balancing placing the checks deep enough to allow a single enforcement point for a particular level abstraction.

As an example: in early versions of the MAC Framework, access control checks for files were performed in the file systems themselves – in later versions, this was moved to the common VFS code invoking all file systems, in order to provide consistent protection. Placing VFS access control too high in the call stack for I/O system calls, however, would place them before file descriptors are differentiated into specific object types such as vnodes and sockets. File systems are necessarily involved in the storage strategy for persistent labels within the file system, but where possible rely on common infrastructure code in the MAC Framework to implement common models, such as extended attribute-based storage. Similarly, the labelling ofvnodes rather than the on- demand provision of labels by file systems when policies make access control decisions was motivated by a desire to share abstractions across file systems, but also to provide a uniform caching model8.

Most policy entry points are entered due to invocation of a corresponding kernel service entry point:

• Object life cycle events, such as socket creation and destruction

• Access control requests checking a subject’s use of a method on an object • General and sometimes subject-free decision requests

Entry point KPIs must be designed with great care in order to provide sufficient information so that policies can implement their semantics while also discouraging unsafe constructions that might, for example, lead to concurrency vulnerabilities. For the policy entry point KPI, it is also necessary to be sensitive to kernel binary interface (KBI) compatibility rules in the base OS, which requires that most third-party modules compiled against an earlier point release of a major release branch work on later point releases. In the MAC Framework context, that policy implies that policy modules compiled on, for example, FreeBSD 8.0 should also work on FreeBSD 8.1 to the greatest extent possible. For this reason, it is desirable to limit policy module exposure to kernel internal data structures where not specifically required for policy semantics. It is simultaneously desirable to offer the flexibility to use those internal structures where

8File systems operate in one of two modes in the MAC Framework:

singlelabel, in which the underlying file system cannot support persistent storage of labels for individual files and directories, andmultilabel, where the file system does implement this capability. In the former case, individual

object labels for in-memoryvnodes are not precluded, but the policy must tolerate loss of values when

avnodefalls out of the cache, or an alternative method of deriving or persistently storing object labels.

required in order to avoid policy developers simply bypassing formal KPIs, which would be counter to the maintainability goals of the MAC Framework.

Structuring the MAC Framework to prevent bugs in policy modules, and the frame- work itself, is a central design concern. Where possible, the framework design employs language types to detect programmer errors; its structure also enables static analysis (such as completeness checking on controlling access to classes) through its use of sym- bols. Sometimes programmability and binary compatibility goals come into conflict, however. Earlier versions of the framework, prior to the advent of C99 sparse static structure initialisation, named entry points using constants registered entry point func- tions cast to void *. On face value, this approach offers stronger KBI resilience by

avoiding embedding the layout of policy entry point vectors into modules – however, it also discards type information for arguments to entry points. When we experimentally switched to explicit, typed entry point functions, we discovered a number of previously unnoticed bugs in policy modules that had been incorrectly interpreting their argu- ments. This design choice has also been adopted by LSM, but not by Apple’s kauth(9) framework, which leads to concern that policies implemented against the latter might contain similar bugs9.