mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
202 lines
10 KiB
Text
202 lines
10 KiB
Text
![]() |
========================================================
|
||
|
Linux Security Modules: General Security Hooks for Linux
|
||
|
========================================================
|
||
|
|
||
|
:Author: Stephen Smalley
|
||
|
:Author: Timothy Fraser
|
||
|
:Author: Chris Vance
|
||
|
|
||
|
.. note::
|
||
|
|
||
|
The APIs described in this book are outdated.
|
||
|
|
||
|
Introduction
|
||
|
============
|
||
|
|
||
|
In March 2001, the National Security Agency (NSA) gave a presentation
|
||
|
about Security-Enhanced Linux (SELinux) at the 2.5 Linux Kernel Summit.
|
||
|
SELinux is an implementation of flexible and fine-grained
|
||
|
nondiscretionary access controls in the Linux kernel, originally
|
||
|
implemented as its own particular kernel patch. Several other security
|
||
|
projects (e.g. RSBAC, Medusa) have also developed flexible access
|
||
|
control architectures for the Linux kernel, and various projects have
|
||
|
developed particular access control models for Linux (e.g. LIDS, DTE,
|
||
|
SubDomain). Each project has developed and maintained its own kernel
|
||
|
patch to support its security needs.
|
||
|
|
||
|
In response to the NSA presentation, Linus Torvalds made a set of
|
||
|
remarks that described a security framework he would be willing to
|
||
|
consider for inclusion in the mainstream Linux kernel. He described a
|
||
|
general framework that would provide a set of security hooks to control
|
||
|
operations on kernel objects and a set of opaque security fields in
|
||
|
kernel data structures for maintaining security attributes. This
|
||
|
framework could then be used by loadable kernel modules to implement any
|
||
|
desired model of security. Linus also suggested the possibility of
|
||
|
migrating the Linux capabilities code into such a module.
|
||
|
|
||
|
The Linux Security Modules (LSM) project was started by WireX to develop
|
||
|
such a framework. LSM is a joint development effort by several security
|
||
|
projects, including Immunix, SELinux, SGI and Janus, and several
|
||
|
individuals, including Greg Kroah-Hartman and James Morris, to develop a
|
||
|
Linux kernel patch that implements this framework. The patch is
|
||
|
currently tracking the 2.4 series and is targeted for integration into
|
||
|
the 2.5 development series. This technical report provides an overview
|
||
|
of the framework and the example capabilities security module provided
|
||
|
by the LSM kernel patch.
|
||
|
|
||
|
LSM Framework
|
||
|
=============
|
||
|
|
||
|
The LSM kernel patch provides a general kernel framework to support
|
||
|
security modules. In particular, the LSM framework is primarily focused
|
||
|
on supporting access control modules, although future development is
|
||
|
likely to address other security needs such as auditing. By itself, the
|
||
|
framework does not provide any additional security; it merely provides
|
||
|
the infrastructure to support security modules. The LSM kernel patch
|
||
|
also moves most of the capabilities logic into an optional security
|
||
|
module, with the system defaulting to the traditional superuser logic.
|
||
|
This capabilities module is discussed further in
|
||
|
`LSM Capabilities Module <#cap>`__.
|
||
|
|
||
|
The LSM kernel patch adds security fields to kernel data structures and
|
||
|
inserts calls to hook functions at critical points in the kernel code to
|
||
|
manage the security fields and to perform access control. It also adds
|
||
|
functions for registering and unregistering security modules, and adds a
|
||
|
general :c:func:`security()` system call to support new system calls
|
||
|
for security-aware applications.
|
||
|
|
||
|
The LSM security fields are simply ``void*`` pointers. For process and
|
||
|
program execution security information, security fields were added to
|
||
|
:c:type:`struct task_struct <task_struct>` and
|
||
|
:c:type:`struct linux_binprm <linux_binprm>`. For filesystem
|
||
|
security information, a security field was added to :c:type:`struct
|
||
|
super_block <super_block>`. For pipe, file, and socket security
|
||
|
information, security fields were added to :c:type:`struct inode
|
||
|
<inode>` and :c:type:`struct file <file>`. For packet and
|
||
|
network device security information, security fields were added to
|
||
|
:c:type:`struct sk_buff <sk_buff>` and :c:type:`struct
|
||
|
net_device <net_device>`. For System V IPC security information,
|
||
|
security fields were added to :c:type:`struct kern_ipc_perm
|
||
|
<kern_ipc_perm>` and :c:type:`struct msg_msg
|
||
|
<msg_msg>`; additionally, the definitions for :c:type:`struct
|
||
|
msg_msg <msg_msg>`, struct msg_queue, and struct shmid_kernel
|
||
|
were moved to header files (``include/linux/msg.h`` and
|
||
|
``include/linux/shm.h`` as appropriate) to allow the security modules to
|
||
|
use these definitions.
|
||
|
|
||
|
Each LSM hook is a function pointer in a global table, security_ops.
|
||
|
This table is a :c:type:`struct security_operations
|
||
|
<security_operations>` structure as defined by
|
||
|
``include/linux/security.h``. Detailed documentation for each hook is
|
||
|
included in this header file. At present, this structure consists of a
|
||
|
collection of substructures that group related hooks based on the kernel
|
||
|
object (e.g. task, inode, file, sk_buff, etc) as well as some top-level
|
||
|
hook function pointers for system operations. This structure is likely
|
||
|
to be flattened in the future for performance. The placement of the hook
|
||
|
calls in the kernel code is described by the "called:" lines in the
|
||
|
per-hook documentation in the header file. The hook calls can also be
|
||
|
easily found in the kernel code by looking for the string
|
||
|
"security_ops->".
|
||
|
|
||
|
Linus mentioned per-process security hooks in his original remarks as a
|
||
|
possible alternative to global security hooks. However, if LSM were to
|
||
|
start from the perspective of per-process hooks, then the base framework
|
||
|
would have to deal with how to handle operations that involve multiple
|
||
|
processes (e.g. kill), since each process might have its own hook for
|
||
|
controlling the operation. This would require a general mechanism for
|
||
|
composing hooks in the base framework. Additionally, LSM would still
|
||
|
need global hooks for operations that have no process context (e.g.
|
||
|
network input operations). Consequently, LSM provides global security
|
||
|
hooks, but a security module is free to implement per-process hooks
|
||
|
(where that makes sense) by storing a security_ops table in each
|
||
|
process' security field and then invoking these per-process hooks from
|
||
|
the global hooks. The problem of composition is thus deferred to the
|
||
|
module.
|
||
|
|
||
|
The global security_ops table is initialized to a set of hook functions
|
||
|
provided by a dummy security module that provides traditional superuser
|
||
|
logic. A :c:func:`register_security()` function (in
|
||
|
``security/security.c``) is provided to allow a security module to set
|
||
|
security_ops to refer to its own hook functions, and an
|
||
|
:c:func:`unregister_security()` function is provided to revert
|
||
|
security_ops to the dummy module hooks. This mechanism is used to set
|
||
|
the primary security module, which is responsible for making the final
|
||
|
decision for each hook.
|
||
|
|
||
|
LSM also provides a simple mechanism for stacking additional security
|
||
|
modules with the primary security module. It defines
|
||
|
:c:func:`register_security()` and
|
||
|
:c:func:`unregister_security()` hooks in the :c:type:`struct
|
||
|
security_operations <security_operations>` structure and
|
||
|
provides :c:func:`mod_reg_security()` and
|
||
|
:c:func:`mod_unreg_security()` functions that invoke these hooks
|
||
|
after performing some sanity checking. A security module can call these
|
||
|
functions in order to stack with other modules. However, the actual
|
||
|
details of how this stacking is handled are deferred to the module,
|
||
|
which can implement these hooks in any way it wishes (including always
|
||
|
returning an error if it does not wish to support stacking). In this
|
||
|
manner, LSM again defers the problem of composition to the module.
|
||
|
|
||
|
Although the LSM hooks are organized into substructures based on kernel
|
||
|
object, all of the hooks can be viewed as falling into two major
|
||
|
categories: hooks that are used to manage the security fields and hooks
|
||
|
that are used to perform access control. Examples of the first category
|
||
|
of hooks include the :c:func:`alloc_security()` and
|
||
|
:c:func:`free_security()` hooks defined for each kernel data
|
||
|
structure that has a security field. These hooks are used to allocate
|
||
|
and free security structures for kernel objects. The first category of
|
||
|
hooks also includes hooks that set information in the security field
|
||
|
after allocation, such as the :c:func:`post_lookup()` hook in
|
||
|
:c:type:`struct inode_security_ops <inode_security_ops>`.
|
||
|
This hook is used to set security information for inodes after
|
||
|
successful lookup operations. An example of the second category of hooks
|
||
|
is the :c:func:`permission()` hook in :c:type:`struct
|
||
|
inode_security_ops <inode_security_ops>`. This hook checks
|
||
|
permission when accessing an inode.
|
||
|
|
||
|
LSM Capabilities Module
|
||
|
=======================
|
||
|
|
||
|
The LSM kernel patch moves most of the existing POSIX.1e capabilities
|
||
|
logic into an optional security module stored in the file
|
||
|
``security/capability.c``. This change allows users who do not want to
|
||
|
use capabilities to omit this code entirely from their kernel, instead
|
||
|
using the dummy module for traditional superuser logic or any other
|
||
|
module that they desire. This change also allows the developers of the
|
||
|
capabilities logic to maintain and enhance their code more freely,
|
||
|
without needing to integrate patches back into the base kernel.
|
||
|
|
||
|
In addition to moving the capabilities logic, the LSM kernel patch could
|
||
|
move the capability-related fields from the kernel data structures into
|
||
|
the new security fields managed by the security modules. However, at
|
||
|
present, the LSM kernel patch leaves the capability fields in the kernel
|
||
|
data structures. In his original remarks, Linus suggested that this
|
||
|
might be preferable so that other security modules can be easily stacked
|
||
|
with the capabilities module without needing to chain multiple security
|
||
|
structures on the security field. It also avoids imposing extra overhead
|
||
|
on the capabilities module to manage the security fields. However, the
|
||
|
LSM framework could certainly support such a move if it is determined to
|
||
|
be desirable, with only a few additional changes described below.
|
||
|
|
||
|
At present, the capabilities logic for computing process capabilities on
|
||
|
:c:func:`execve()` and :c:func:`set\*uid()`, checking
|
||
|
capabilities for a particular process, saving and checking capabilities
|
||
|
for netlink messages, and handling the :c:func:`capget()` and
|
||
|
:c:func:`capset()` system calls have been moved into the
|
||
|
capabilities module. There are still a few locations in the base kernel
|
||
|
where capability-related fields are directly examined or modified, but
|
||
|
the current version of the LSM patch does allow a security module to
|
||
|
completely replace the assignment and testing of capabilities. These few
|
||
|
locations would need to be changed if the capability-related fields were
|
||
|
moved into the security field. The following is a list of known
|
||
|
locations that still perform such direct examination or modification of
|
||
|
capability-related fields:
|
||
|
|
||
|
- ``fs/open.c``::c:func:`sys_access()`
|
||
|
|
||
|
- ``fs/lockd/host.c``::c:func:`nlm_bind_host()`
|
||
|
|
||
|
- ``fs/nfsd/auth.c``::c:func:`nfsd_setuser()`
|
||
|
|
||
|
- ``fs/proc/array.c``::c:func:`task_cap()`
|