The system call interface provides an abstraction for userspace to interact with the kernel, and is a tempting location to mediate access. In fact, no kernel modifications are required to overwrite entries in the system call lookup table, making it trivial to mediate this interface using kernel modules [18,19]. While this is an attractive feature, mediating the system call interface provides limited value for a general purpose security framework such as LSM . This level of mediation is not race-free, may require code duplication, and may not adequately express the full context needed to make security policy decisions.
The basic abstraction of the LSM interface is to mediate access to internal kernel objects. LSM seeks to allow modules to answer the question ``May a subject S perform a kernel operation OP on an internal kernel object OBJ?''
LSM allows modules to mediate access to kernel objects by placing hooks in the kernel code just ahead of the access, as shown in Figure 1. Just before the kernel would have accessed an internal object, a hook makes a call to a function that the LSM module must provide. The module can either let the access occur, or deny access, forcing an error code return.
The LSM framework leverages the kernel's existing mechanisms to translate user supplied data -- typically strings, handles or simplified data structures -- into internal data structures. This avoids time of check to time of use (TOCTTOU) races  and inefficient duplicate look ups. It also allows the LSM framework to directly mediate access to the core kernel data structures. With such an approach, the LSM framework has access to the full kernel context just before the kernel actually performs the requested service. This improves access control granularity.
Given the constrained design space described in Section 2, the LSM project chose to limit the scope of the LSM design to supporting the core access control functionality required by the existing Linux security projects. This limitation enabled the LSM framework to remain conceptually simple and minimally invasive while still meeting the needs of many of the security projects. It also strengthened the justification for adopting the LSM framework into the Linux kernel, since the need for enhanced access controls was more generally accepted by the kernel developers than the need for other kinds of security functionality such as auditing.
A consequence of the ``stay simple'' design decision is that LSM hooks are primarily restrictive: where the kernel was about to grant access, the module may deny access, but when the kernel would deny access, the module is not consulted. This design simplification exists largely because the Linux kernel ``short-circuits'' many decisions early when error conditions are detected. Providing for authoritative hooks (where the module can override either decision) would require many more hooks into the Linux kernel.
However, the POSIX.1e capabilities logic requires the ability to grant accesses that would ordinarily be denied at a coarse level of granularity. In order to support this logic as a security module, LSM provides some minimal support for these permissive hooks, where the module can grant access the kernel was about to deny. The permissive hooks are typically coupled with a simple DAC check, and allow the module to override the DAC restriction. Figure 2 shows a user access request where a failed user ID check can be overridden by a permissive hook. These hooks are limited to the extent that the kernel already consults the POSIX.1e capable() function.
Although LSM was not designed to explicitly support security auditing, some forms of auditing can be supported using the features provided for access control. For example, many of the existing Linux security projects provide support for auditing the access checks performed by their access controls. LSM also enables support for this kind of auditing. Some security auditing can also be supported via existing kernel modules by interposing on system calls, as in the SNARE project .
Many security models require binding security attributes to kernel objects. To facilitate this, LSM provides for opaque security fields that are attached to various internal kernel objects (detailed in Section 4.1.1). However, the module is completely responsible for managing these fields, including allocation, deallocation, and concurrency control.
Finally, module composition presented a challenge to the LSM design. On the one hand, there clearly is a need to compose some modules with complementary functionality. On the other hand, fully generic security policy composition is known to be intractable . Therefore, LSM permits module stacking, but pushes most of the work to the modules themselves. A module that wishes to be stackable must itself export an LSM-like interface, and make calls to subsequently loaded modules when appropriate. The first module loaded has ultimate control over all decisions, determining when to call any other modules and how to combine their results.