Initial commit: Linux kernel 4.19 for Unplugged OS

This commit is contained in:
ziv committed 2025-10-06 13:52:42 +00:00
commit d30235b04c
80519 files changed
+35800681

No files matched your search

+94
View File
@@ -0,0 +1,94 @@
=================================
IMA Template Management Mechanism
=================================
Introduction
============
The original ``ima`` template is fixed length, containing the filedata hash
and pathname. The filedata hash is limited to 20 bytes (md5/sha1).
The pathname is a null terminated string, limited to 255 characters.
To overcome these limitations and to add additional file metadata, it is
necessary to extend the current version of IMA by defining additional
templates. For example, information that could be possibly reported are
the inode UID/GID or the LSM labels either of the inode and of the process
that is accessing it.
However, the main problem to introduce this feature is that, each time
a new template is defined, the functions that generate and display
the measurements list would include the code for handling a new format
and, thus, would significantly grow over the time.
The proposed solution solves this problem by separating the template
management from the remaining IMA code. The core of this solution is the
definition of two new data structures: a template descriptor, to determine
which information should be included in the measurement list; a template
field, to generate and display data of a given type.
Managing templates with these structures is very simple. To support
a new data type, developers define the field identifier and implement
two functions, init() and show(), respectively to generate and display
measurement entries. Defining a new template descriptor requires
specifying the template format (a string of field identifiers separated
by the ``|`` character) through the ``ima_template_fmt`` kernel command line
parameter. At boot time, IMA initializes the chosen template descriptor
by translating the format into an array of template fields structures taken
from the set of the supported ones.
After the initialization step, IMA will call ``ima_alloc_init_template()``
(new function defined within the patches for the new template management
mechanism) to generate a new measurement entry by using the template
descriptor chosen through the kernel configuration or through the newly
introduced ``ima_template`` and ``ima_template_fmt`` kernel command line parameters.
It is during this phase that the advantages of the new architecture are
clearly shown: the latter function will not contain specific code to handle
a given template but, instead, it simply calls the ``init()`` method of the template
fields associated to the chosen template descriptor and store the result
(pointer to allocated data and data length) in the measurement entry structure.
The same mechanism is employed to display measurements entries.
The functions ``ima[_ascii]_measurements_show()`` retrieve, for each entry,
the template descriptor used to produce that entry and call the show()
method for each item of the array of template fields structures.
Supported Template Fields and Descriptors
=========================================
In the following, there is the list of supported template fields
``('<identifier>': description)``, that can be used to define new template
descriptors by adding their identifier to the format string
(support for more data types will be added later):
- 'd': the digest of the event (i.e. the digest of a measured file),
calculated with the SHA1 or MD5 hash algorithm;
- 'n': the name of the event (i.e. the file name), with size up to 255 bytes;
- 'd-ng': the digest of the event, calculated with an arbitrary hash
algorithm (field format: [<hash algo>:]digest, where the digest
prefix is shown only if the hash algorithm is not SHA1 or MD5);
- 'n-ng': the name of the event, without size limitations;
- 'sig': the file signature.
Below, there is the list of defined template descriptors:
- "ima": its format is ``d|n``;
- "ima-ng" (default): its format is ``d-ng|n-ng``;
- "ima-sig": its format is ``d-ng|n-ng|sig``.
Use
===
To specify the template descriptor to be used to generate measurement entries,
currently the following methods are supported:
- select a template descriptor among those supported in the kernel
configuration (``ima-ng`` is the default choice);
- specify a template descriptor name from the kernel command line through
the ``ima_template=`` parameter;
- register a new template descriptor with custom format through the kernel
command line parameter ``ima_template_fmt=``.
+175
View File
@@ -0,0 +1,175 @@
SCTP LSM Support
================
For security module support, three SCTP specific hooks have been implemented::
security_sctp_assoc_request()
security_sctp_bind_connect()
security_sctp_sk_clone()
Also the following security hook has been utilised::
security_inet_conn_established()
The usage of these hooks are described below with the SELinux implementation
described in ``Documentation/security/SELinux-sctp.rst``
security_sctp_assoc_request()
-----------------------------
Passes the ``@ep`` and ``@chunk->skb`` of the association INIT packet to the
security module. Returns 0 on success, error on failure.
::
@ep - pointer to sctp endpoint structure.
@skb - pointer to skbuff of association packet.
security_sctp_bind_connect()
-----------------------------
Passes one or more ipv4/ipv6 addresses to the security module for validation
based on the ``@optname`` that will result in either a bind or connect
service as shown in the permission check tables below.
Returns 0 on success, error on failure.
::
@sk - Pointer to sock structure.
@optname - Name of the option to validate.
@address - One or more ipv4 / ipv6 addresses.
@addrlen - The total length of address(s). This is calculated on each
ipv4 or ipv6 address using sizeof(struct sockaddr_in) or
sizeof(struct sockaddr_in6).
------------------------------------------------------------------
| BIND Type Checks |
| @optname | @address contains |
|----------------------------|-----------------------------------|
| SCTP_SOCKOPT_BINDX_ADD | One or more ipv4 / ipv6 addresses |
| SCTP_PRIMARY_ADDR | Single ipv4 or ipv6 address |
| SCTP_SET_PEER_PRIMARY_ADDR | Single ipv4 or ipv6 address |
------------------------------------------------------------------
------------------------------------------------------------------
| CONNECT Type Checks |
| @optname | @address contains |
|----------------------------|-----------------------------------|
| SCTP_SOCKOPT_CONNECTX | One or more ipv4 / ipv6 addresses |
| SCTP_PARAM_ADD_IP | One or more ipv4 / ipv6 addresses |
| SCTP_SENDMSG_CONNECT | Single ipv4 or ipv6 address |
| SCTP_PARAM_SET_PRIMARY | Single ipv4 or ipv6 address |
------------------------------------------------------------------
A summary of the ``@optname`` entries is as follows::
SCTP_SOCKOPT_BINDX_ADD - Allows additional bind addresses to be
associated after (optionally) calling
bind(3).
sctp_bindx(3) adds a set of bind
addresses on a socket.
SCTP_SOCKOPT_CONNECTX - Allows the allocation of multiple
addresses for reaching a peer
(multi-homed).
sctp_connectx(3) initiates a connection
on an SCTP socket using multiple
destination addresses.
SCTP_SENDMSG_CONNECT - Initiate a connection that is generated by a
sendmsg(2) or sctp_sendmsg(3) on a new asociation.
SCTP_PRIMARY_ADDR - Set local primary address.
SCTP_SET_PEER_PRIMARY_ADDR - Request peer sets address as
association primary.
SCTP_PARAM_ADD_IP - These are used when Dynamic Address
SCTP_PARAM_SET_PRIMARY - Reconfiguration is enabled as explained below.
To support Dynamic Address Reconfiguration the following parameters must be
enabled on both endpoints (or use the appropriate **setsockopt**\(2))::
/proc/sys/net/sctp/addip_enable
/proc/sys/net/sctp/addip_noauth_enable
then the following *_PARAM_*'s are sent to the peer in an
ASCONF chunk when the corresponding ``@optname``'s are present::
@optname ASCONF Parameter
---------- ------------------
SCTP_SOCKOPT_BINDX_ADD -> SCTP_PARAM_ADD_IP
SCTP_SET_PEER_PRIMARY_ADDR -> SCTP_PARAM_SET_PRIMARY
security_sctp_sk_clone()
-------------------------
Called whenever a new socket is created by **accept**\(2)
(i.e. a TCP style socket) or when a socket is 'peeled off' e.g userspace
calls **sctp_peeloff**\(3).
::
@ep - pointer to current sctp endpoint structure.
@sk - pointer to current sock structure.
@sk - pointer to new sock structure.
security_inet_conn_established()
---------------------------------
Called when a COOKIE ACK is received::
@sk - pointer to sock structure.
@skb - pointer to skbuff of the COOKIE ACK packet.
Security Hooks used for Association Establishment
=================================================
The following diagram shows the use of ``security_sctp_bind_connect()``,
``security_sctp_assoc_request()``, ``security_inet_conn_established()`` when
establishing an association.
::
SCTP endpoint "A" SCTP endpoint "Z"
================= =================
sctp_sf_do_prm_asoc()
Association setup can be initiated
by a connect(2), sctp_connectx(3),
sendmsg(2) or sctp_sendmsg(3).
These will result in a call to
security_sctp_bind_connect() to
initiate an association to
SCTP peer endpoint "Z".
INIT --------------------------------------------->
sctp_sf_do_5_1B_init()
Respond to an INIT chunk.
SCTP peer endpoint "A" is
asking for an association. Call
security_sctp_assoc_request()
to set the peer label if first
association.
If not first association, check
whether allowed, IF so send:
<----------------------------------------------- INIT ACK
| ELSE audit event and silently
| discard the packet.
|
COOKIE ECHO ------------------------------------------>
|
|
|
<------------------------------------------- COOKIE ACK
| |
sctp_sf_do_5_1E_ca |
Call security_inet_conn_established() |
to set the peer label. |
| |
| If SCTP_SOCKET_TCP or peeled off
| socket security_sctp_sk_clone() is
| called to clone the new socket.
| |
ESTABLISHED ESTABLISHED
| |
------------------------------------------------------------------
| Association Established |
------------------------------------------------------------------
+14
View File
@@ -0,0 +1,14 @@
=================================
Linux Security Module Development
=================================
Based on https://lkml.org/lkml/2007/10/26/215,
a new LSM is accepted into the kernel when its intent (a description of
what it tries to protect against and in what cases one would expect to
use it) has been appropriately documented in ``Documentation/security/LSM.rst``.
This allows an LSM's code to be easily compared to its goals, and so
that end users and distros can make a more informed decision about which
LSMs suit their requirements.
For extensive documentation on the available LSM hook interfaces, please
see ``include/linux/lsm_hooks.h``.
+158
View File
@@ -0,0 +1,158 @@
SCTP SELinux Support
=====================
Security Hooks
===============
``Documentation/security/LSM-sctp.rst`` describes the following SCTP security
hooks with the SELinux specifics expanded below::
security_sctp_assoc_request()
security_sctp_bind_connect()
security_sctp_sk_clone()
security_inet_conn_established()
security_sctp_assoc_request()
-----------------------------
Passes the ``@ep`` and ``@chunk->skb`` of the association INIT packet to the
security module. Returns 0 on success, error on failure.
::
@ep - pointer to sctp endpoint structure.
@skb - pointer to skbuff of association packet.
The security module performs the following operations:
IF this is the first association on ``@ep->base.sk``, then set the peer
sid to that in ``@skb``. This will ensure there is only one peer sid
assigned to ``@ep->base.sk`` that may support multiple associations.
ELSE validate the ``@ep->base.sk peer_sid`` against the ``@skb peer sid``
to determine whether the association should be allowed or denied.
Set the sctp ``@ep sid`` to socket's sid (from ``ep->base.sk``) with
MLS portion taken from ``@skb peer sid``. This will be used by SCTP
TCP style sockets and peeled off connections as they cause a new socket
to be generated.
If IP security options are configured (CIPSO/CALIPSO), then the ip
options are set on the socket.
security_sctp_bind_connect()
-----------------------------
Checks permissions required for ipv4/ipv6 addresses based on the ``@optname``
as follows::
------------------------------------------------------------------
| BIND Permission Checks |
| @optname | @address contains |
|----------------------------|-----------------------------------|
| SCTP_SOCKOPT_BINDX_ADD | One or more ipv4 / ipv6 addresses |
| SCTP_PRIMARY_ADDR | Single ipv4 or ipv6 address |
| SCTP_SET_PEER_PRIMARY_ADDR | Single ipv4 or ipv6 address |
------------------------------------------------------------------
------------------------------------------------------------------
| CONNECT Permission Checks |
| @optname | @address contains |
|----------------------------|-----------------------------------|
| SCTP_SOCKOPT_CONNECTX | One or more ipv4 / ipv6 addresses |
| SCTP_PARAM_ADD_IP | One or more ipv4 / ipv6 addresses |
| SCTP_SENDMSG_CONNECT | Single ipv4 or ipv6 address |
| SCTP_PARAM_SET_PRIMARY | Single ipv4 or ipv6 address |
------------------------------------------------------------------
``Documentation/security/LSM-sctp.rst`` gives a summary of the ``@optname``
entries and also describes ASCONF chunk processing when Dynamic Address
Reconfiguration is enabled.
security_sctp_sk_clone()
-------------------------
Called whenever a new socket is created by **accept**\(2) (i.e. a TCP style
socket) or when a socket is 'peeled off' e.g userspace calls
**sctp_peeloff**\(3). ``security_sctp_sk_clone()`` will set the new
sockets sid and peer sid to that contained in the ``@ep sid`` and
``@ep peer sid`` respectively.
::
@ep - pointer to current sctp endpoint structure.
@sk - pointer to current sock structure.
@sk - pointer to new sock structure.
security_inet_conn_established()
---------------------------------
Called when a COOKIE ACK is received where it sets the connection's peer sid
to that in ``@skb``::
@sk - pointer to sock structure.
@skb - pointer to skbuff of the COOKIE ACK packet.
Policy Statements
==================
The following class and permissions to support SCTP are available within the
kernel::
class sctp_socket inherits socket { node_bind }
whenever the following policy capability is enabled::
policycap extended_socket_class;
SELinux SCTP support adds the ``name_connect`` permission for connecting
to a specific port type and the ``association`` permission that is explained
in the section below.
If userspace tools have been updated, SCTP will support the ``portcon``
statement as shown in the following example::
portcon sctp 1024-1036 system_u:object_r:sctp_ports_t:s0
SCTP Peer Labeling
===================
An SCTP socket will only have one peer label assigned to it. This will be
assigned during the establishment of the first association. Any further
associations on this socket will have their packet peer label compared to
the sockets peer label, and only if they are different will the
``association`` permission be validated. This is validated by checking the
socket peer sid against the received packets peer sid to determine whether
the association should be allowed or denied.
NOTES:
1) If peer labeling is not enabled, then the peer context will always be
``SECINITSID_UNLABELED`` (``unlabeled_t`` in Reference Policy).
2) As SCTP can support more than one transport address per endpoint
(multi-homing) on a single socket, it is possible to configure policy
and NetLabel to provide different peer labels for each of these. As the
socket peer label is determined by the first associations transport
address, it is recommended that all peer labels are consistent.
3) **getpeercon**\(3) may be used by userspace to retrieve the sockets peer
context.
4) While not SCTP specific, be aware when using NetLabel that if a label
is assigned to a specific interface, and that interface 'goes down',
then the NetLabel service will remove the entry. Therefore ensure that
the network startup scripts call **netlabelctl**\(8) to set the required
label (see **netlabel-config**\(8) helper script for details).
5) The NetLabel SCTP peer labeling rules apply as discussed in the following
set of posts tagged "netlabel" at: http://www.paul-moore.com/blog/t.
6) CIPSO is only supported for IPv4 addressing: ``socket(AF_INET, ...)``
CALIPSO is only supported for IPv6 addressing: ``socket(AF_INET6, ...)``
Note the following when testing CIPSO/CALIPSO:
a) CIPSO will send an ICMP packet if an SCTP packet cannot be
delivered because of an invalid label.
b) CALIPSO does not send an ICMP packet, just silently discards it.
7) IPSEC is not supported as RFC 3554 - sctp/ipsec support has not been
implemented in userspace (**racoon**\(8) or **ipsec_pluto**\(8)),
although the kernel supports SCTP/IPSEC.
+561
View File
@@ -0,0 +1,561 @@
====================
Credentials in Linux
====================
By: David Howells <dhowells@redhat.com>
.. contents:: :local:
Overview
========
There are several parts to the security check performed by Linux when one
object acts upon another:
1. Objects.
Objects are things in the system that may be acted upon directly by
userspace programs. Linux has a variety of actionable objects, including:
- Tasks
- Files/inodes
- Sockets
- Message queues
- Shared memory segments
- Semaphores
- Keys
As a part of the description of all these objects there is a set of
credentials. What's in the set depends on the type of object.
2. Object ownership.
Amongst the credentials of most objects, there will be a subset that
indicates the ownership of that object. This is used for resource
accounting and limitation (disk quotas and task rlimits for example).
In a standard UNIX filesystem, for instance, this will be defined by the
UID marked on the inode.
3. The objective context.
Also amongst the credentials of those objects, there will be a subset that
indicates the 'objective context' of that object. This may or may not be
the same set as in (2) - in standard UNIX files, for instance, this is the
defined by the UID and the GID marked on the inode.
The objective context is used as part of the security calculation that is
carried out when an object is acted upon.
4. Subjects.
A subject is an object that is acting upon another object.
Most of the objects in the system are inactive: they don't act on other
objects within the system. Processes/tasks are the obvious exception:
they do stuff; they access and manipulate things.
Objects other than tasks may under some circumstances also be subjects.
For instance an open file may send SIGIO to a task using the UID and EUID
given to it by a task that called ``fcntl(F_SETOWN)`` upon it. In this case,
the file struct will have a subjective context too.
5. The subjective context.
A subject has an additional interpretation of its credentials. A subset
of its credentials forms the 'subjective context'. The subjective context
is used as part of the security calculation that is carried out when a
subject acts.
A Linux task, for example, has the FSUID, FSGID and the supplementary
group list for when it is acting upon a file - which are quite separate
from the real UID and GID that normally form the objective context of the
task.
6. Actions.
Linux has a number of actions available that a subject may perform upon an
object. The set of actions available depends on the nature of the subject
and the object.
Actions include reading, writing, creating and deleting files; forking or
signalling and tracing tasks.
7. Rules, access control lists and security calculations.
When a subject acts upon an object, a security calculation is made. This
involves taking the subjective context, the objective context and the
action, and searching one or more sets of rules to see whether the subject
is granted or denied permission to act in the desired manner on the
object, given those contexts.
There are two main sources of rules:
a. Discretionary access control (DAC):
Sometimes the object will include sets of rules as part of its
description. This is an 'Access Control List' or 'ACL'. A Linux
file may supply more than one ACL.
A traditional UNIX file, for example, includes a permissions mask that
is an abbreviated ACL with three fixed classes of subject ('user',
'group' and 'other'), each of which may be granted certain privileges
('read', 'write' and 'execute' - whatever those map to for the object
in question). UNIX file permissions do not allow the arbitrary
specification of subjects, however, and so are of limited use.
A Linux file might also sport a POSIX ACL. This is a list of rules
that grants various permissions to arbitrary subjects.
b. Mandatory access control (MAC):
The system as a whole may have one or more sets of rules that get
applied to all subjects and objects, regardless of their source.
SELinux and Smack are examples of this.
In the case of SELinux and Smack, each object is given a label as part
of its credentials. When an action is requested, they take the
subject label, the object label and the action and look for a rule
that says that this action is either granted or denied.
Types of Credentials
====================
The Linux kernel supports the following types of credentials:
1. Traditional UNIX credentials.
- Real User ID
- Real Group ID
The UID and GID are carried by most, if not all, Linux objects, even if in
some cases it has to be invented (FAT or CIFS files for example, which are
derived from Windows). These (mostly) define the objective context of
that object, with tasks being slightly different in some cases.
- Effective, Saved and FS User ID
- Effective, Saved and FS Group ID
- Supplementary groups
These are additional credentials used by tasks only. Usually, an
EUID/EGID/GROUPS will be used as the subjective context, and real UID/GID
will be used as the objective. For tasks, it should be noted that this is
not always true.
2. Capabilities.
- Set of permitted capabilities
- Set of inheritable capabilities
- Set of effective capabilities
- Capability bounding set
These are only carried by tasks. They indicate superior capabilities
granted piecemeal to a task that an ordinary task wouldn't otherwise have.
These are manipulated implicitly by changes to the traditional UNIX
credentials, but can also be manipulated directly by the ``capset()``
system call.
The permitted capabilities are those caps that the process might grant
itself to its effective or permitted sets through ``capset()``. This
inheritable set might also be so constrained.
The effective capabilities are the ones that a task is actually allowed to
make use of itself.
The inheritable capabilities are the ones that may get passed across
``execve()``.
The bounding set limits the capabilities that may be inherited across
``execve()``, especially when a binary is executed that will execute as
UID 0.
3. Secure management flags (securebits).
These are only carried by tasks. These govern the way the above
credentials are manipulated and inherited over certain operations such as
execve(). They aren't used directly as objective or subjective
credentials.
4. Keys and keyrings.
These are only carried by tasks. They carry and cache security tokens
that don't fit into the other standard UNIX credentials. They are for
making such things as network filesystem keys available to the file
accesses performed by processes, without the necessity of ordinary
programs having to know about security details involved.
Keyrings are a special type of key. They carry sets of other keys and can
be searched for the desired key. Each process may subscribe to a number
of keyrings:
Per-thread keying
Per-process keyring
Per-session keyring
When a process accesses a key, if not already present, it will normally be
cached on one of these keyrings for future accesses to find.
For more information on using keys, see ``Documentation/security/keys/*``.
5. LSM
The Linux Security Module allows extra controls to be placed over the
operations that a task may do. Currently Linux supports several LSM
options.
Some work by labelling the objects in a system and then applying sets of
rules (policies) that say what operations a task with one label may do to
an object with another label.
6. AF_KEY
This is a socket-based approach to credential management for networking
stacks [RFC 2367]. It isn't discussed by this document as it doesn't
interact directly with task and file credentials; rather it keeps system
level credentials.
When a file is opened, part of the opening task's subjective context is
recorded in the file struct created. This allows operations using that file
struct to use those credentials instead of the subjective context of the task
that issued the operation. An example of this would be a file opened on a
network filesystem where the credentials of the opened file should be presented
to the server, regardless of who is actually doing a read or a write upon it.
File Markings
=============
Files on disk or obtained over the network may have annotations that form the
objective security context of that file. Depending on the type of filesystem,
this may include one or more of the following:
* UNIX UID, GID, mode;
* Windows user ID;
* Access control list;
* LSM security label;
* UNIX exec privilege escalation bits (SUID/SGID);
* File capabilities exec privilege escalation bits.
These are compared to the task's subjective security context, and certain
operations allowed or disallowed as a result. In the case of execve(), the
privilege escalation bits come into play, and may allow the resulting process
extra privileges, based on the annotations on the executable file.
Task Credentials
================
In Linux, all of a task's credentials are held in (uid, gid) or through
(groups, keys, LSM security) a refcounted structure of type 'struct cred'.
Each task points to its credentials by a pointer called 'cred' in its
task_struct.
Once a set of credentials has been prepared and committed, it may not be
changed, barring the following exceptions:
1. its reference count may be changed;
2. the reference count on the group_info struct it points to may be changed;
3. the reference count on the security data it points to may be changed;
4. the reference count on any keyrings it points to may be changed;
5. any keyrings it points to may be revoked, expired or have their security
attributes changed; and
6. the contents of any keyrings to which it points may be changed (the whole
point of keyrings being a shared set of credentials, modifiable by anyone
with appropriate access).
To alter anything in the cred struct, the copy-and-replace principle must be
adhered to. First take a copy, then alter the copy and then use RCU to change
the task pointer to make it point to the new copy. There are wrappers to aid
with this (see below).
A task may only alter its _own_ credentials; it is no longer permitted for a
task to alter another's credentials. This means the ``capset()`` system call
is no longer permitted to take any PID other than the one of the current
process. Also ``keyctl_instantiate()`` and ``keyctl_negate()`` functions no
longer permit attachment to process-specific keyrings in the requesting
process as the instantiating process may need to create them.
Immutable Credentials
---------------------
Once a set of credentials has been made public (by calling ``commit_creds()``
for example), it must be considered immutable, barring two exceptions:
1. The reference count may be altered.
2. Whilst the keyring subscriptions of a set of credentials may not be
changed, the keyrings subscribed to may have their contents altered.
To catch accidental credential alteration at compile time, struct task_struct
has _const_ pointers to its credential sets, as does struct file. Furthermore,
certain functions such as ``get_cred()`` and ``put_cred()`` operate on const
pointers, thus rendering casts unnecessary, but require to temporarily ditch
the const qualification to be able to alter the reference count.
Accessing Task Credentials
--------------------------
A task being able to alter only its own credentials permits the current process
to read or replace its own credentials without the need for any form of locking
-- which simplifies things greatly. It can just call::
const struct cred *current_cred()
to get a pointer to its credentials structure, and it doesn't have to release
it afterwards.
There are convenience wrappers for retrieving specific aspects of a task's
credentials (the value is simply returned in each case)::
uid_t current_uid(void) Current's real UID
gid_t current_gid(void) Current's real GID
uid_t current_euid(void) Current's effective UID
gid_t current_egid(void) Current's effective GID
uid_t current_fsuid(void) Current's file access UID
gid_t current_fsgid(void) Current's file access GID
kernel_cap_t current_cap(void) Current's effective capabilities
void *current_security(void) Current's LSM security pointer
struct user_struct *current_user(void) Current's user account
There are also convenience wrappers for retrieving specific associated pairs of
a task's credentials::
void current_uid_gid(uid_t *, gid_t *);
void current_euid_egid(uid_t *, gid_t *);
void current_fsuid_fsgid(uid_t *, gid_t *);
which return these pairs of values through their arguments after retrieving
them from the current task's credentials.
In addition, there is a function for obtaining a reference on the current
process's current set of credentials::
const struct cred *get_current_cred(void);
and functions for getting references to one of the credentials that don't
actually live in struct cred::
struct user_struct *get_current_user(void);
struct group_info *get_current_groups(void);
which get references to the current process's user accounting structure and
supplementary groups list respectively.
Once a reference has been obtained, it must be released with ``put_cred()``,
``free_uid()`` or ``put_group_info()`` as appropriate.
Accessing Another Task's Credentials
------------------------------------
Whilst a task may access its own credentials without the need for locking, the
same is not true of a task wanting to access another task's credentials. It
must use the RCU read lock and ``rcu_dereference()``.
The ``rcu_dereference()`` is wrapped by::
const struct cred *__task_cred(struct task_struct *task);
This should be used inside the RCU read lock, as in the following example::
void foo(struct task_struct *t, struct foo_data *f)
{
const struct cred *tcred;
...
rcu_read_lock();
tcred = __task_cred(t);
f->uid = tcred->uid;
f->gid = tcred->gid;
f->groups = get_group_info(tcred->groups);
rcu_read_unlock();
...
}
Should it be necessary to hold another task's credentials for a long period of
time, and possibly to sleep whilst doing so, then the caller should get a
reference on them using::
const struct cred *get_task_cred(struct task_struct *task);
This does all the RCU magic inside of it. The caller must call put_cred() on
the credentials so obtained when they're finished with.
.. note::
The result of ``__task_cred()`` should not be passed directly to
``get_cred()`` as this may race with ``commit_cred()``.
There are a couple of convenience functions to access bits of another task's
credentials, hiding the RCU magic from the caller::
uid_t task_uid(task) Task's real UID
uid_t task_euid(task) Task's effective UID
If the caller is holding the RCU read lock at the time anyway, then::
__task_cred(task)->uid
__task_cred(task)->euid
should be used instead. Similarly, if multiple aspects of a task's credentials
need to be accessed, RCU read lock should be used, ``__task_cred()`` called,
the result stored in a temporary pointer and then the credential aspects called
from that before dropping the lock. This prevents the potentially expensive
RCU magic from being invoked multiple times.
Should some other single aspect of another task's credentials need to be
accessed, then this can be used::
task_cred_xxx(task, member)
where 'member' is a non-pointer member of the cred struct. For instance::
uid_t task_cred_xxx(task, suid);
will retrieve 'struct cred::suid' from the task, doing the appropriate RCU
magic. This may not be used for pointer members as what they point to may
disappear the moment the RCU read lock is dropped.
Altering Credentials
--------------------
As previously mentioned, a task may only alter its own credentials, and may not
alter those of another task. This means that it doesn't need to use any
locking to alter its own credentials.
To alter the current process's credentials, a function should first prepare a
new set of credentials by calling::
struct cred *prepare_creds(void);
this locks current->cred_replace_mutex and then allocates and constructs a
duplicate of the current process's credentials, returning with the mutex still
held if successful. It returns NULL if not successful (out of memory).
The mutex prevents ``ptrace()`` from altering the ptrace state of a process
whilst security checks on credentials construction and changing is taking place
as the ptrace state may alter the outcome, particularly in the case of
``execve()``.
The new credentials set should be altered appropriately, and any security
checks and hooks done. Both the current and the proposed sets of credentials
are available for this purpose as current_cred() will return the current set
still at this point.
When replacing the group list, the new list must be sorted before it
is added to the credential, as a binary search is used to test for
membership. In practice, this means :c:func:`groups_sort` should be
called before :c:func:`set_groups` or :c:func:`set_current_groups`.
:c:func:`groups_sort)` must not be called on a ``struct group_list`` which
is shared as it may permute elements as part of the sorting process
even if the array is already sorted.
When the credential set is ready, it should be committed to the current process
by calling::
int commit_creds(struct cred *new);
This will alter various aspects of the credentials and the process, giving the
LSM a chance to do likewise, then it will use ``rcu_assign_pointer()`` to
actually commit the new credentials to ``current->cred``, it will release
``current->cred_replace_mutex`` to allow ``ptrace()`` to take place, and it
will notify the scheduler and others of the changes.
This function is guaranteed to return 0, so that it can be tail-called at the
end of such functions as ``sys_setresuid()``.
Note that this function consumes the caller's reference to the new credentials.
The caller should _not_ call ``put_cred()`` on the new credentials afterwards.
Furthermore, once this function has been called on a new set of credentials,
those credentials may _not_ be changed further.
Should the security checks fail or some other error occur after
``prepare_creds()`` has been called, then the following function should be
invoked::
void abort_creds(struct cred *new);
This releases the lock on ``current->cred_replace_mutex`` that
``prepare_creds()`` got and then releases the new credentials.
A typical credentials alteration function would look something like this::
int alter_suid(uid_t suid)
{
struct cred *new;
int ret;
new = prepare_creds();
if (!new)
return -ENOMEM;
new->suid = suid;
ret = security_alter_suid(new);
if (ret < 0) {
abort_creds(new);
return ret;
}
return commit_creds(new);
}
Managing Credentials
--------------------
There are some functions to help manage credentials:
- ``void put_cred(const struct cred *cred);``
This releases a reference to the given set of credentials. If the
reference count reaches zero, the credentials will be scheduled for
destruction by the RCU system.
- ``const struct cred *get_cred(const struct cred *cred);``
This gets a reference on a live set of credentials, returning a pointer to
that set of credentials.
- ``struct cred *get_new_cred(struct cred *cred);``
This gets a reference on a set of credentials that is under construction
and is thus still mutable, returning a pointer to that set of credentials.
Open File Credentials
=====================
When a new file is opened, a reference is obtained on the opening task's
credentials and this is attached to the file struct as ``f_cred`` in place of
``f_uid`` and ``f_gid``. Code that used to access ``file->f_uid`` and
``file->f_gid`` should now access ``file->f_cred->fsuid`` and
``file->f_cred->fsgid``.
It is safe to access ``f_cred`` without the use of RCU or locking because the
pointer will not change over the lifetime of the file struct, and nor will the
contents of the cred struct pointed to, barring the exceptions listed above
(see the Task Credentials section).
Overriding the VFS's Use of Credentials
=======================================
Under some circumstances it is desirable to override the credentials used by
the VFS, and that can be done by calling into such as ``vfs_mkdir()`` with a
different set of credentials. This is done in the following places:
* ``sys_faccessat()``.
* ``do_coredump()``.
* nfs4recover.c.
+15
View File
@@ -0,0 +1,15 @@
======================
Security Documentation
======================
.. toctree::
:maxdepth: 1
credentials
IMA-templates
keys/index
LSM
LSM-sctp
SELinux-sctp
self-protection
tpm/index
File diff suppressed because it is too large. Load diff
+73
View File
@@ -0,0 +1,73 @@
==========================================
Encrypted keys for the eCryptfs filesystem
==========================================
ECryptfs is a stacked filesystem which transparently encrypts and decrypts each
file using a randomly generated File Encryption Key (FEK).
Each FEK is in turn encrypted with a File Encryption Key Encryption Key (FEFEK)
either in kernel space or in user space with a daemon called 'ecryptfsd'. In
the former case the operation is performed directly by the kernel CryptoAPI
using a key, the FEFEK, derived from a user prompted passphrase; in the latter
the FEK is encrypted by 'ecryptfsd' with the help of external libraries in order
to support other mechanisms like public key cryptography, PKCS#11 and TPM based
operations.
The data structure defined by eCryptfs to contain information required for the
FEK decryption is called authentication token and, currently, can be stored in a
kernel key of the 'user' type, inserted in the user's session specific keyring
by the userspace utility 'mount.ecryptfs' shipped with the package
'ecryptfs-utils'.
The 'encrypted' key type has been extended with the introduction of the new
format 'ecryptfs' in order to be used in conjunction with the eCryptfs
filesystem. Encrypted keys of the newly introduced format store an
authentication token in its payload with a FEFEK randomly generated by the
kernel and protected by the parent master key.
In order to avoid known-plaintext attacks, the datablob obtained through
commands 'keyctl print' or 'keyctl pipe' does not contain the overall
authentication token, which content is well known, but only the FEFEK in
encrypted form.
The eCryptfs filesystem may really benefit from using encrypted keys in that the
required key can be securely generated by an Administrator and provided at boot
time after the unsealing of a 'trusted' key in order to perform the mount in a
controlled environment. Another advantage is that the key is not exposed to
threats of malicious software, because it is available in clear form only at
kernel level.
Usage::
keyctl add encrypted name "new ecryptfs key-type:master-key-name keylen" ring
keyctl add encrypted name "load hex_blob" ring
keyctl update keyid "update key-type:master-key-name"
Where::
name:= '<16 hexadecimal characters>'
key-type:= 'trusted' | 'user'
keylen:= 64
Example of encrypted key usage with the eCryptfs filesystem:
Create an encrypted key "1000100010001000" of length 64 bytes with format
'ecryptfs' and save it using a previously loaded user key "test"::
$ keyctl add encrypted 1000100010001000 "new ecryptfs user:test 64" @u
19184530
$ keyctl print 19184530
ecryptfs user:test 64 490045d4bfe48c99f0d465fbbbb79e7500da954178e2de0697
dd85091f5450a0511219e9f7cd70dcd498038181466f78ac8d4c19504fcc72402bfc41c2
f253a41b7507ccaa4b2b03fff19a69d1cc0b16e71746473f023a95488b6edfd86f7fdd40
9d292e4bacded1258880122dd553a661
$ keyctl pipe 19184530 > ecryptfs.blob
Mount an eCryptfs filesystem using the created encrypted key "1000100010001000"
into the '/secret' directory::
$ mount -i -t ecryptfs -oecryptfs_sig=1000100010001000,\
ecryptfs_cipher=aes,ecryptfs_key_bytes=32 /secret /secret
+11
View File
@@ -0,0 +1,11 @@
===========
Kernel Keys
===========
.. toctree::
:maxdepth: 1
core
ecryptfs
request-key
trusted-encrypted
+199
View File
@@ -0,0 +1,199 @@
===================
Key Request Service
===================
The key request service is part of the key retention service (refer to
Documentation/security/keys/core.rst). This document explains more fully how
the requesting algorithm works.
The process starts by either the kernel requesting a service by calling
``request_key*()``::
struct key *request_key(const struct key_type *type,
const char *description,
const char *callout_info);
or::
struct key *request_key_with_auxdata(const struct key_type *type,
const char *description,
const char *callout_info,
size_t callout_len,
void *aux);
or::
struct key *request_key_async(const struct key_type *type,
const char *description,
const char *callout_info,
size_t callout_len);
or::
struct key *request_key_async_with_auxdata(const struct key_type *type,
const char *description,
const char *callout_info,
size_t callout_len,
void *aux);
Or by userspace invoking the request_key system call::
key_serial_t request_key(const char *type,
const char *description,
const char *callout_info,
key_serial_t dest_keyring);
The main difference between the access points is that the in-kernel interface
does not need to link the key to a keyring to prevent it from being immediately
destroyed. The kernel interface returns a pointer directly to the key, and
it's up to the caller to destroy the key.
The request_key*_with_auxdata() calls are like the in-kernel request_key*()
calls, except that they permit auxiliary data to be passed to the upcaller (the
default is NULL). This is only useful for those key types that define their
own upcall mechanism rather than using /sbin/request-key.
The two async in-kernel calls may return keys that are still in the process of
being constructed. The two non-async ones will wait for construction to
complete first.
The userspace interface links the key to a keyring associated with the process
to prevent the key from going away, and returns the serial number of the key to
the caller.
The following example assumes that the key types involved don't define their
own upcall mechanisms. If they do, then those should be substituted for the
forking and execution of /sbin/request-key.
The Process
===========
A request proceeds in the following manner:
1) Process A calls request_key() [the userspace syscall calls the kernel
interface].
2) request_key() searches the process's subscribed keyrings to see if there's
a suitable key there. If there is, it returns the key. If there isn't,
and callout_info is not set, an error is returned. Otherwise the process
proceeds to the next step.
3) request_key() sees that A doesn't have the desired key yet, so it creates
two things:
a) An uninstantiated key U of requested type and description.
b) An authorisation key V that refers to key U and notes that process A
is the context in which key U should be instantiated and secured, and
from which associated key requests may be satisfied.
4) request_key() then forks and executes /sbin/request-key with a new session
keyring that contains a link to auth key V.
5) /sbin/request-key assumes the authority associated with key U.
6) /sbin/request-key execs an appropriate program to perform the actual
instantiation.
7) The program may want to access another key from A's context (say a
Kerberos TGT key). It just requests the appropriate key, and the keyring
search notes that the session keyring has auth key V in its bottom level.
This will permit it to then search the keyrings of process A with the
UID, GID, groups and security info of process A as if it was process A,
and come up with key W.
8) The program then does what it must to get the data with which to
instantiate key U, using key W as a reference (perhaps it contacts a
Kerberos server using the TGT) and then instantiates key U.
9) Upon instantiating key U, auth key V is automatically revoked so that it
may not be used again.
10) The program then exits 0 and request_key() deletes key V and returns key
U to the caller.
This also extends further. If key W (step 7 above) didn't exist, key W would
be created uninstantiated, another auth key (X) would be created (as per step
3) and another copy of /sbin/request-key spawned (as per step 4); but the
context specified by auth key X will still be process A, as it was in auth key
V.
This is because process A's keyrings can't simply be attached to
/sbin/request-key at the appropriate places because (a) execve will discard two
of them, and (b) it requires the same UID/GID/Groups all the way through.
Negative Instantiation And Rejection
====================================
Rather than instantiating a key, it is possible for the possessor of an
authorisation key to negatively instantiate a key that's under construction.
This is a short duration placeholder that causes any attempt at re-requesting
the key whilst it exists to fail with error ENOKEY if negated or the specified
error if rejected.
This is provided to prevent excessive repeated spawning of /sbin/request-key
processes for a key that will never be obtainable.
Should the /sbin/request-key process exit anything other than 0 or die on a
signal, the key under construction will be automatically negatively
instantiated for a short amount of time.
The Search Algorithm
====================
A search of any particular keyring proceeds in the following fashion:
1) When the key management code searches for a key (keyring_search_aux) it
firstly calls key_permission(SEARCH) on the keyring it's starting with,
if this denies permission, it doesn't search further.
2) It considers all the non-keyring keys within that keyring and, if any key
matches the criteria specified, calls key_permission(SEARCH) on it to see
if the key is allowed to be found. If it is, that key is returned; if
not, the search continues, and the error code is retained if of higher
priority than the one currently set.
3) It then considers all the keyring-type keys in the keyring it's currently
searching. It calls key_permission(SEARCH) on each keyring, and if this
grants permission, it recurses, executing steps (2) and (3) on that
keyring.
The process stops immediately a valid key is found with permission granted to
use it. Any error from a previous match attempt is discarded and the key is
returned.
When search_process_keyrings() is invoked, it performs the following searches
until one succeeds:
1) If extant, the process's thread keyring is searched.
2) If extant, the process's process keyring is searched.
3) The process's session keyring is searched.
4) If the process has assumed the authority associated with a request_key()
authorisation key then:
a) If extant, the calling process's thread keyring is searched.
b) If extant, the calling process's process keyring is searched.
c) The calling process's session keyring is searched.
The moment one succeeds, all pending errors are discarded and the found key is
returned.
Only if all these fail does the whole thing fail with the highest priority
error. Note that several errors may have come from LSM.
The error priority is::
EKEYREVOKED > EKEYEXPIRED > ENOKEY
EACCES/EPERM are only returned on a direct search of a specific keyring where
the basal keyring does not grant Search permission.
@@ -0,0 +1,175 @@
==========================
Trusted and Encrypted Keys
==========================
Trusted and Encrypted Keys are two new key types added to the existing kernel
key ring service. Both of these new types are variable length symmetric keys,
and in both cases all keys are created in the kernel, and user space sees,
stores, and loads only encrypted blobs. Trusted Keys require the availability
of a Trusted Platform Module (TPM) chip for greater security, while Encrypted
Keys can be used on any system. All user level blobs, are displayed and loaded
in hex ascii for convenience, and are integrity verified.
Trusted Keys use a TPM both to generate and to seal the keys. Keys are sealed
under a 2048 bit RSA key in the TPM, and optionally sealed to specified PCR
(integrity measurement) values, and only unsealed by the TPM, if PCRs and blob
integrity verifications match. A loaded Trusted Key can be updated with new
(future) PCR values, so keys are easily migrated to new pcr values, such as
when the kernel and initramfs are updated. The same key can have many saved
blobs under different PCR values, so multiple boots are easily supported.
By default, trusted keys are sealed under the SRK, which has the default
authorization value (20 zeros). This can be set at takeownership time with the
trouser's utility: "tpm_takeownership -u -z".
Usage::
keyctl add trusted name "new keylen [options]" ring
keyctl add trusted name "load hex_blob [pcrlock=pcrnum]" ring
keyctl update key "update [options]"
keyctl print keyid
options:
keyhandle= ascii hex value of sealing key default 0x40000000 (SRK)
keyauth= ascii hex auth for sealing key default 0x00...i
(40 ascii zeros)
blobauth= ascii hex auth for sealed data default 0x00...
(40 ascii zeros)
pcrinfo= ascii hex of PCR_INFO or PCR_INFO_LONG (no default)
pcrlock= pcr number to be extended to "lock" blob
migratable= 0|1 indicating permission to reseal to new PCR values,
default 1 (resealing allowed)
hash= hash algorithm name as a string. For TPM 1.x the only
allowed value is sha1. For TPM 2.x the allowed values
are sha1, sha256, sha384, sha512 and sm3-256.
policydigest= digest for the authorization policy. must be calculated
with the same hash algorithm as specified by the 'hash='
option.
policyhandle= handle to an authorization policy session that defines the
same policy and with the same hash algorithm as was used to
seal the key.
"keyctl print" returns an ascii hex copy of the sealed key, which is in standard
TPM_STORED_DATA format. The key length for new keys are always in bytes.
Trusted Keys can be 32 - 128 bytes (256 - 1024 bits), the upper limit is to fit
within the 2048 bit SRK (RSA) keylength, with all necessary structure/padding.
Encrypted keys do not depend on a TPM, and are faster, as they use AES for
encryption/decryption. New keys are created from kernel generated random
numbers, and are encrypted/decrypted using a specified 'master' key. The
'master' key can either be a trusted-key or user-key type. The main
disadvantage of encrypted keys is that if they are not rooted in a trusted key,
they are only as secure as the user key encrypting them. The master user key
should therefore be loaded in as secure a way as possible, preferably early in
boot.
The decrypted portion of encrypted keys can contain either a simple symmetric
key or a more complex structure. The format of the more complex structure is
application specific, which is identified by 'format'.
Usage::
keyctl add encrypted name "new [format] key-type:master-key-name keylen"
ring
keyctl add encrypted name "load hex_blob" ring
keyctl update keyid "update key-type:master-key-name"
Where::
format:= 'default | ecryptfs'
key-type:= 'trusted' | 'user'
Examples of trusted and encrypted key usage:
Create and save a trusted key named "kmk" of length 32 bytes::
$ keyctl add trusted kmk "new 32" @u
440502848
$ keyctl show
Session Keyring
-3 --alswrv 500 500 keyring: _ses
97833714 --alswrv 500 -1 \_ keyring: _uid.500
440502848 --alswrv 500 500 \_ trusted: kmk
$ keyctl print 440502848
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba
$ keyctl pipe 440502848 > kmk.blob
Load a trusted key from the saved blob::
$ keyctl add trusted kmk "load `cat kmk.blob`" @u
268728824
$ keyctl print 268728824
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba
Reseal a trusted key under new pcr values::
$ keyctl update 268728824 "update pcrinfo=`cat pcr.blob`"
$ keyctl print 268728824
010100000000002c0002800093c35a09b70fff26e7a98ae786c641e678ec6ffb6b46d805
77c8a6377aed9d3219c6dfec4b23ffe3000001005d37d472ac8a44023fbb3d18583a4f73
d3a076c0858f6f1dcaa39ea0f119911ff03f5406df4f7f27f41da8d7194f45c9f4e00f2e
df449f266253aa3f52e55c53de147773e00f0f9aca86c64d94c95382265968c354c5eab4
9638c5ae99c89de1e0997242edfb0b501744e11ff9762dfd951cffd93227cc513384e7e6
e782c29435c7ec2edafaa2f4c1fe6e7a781b59549ff5296371b42133777dcc5b8b971610
94bc67ede19e43ddb9dc2baacad374a36feaf0314d700af0a65c164b7082401740e489c9
7ef6a24defe4846104209bf0c3eced7fa1a672ed5b125fc9d8cd88b476a658a4434644ef
df8ae9a178e9f83ba9f08d10fa47e4226b98b0702f06b3b8
The initial consumer of trusted keys is EVM, which at boot time needs a high
quality symmetric key for HMAC protection of file metadata. The use of a
trusted key provides strong guarantees that the EVM key has not been
compromised by a user level problem, and when sealed to specific boot PCR
values, protects against boot and offline attacks. Create and save an
encrypted key "evm" using the above trusted key "kmk":
option 1: omitting 'format'::
$ keyctl add encrypted evm "new trusted:kmk 32" @u
159771175
option 2: explicitly defining 'format' as 'default'::
$ keyctl add encrypted evm "new default trusted:kmk 32" @u
159771175
$ keyctl print 159771175
default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
24717c64 5972dcb82ab2dde83376d82b2e3c09ffc
$ keyctl pipe 159771175 > evm.blob
Load an encrypted key "evm" from saved blob::
$ keyctl add encrypted evm "load `cat evm.blob`" @u
831684262
$ keyctl print 831684262
default trusted:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b3
82dbbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0
24717c64 5972dcb82ab2dde83376d82b2e3c09ffc
Other uses for trusted and encrypted keys, such as for disk and file encryption
are anticipated. In particular the new format 'ecryptfs' has been defined in
in order to use encrypted keys to mount an eCryptfs filesystem. More details
about the usage can be found in the file
``Documentation/security/keys/ecryptfs.rst``.
+317
View File
@@ -0,0 +1,317 @@
======================
Kernel Self-Protection
======================
Kernel self-protection is the design and implementation of systems and
structures within the Linux kernel to protect against security flaws in
the kernel itself. This covers a wide range of issues, including removing
entire classes of bugs, blocking security flaw exploitation methods,
and actively detecting attack attempts. Not all topics are explored in
this document, but it should serve as a reasonable starting point and
answer any frequently asked questions. (Patches welcome, of course!)
In the worst-case scenario, we assume an unprivileged local attacker
has arbitrary read and write access to the kernel's memory. In many
cases, bugs being exploited will not provide this level of access,
but with systems in place that defend against the worst case we'll
cover the more limited cases as well. A higher bar, and one that should
still be kept in mind, is protecting the kernel against a _privileged_
local attacker, since the root user has access to a vastly increased
attack surface. (Especially when they have the ability to load arbitrary
kernel modules.)
The goals for successful self-protection systems would be that they
are effective, on by default, require no opt-in by developers, have no
performance impact, do not impede kernel debugging, and have tests. It
is uncommon that all these goals can be met, but it is worth explicitly
mentioning them, since these aspects need to be explored, dealt with,
and/or accepted.
Attack Surface Reduction
========================
The most fundamental defense against security exploits is to reduce the
areas of the kernel that can be used to redirect execution. This ranges
from limiting the exposed APIs available to userspace, making in-kernel
APIs hard to use incorrectly, minimizing the areas of writable kernel
memory, etc.
Strict kernel memory permissions
--------------------------------
When all of kernel memory is writable, it becomes trivial for attacks
to redirect execution flow. To reduce the availability of these targets
the kernel needs to protect its memory with a tight set of permissions.
Executable code and read-only data must not be writable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Any areas of the kernel with executable memory must not be writable.
While this obviously includes the kernel text itself, we must consider
all additional places too: kernel modules, JIT memory, etc. (There are
temporary exceptions to this rule to support things like instruction
alternatives, breakpoints, kprobes, etc. If these must exist in a
kernel, they are implemented in a way where the memory is temporarily
made writable during the update, and then returned to the original
permissions.)
In support of this are ``CONFIG_STRICT_KERNEL_RWX`` and
``CONFIG_STRICT_MODULE_RWX``, which seek to make sure that code is not
writable, data is not executable, and read-only data is neither writable
nor executable.
Most architectures have these options on by default and not user selectable.
For some architectures like arm that wish to have these be selectable,
the architecture Kconfig can select ARCH_OPTIONAL_KERNEL_RWX to enable
a Kconfig prompt. ``CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT`` determines
the default setting when ARCH_OPTIONAL_KERNEL_RWX is enabled.
Function pointers and sensitive variables must not be writable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vast areas of kernel memory contain function pointers that are looked
up by the kernel and used to continue execution (e.g. descriptor/vector
tables, file/network/etc operation structures, etc). The number of these
variables must be reduced to an absolute minimum.
Many such variables can be made read-only by setting them "const"
so that they live in the .rodata section instead of the .data section
of the kernel, gaining the protection of the kernel's strict memory
permissions as described above.
For variables that are initialized once at ``__init`` time, these can
be marked with the (new and under development) ``__ro_after_init``
attribute.
What remains are variables that are updated rarely (e.g. GDT). These
will need another infrastructure (similar to the temporary exceptions
made to kernel code mentioned above) that allow them to spend the rest
of their lifetime read-only. (For example, when being updated, only the
CPU thread performing the update would be given uninterruptible write
access to the memory.)
Segregation of kernel memory from userspace memory
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The kernel must never execute userspace memory. The kernel must also never
access userspace memory without explicit expectation to do so. These
rules can be enforced either by support of hardware-based restrictions
(x86's SMEP/SMAP, ARM's PXN/PAN) or via emulation (ARM's Memory Domains).
By blocking userspace memory in this way, execution and data parsing
cannot be passed to trivially-controlled userspace memory, forcing
attacks to operate entirely in kernel memory.
Reduced access to syscalls
--------------------------
One trivial way to eliminate many syscalls for 64-bit systems is building
without ``CONFIG_COMPAT``. However, this is rarely a feasible scenario.
The "seccomp" system provides an opt-in feature made available to
userspace, which provides a way to reduce the number of kernel entry
points available to a running process. This limits the breadth of kernel
code that can be reached, possibly reducing the availability of a given
bug to an attack.
An area of improvement would be creating viable ways to keep access to
things like compat, user namespaces, BPF creation, and perf limited only
to trusted processes. This would keep the scope of kernel entry points
restricted to the more regular set of normally available to unprivileged
userspace.
Restricting access to kernel modules
------------------------------------
The kernel should never allow an unprivileged user the ability to
load specific kernel modules, since that would provide a facility to
unexpectedly extend the available attack surface. (The on-demand loading
of modules via their predefined subsystems, e.g. MODULE_ALIAS_*, is
considered "expected" here, though additional consideration should be
given even to these.) For example, loading a filesystem module via an
unprivileged socket API is nonsense: only the root or physically local
user should trigger filesystem module loading. (And even this can be up
for debate in some scenarios.)
To protect against even privileged users, systems may need to either
disable module loading entirely (e.g. monolithic kernel builds or
modules_disabled sysctl), or provide signed modules (e.g.
``CONFIG_MODULE_SIG_FORCE``, or dm-crypt with LoadPin), to keep from having
root load arbitrary kernel code via the module loader interface.
Memory integrity
================
There are many memory structures in the kernel that are regularly abused
to gain execution control during an attack, By far the most commonly
understood is that of the stack buffer overflow in which the return
address stored on the stack is overwritten. Many other examples of this
kind of attack exist, and protections exist to defend against them.
Stack buffer overflow
---------------------
The classic stack buffer overflow involves writing past the expected end
of a variable stored on the stack, ultimately writing a controlled value
to the stack frame's stored return address. The most widely used defense
is the presence of a stack canary between the stack variables and the
return address (``CONFIG_STACKPROTECTOR``), which is verified just before
the function returns. Other defenses include things like shadow stacks.
Stack depth overflow
--------------------
A less well understood attack is using a bug that triggers the
kernel to consume stack memory with deep function calls or large stack
allocations. With this attack it is possible to write beyond the end of
the kernel's preallocated stack space and into sensitive structures. Two
important changes need to be made for better protections: moving the
sensitive thread_info structure elsewhere, and adding a faulting memory
hole at the bottom of the stack to catch these overflows.
Heap memory integrity
---------------------
The structures used to track heap free lists can be sanity-checked during
allocation and freeing to make sure they aren't being used to manipulate
other memory areas.
Counter integrity
-----------------
Many places in the kernel use atomic counters to track object references
or perform similar lifetime management. When these counters can be made
to wrap (over or under) this traditionally exposes a use-after-free
flaw. By trapping atomic wrapping, this class of bug vanishes.
Size calculation overflow detection
-----------------------------------
Similar to counter overflow, integer overflows (usually size calculations)
need to be detected at runtime to kill this class of bug, which
traditionally leads to being able to write past the end of kernel buffers.
Probabilistic defenses
======================
While many protections can be considered deterministic (e.g. read-only
memory cannot be written to), some protections provide only statistical
defense, in that an attack must gather enough information about a
running system to overcome the defense. While not perfect, these do
provide meaningful defenses.
Canaries, blinding, and other secrets
-------------------------------------
It should be noted that things like the stack canary discussed earlier
are technically statistical defenses, since they rely on a secret value,
and such values may become discoverable through an information exposure
flaw.
Blinding literal values for things like JITs, where the executable
contents may be partially under the control of userspace, need a similar
secret value.
It is critical that the secret values used must be separate (e.g.
different canary per stack) and high entropy (e.g. is the RNG actually
working?) in order to maximize their success.
Kernel Address Space Layout Randomization (KASLR)
-------------------------------------------------
Since the location of kernel memory is almost always instrumental in
mounting a successful attack, making the location non-deterministic
raises the difficulty of an exploit. (Note that this in turn makes
the value of information exposures higher, since they may be used to
discover desired memory locations.)
Text and module base
~~~~~~~~~~~~~~~~~~~~
By relocating the physical and virtual base address of the kernel at
boot-time (``CONFIG_RANDOMIZE_BASE``), attacks needing kernel code will be
frustrated. Additionally, offsetting the module loading base address
means that even systems that load the same set of modules in the same
order every boot will not share a common base address with the rest of
the kernel text.
Stack base
~~~~~~~~~~
If the base address of the kernel stack is not the same between processes,
or even not the same between syscalls, targets on or beyond the stack
become more difficult to locate.
Dynamic memory base
~~~~~~~~~~~~~~~~~~~
Much of the kernel's dynamic memory (e.g. kmalloc, vmalloc, etc) ends up
being relatively deterministic in layout due to the order of early-boot
initializations. If the base address of these areas is not the same
between boots, targeting them is frustrated, requiring an information
exposure specific to the region.
Structure layout
~~~~~~~~~~~~~~~~
By performing a per-build randomization of the layout of sensitive
structures, attacks must either be tuned to known kernel builds or expose
enough kernel memory to determine structure layouts before manipulating
them.
Preventing Information Exposures
================================
Since the locations of sensitive structures are the primary target for
attacks, it is important to defend against exposure of both kernel memory
addresses and kernel memory contents (since they may contain kernel
addresses or other sensitive things like canary values).
Kernel addresses
----------------
Printing kernel addresses to userspace leaks sensitive information about
the kernel memory layout. Care should be exercised when using any printk
specifier that prints the raw address, currently %px, %p[ad], (and %p[sSb]
in certain circumstances [*]). Any file written to using one of these
specifiers should be readable only by privileged processes.
Kernels 4.14 and older printed the raw address using %p. As of 4.15-rc1
addresses printed with the specifier %p are hashed before printing.
[*] If KALLSYMS is enabled and symbol lookup fails, the raw address is
printed. If KALLSYMS is not enabled the raw address is printed.
Unique identifiers
------------------
Kernel memory addresses must never be used as identifiers exposed to
userspace. Instead, use an atomic counter, an idr, or similar unique
identifier.
Memory initialization
---------------------
Memory copied to userspace must always be fully initialized. If not
explicitly memset(), this will require changes to the compiler to make
sure structure holes are cleared.
Memory poisoning
----------------
When releasing memory, it is best to poison the contents (clear stack on
syscall return, wipe heap memory on a free), to avoid reuse attacks that
rely on the old contents of memory. This frustrates many uninitialized
variable attacks, stack content exposures, heap content exposures, and
use-after-free attacks.
Destination tracking
--------------------
To help kill classes of bugs that result in kernel addresses being
written to userspace, the destination of writes needs to be tracked. If
the buffer is destined for userspace (e.g. seq_file backed ``/proc`` files),
it should automatically censor sensitive values.
+7
View File
@@ -0,0 +1,7 @@
=====================================
Trusted Platform Module documentation
=====================================
.. toctree::
tpm_vtpm_proxy
@@ -0,0 +1,50 @@
=============================================
Virtual TPM Proxy Driver for Linux Containers
=============================================
| Authors:
| Stefan Berger <stefanb@linux.vnet.ibm.com>
This document describes the virtual Trusted Platform Module (vTPM)
proxy device driver for Linux containers.
Introduction
============
The goal of this work is to provide TPM functionality to each Linux
container. This allows programs to interact with a TPM in a container
the same way they interact with a TPM on the physical system. Each
container gets its own unique, emulated, software TPM.
Design
======
To make an emulated software TPM available to each container, the container
management stack needs to create a device pair consisting of a client TPM
character device ``/dev/tpmX`` (with X=0,1,2...) and a 'server side' file
descriptor. The former is moved into the container by creating a character
device with the appropriate major and minor numbers while the file descriptor
is passed to the TPM emulator. Software inside the container can then send
TPM commands using the character device and the emulator will receive the
commands via the file descriptor and use it for sending back responses.
To support this, the virtual TPM proxy driver provides a device ``/dev/vtpmx``
that is used to create device pairs using an ioctl. The ioctl takes as
an input flags for configuring the device. The flags for example indicate
whether TPM 1.2 or TPM 2 functionality is supported by the TPM emulator.
The result of the ioctl are the file descriptor for the 'server side'
as well as the major and minor numbers of the character device that was created.
Besides that the number of the TPM character device is returned. If for
example ``/dev/tpm10`` was created, the number (``dev_num``) 10 is returned.
Once the device has been created, the driver will immediately try to talk
to the TPM. All commands from the driver can be read from the file descriptor
returned by the ioctl. The commands should be responded to immediately.
UAPI
====
.. kernel-doc:: include/uapi/linux/vtpm_proxy.h
.. kernel-doc:: drivers/char/tpm/tpm_vtpm_proxy.c
:functions: vtpmx_ioc_new_dev
+113
View File
@@ -0,0 +1,113 @@
Virtual TPM interface for Xen
Authors: Matthew Fioravante (JHUAPL), Daniel De Graaf (NSA)
This document describes the virtual Trusted Platform Module (vTPM) subsystem for
Xen. The reader is assumed to have familiarity with building and installing Xen,
Linux, and a basic understanding of the TPM and vTPM concepts.
INTRODUCTION
The goal of this work is to provide a TPM functionality to a virtual guest
operating system (in Xen terms, a DomU). This allows programs to interact with
a TPM in a virtual system the same way they interact with a TPM on the physical
system. Each guest gets its own unique, emulated, software TPM. However, each
of the vTPM's secrets (Keys, NVRAM, etc) are managed by a vTPM Manager domain,
which seals the secrets to the Physical TPM. If the process of creating each of
these domains (manager, vTPM, and guest) is trusted, the vTPM subsystem extends
the chain of trust rooted in the hardware TPM to virtual machines in Xen. Each
major component of vTPM is implemented as a separate domain, providing secure
separation guaranteed by the hypervisor. The vTPM domains are implemented in
mini-os to reduce memory and processor overhead.
This mini-os vTPM subsystem was built on top of the previous vTPM work done by
IBM and Intel corporation.
DESIGN OVERVIEW
---------------
The architecture of vTPM is described below:
+------------------+
| Linux DomU | ...
| | ^ |
| v | |
| xen-tpmfront |
+------------------+
| ^
v |
+------------------+
| mini-os/tpmback |
| | ^ |
| v | |
| vtpm-stubdom | ...
| | ^ |
| v | |
| mini-os/tpmfront |
+------------------+
| ^
v |
+------------------+
| mini-os/tpmback |
| | ^ |
| v | |
| vtpmmgr-stubdom |
| | ^ |
| v | |
| mini-os/tpm_tis |
+------------------+
| ^
v |
+------------------+
| Hardware TPM |
+------------------+
* Linux DomU: The Linux based guest that wants to use a vTPM. There may be
more than one of these.
* xen-tpmfront.ko: Linux kernel virtual TPM frontend driver. This driver
provides vTPM access to a Linux-based DomU.
* mini-os/tpmback: Mini-os TPM backend driver. The Linux frontend driver
connects to this backend driver to facilitate communications
between the Linux DomU and its vTPM. This driver is also
used by vtpmmgr-stubdom to communicate with vtpm-stubdom.
* vtpm-stubdom: A mini-os stub domain that implements a vTPM. There is a
one to one mapping between running vtpm-stubdom instances and
logical vtpms on the system. The vTPM Platform Configuration
Registers (PCRs) are normally all initialized to zero.
* mini-os/tpmfront: Mini-os TPM frontend driver. The vTPM mini-os domain
vtpm-stubdom uses this driver to communicate with
vtpmmgr-stubdom. This driver is also used in mini-os
domains such as pv-grub that talk to the vTPM domain.
* vtpmmgr-stubdom: A mini-os domain that implements the vTPM manager. There is
only one vTPM manager and it should be running during the
entire lifetime of the machine. This domain regulates
access to the physical TPM on the system and secures the
persistent state of each vTPM.
* mini-os/tpm_tis: Mini-os TPM version 1.2 TPM Interface Specification (TIS)
driver. This driver used by vtpmmgr-stubdom to talk directly to
the hardware TPM. Communication is facilitated by mapping
hardware memory pages into vtpmmgr-stubdom.
* Hardware TPM: The physical TPM that is soldered onto the motherboard.
INTEGRATION WITH XEN
--------------------
Support for the vTPM driver was added in Xen using the libxl toolstack in Xen
4.3. See the Xen documentation (docs/misc/vtpm.txt) for details on setting up
the vTPM and vTPM Manager stub domains. Once the stub domains are running, a
vTPM device is set up in the same manner as a disk or network device in the
domain's configuration file.
In order to use features such as IMA that require a TPM to be loaded prior to
the initrd, the xen-tpmfront driver must be compiled in to the kernel. If not
using such features, the driver can be compiled as a module and will be loaded
as usual.