Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,203 @@
.. SPDX-License-Identifier: GPL-2.0
==================================
IMA Measurements Export and Delete
==================================
Introduction
============
The IMA measurements list is currently stored in the kernel memory. Memory
occupation grows linearly with the number of records, and can become a
problem especially in environments with reduced resources.
While there is an advantage in keeping the IMA measurements list in kernel
memory, so that it is always available for reading from the securityfs
interfaces, storing it elsewhere would make it possible to free precious
memory for other kernel usage.
The IMA measurements list needs to be retained and safely stored for new
attestation servers to validate it. Assuming the IMA measurements list is
properly saved, storing it outside the kernel does not introduce security
issues, since its integrity is anyway protected by the TPM.
Hence, the new IMA staging mechanism is introduced to export IMA
measurements to user space and delete them from kernel space.
Staging consists in atomically moving the current measurements list to a
temporary list, so that measurements can be deleted afterwards. The staging
operation locks the hot path (racing with addition of new measurements) for
a very short time, only for swapping the list pointers. Deletion of the
measurements instead is done locklessly, away from the hot path.
There are two flavors of the staging mechanism. In the staging with prompt,
all current measurements are staged, read and deleted upon confirmation. In
the staging and deleting flavor, N measurements are staged from the
beginning of the current measurements list and immediately deleted without
confirmation.
Management of Staged Measurements
=================================
Since with the staging mechanism measurement records are removed from the
kernel, the staged measurements need to be saved in a storage and
concatenated together, so that they can be presented during remote
attestation as if staging was never done. This task can be accomplished by
a remote attestation agent modified to support staging, or a system
service.
Coordination is necessary in the case where there are multiple actors
requesting measurements to be staged.
In the staging with prompt case, the measurement interfaces can be accessed
only by one actor (writer) at a time, so the others will get an error until
the former closes it. Since the actors don't care about N, when they gain
access to the interface, they will get all the staged measurements at the
time of their request.
In the case of staging and deleting, coordination is more important, since
there is the risk that two actors unaware of each other compute the value N
on the current measurements list and request IMA to stage N twice.
Remote Attestation Agent Workflow
=================================
Remote attestation agents can be configured to always present all the
measurements to the remote verifiers or, alternatively, to only provide the
measurements that have not been verified yet by the remote verifiers.
In the latter case, determining which measurements need to be sent and
verified must solely depend on the remote verifier. The remote attestation
agent can proactively send partial measurements, at the condition that they
are the ones that the remote verifier needs.
An agent can rely on one of the supported staging methods to proactively
send to a remote verifier the measurements since the previous request up
to the ones that verify the TPM quote obtained in the current request.
The workflow with each staging method is the following.
With staging with prompt, the agent stages the current measurements list,
reads and stores the measurements in a storage and immediately requests
IMA to delete the staged measurements from kernel memory. Afterwards, it
calculates N by replaying the PCR extend on the stored measurements until
the calculated PCRs match the quoted PCRs. It then keeps the measurements
in excess for the next attestation request.
At the next attestation request, the agent performs the same steps above,
and concatenates the new measurements to the ones in excess from the
previous request. Also in this case, the agent replays the PCR extend until
it matches the currently quoted PCRs, keeps the measurements in excess and
presents the new N measurement records to the remote attestation server.
With the staging and deleting method, the agent reads the current
measurements list, calculates N and requests IMA to delete only those. The
measurements in excess are kept in the IMA measurements list and can be
retrieved at the next remote attestation request.
While keeping only the excess measurements in the storage could be
sufficient to serve the requests of a remote verifier, it is advised to
keep all the obtained measurements locally, as they might be needed for the
attestation with a different remote verifier.
Usage
=====
The IMA staging mechanism can be enabled from the kernel configuration with
the CONFIG_IMA_STAGING option. This option prevents inadvertently removing
the IMA measurement list on systems which do not properly save it.
If the option is enabled, IMA duplicates the current securityfs
measurements interfaces (both binary and ASCII), by adding the ``_staged``
file suffix. Both the original and the staging interfaces gain the write
permission for the root user and group, but require the process to have
CAP_SYS_ADMIN set.
The staging mechanism supports two flavors.
Staging with prompt
~~~~~~~~~~~~~~~~~~~
The current measurements list is moved to a temporary staging area,
allowing it to be saved to external storage, before being deleted upon
confirmation.
This staging process is achieved with the following steps.
1. ``echo A > <_staged interface>``: the user requests IMA to stage the
entire measurements list;
2. ``cat <_staged interface>``: the user reads the staged measurements;
3. ``echo D > <_staged interface>``: the user requests IMA to delete
staged measurements.
Staging and deleting
~~~~~~~~~~~~~~~~~~~~
N measurements are staged to a temporary staging area, and immediately
deleted without further confirmation.
This staging process is achieved with the following steps.
1. ``cat <original interface>``: the user reads the current measurements
list and determines what the value N for staging should be;
2. ``echo N > <original interface>``: the user requests IMA to delete N
measurements from the current measurements list.
Interface Access
================
In order to avoid the IMA measurements list being suddenly truncated by the
staging mechanism during a read, or having multiple concurrent staging, a
semaphore-like locking scheme has been implemented on all the measurements
list interfaces.
Multiple readers can access concurrently the original and staged
interfaces, and they can be in mutual exclusion with one writer. In order
to see the same state across all the measurement interfaces, the same
writer is allowed to open multiple interfaces for write or read/write.
If an illegal access occurs, the open to the measurements list interface is
denied.
Kexec
=====
In the event a kexec() system call occurs between staging and deleting, the
staged measurement records are marshalled before the current measurements
list, so that they are both available when the secondary kernel starts.
If measurement is suspended before requesting to delete staged or current
measurements, IMA returns an error to user space to let it know that
marshalling is already in progress, so that it does not save the
measurements twice.
IMA also disallows staging when suspending measurement, to avoid the
situation where neither measurements are carried over to the secondary
kernel, nor they are saved by user space to the storage.
Hash table
==========
By default, the template digest of staged measurement records are kept in
kernel memory (only template data are freed), to be able to detect
duplicate records independently of staging.
The new kernel option ``ima_flush_htable`` has been introduced to
explicitly request a complete deletion of the staged measurements, for
maximum kernel memory saving. If the option has been specified, duplicate
records are still avoided on records of the current measurements list,
but there can be duplicates between different groups of staged
measurements.
Flushing the hash table is supported only for the staging with prompt
flavor. For the staging and deleting flavor, it would have been necessary
to lock the hot path adding new measurements for the time needed to remove
each selected measurement individually.
@@ -0,0 +1,111 @@
=================================
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);
- 'd-ngv2': same as d-ng, but prefixed with the "ima" or "verity" digest type
(field format: <digest type>:<hash algo>:digest);
- 'd-modsig': the digest of the event without the appended modsig;
- 'n-ng': the name of the event, without size limitations;
- 'sig': the file signature, based on either the file's/fsverity's digest[1],
or the EVM portable signature, if 'security.ima' contains a file hash.
- 'modsig' the appended file signature;
- 'buf': the buffer data that was used to generate the hash without size limitations;
- 'evmsig': the EVM portable signature;
- 'iuid': the inode UID;
- 'igid': the inode GID;
- 'imode': the inode mode;
- 'xattrnames': a list of xattr names (separated by ``|``), only if the xattr is
present;
- 'xattrlengths': a list of xattr lengths (u32), only if the xattr is present;
- 'xattrvalues': a list of xattr values;
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-ngv2": its format is ``d-ngv2|n-ng``;
- "ima-sig": its format is ``d-ng|n-ng|sig``;
- "ima-sigv2": its format is ``d-ngv2|n-ng|sig``;
- "ima-buf": its format is ``d-ng|n-ng|buf``;
- "ima-modsig": its format is ``d-ng|n-ng|sig|d-modsig|modsig``;
- "evm-sig": its format is ``d-ng|n-ng|evmsig|xattrnames|xattrlengths|xattrvalues|iuid|igid|imode``;
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=``.
+344
View File
@@ -0,0 +1,344 @@
.. SPDX-License-Identifier: GPL-2.0
====
SCTP
====
SCTP LSM Support
================
Security Hooks
--------------
For security module support, three SCTP specific hooks have been implemented::
security_sctp_assoc_request()
security_sctp_bind_connect()
security_sctp_sk_clone()
security_sctp_assoc_established()
The usage of these hooks are described below with the SELinux implementation
described in the `SCTP SELinux Support`_ chapter.
security_sctp_assoc_request()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Passes the ``@asoc`` and ``@chunk->skb`` of the association INIT packet to the
security module. Returns 0 on success, error on failure.
::
@asoc - pointer to sctp association 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 association.
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).
::
@asoc - pointer to current sctp association structure.
@sk - pointer to current sock structure.
@newsk - pointer to new sock structure.
security_sctp_assoc_established()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Called when a COOKIE ACK is received, and the peer secid will be
saved into ``@asoc->peer_secid`` for client::
@asoc - pointer to sctp association 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_sctp_assoc_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 a temporary 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 ------------------------------------------>
sctp_sf_do_5_1D_ce()
Respond to an COOKIE ECHO chunk.
Confirm the cookie and create a
permanent association.
Call security_sctp_assoc_request() to
do the same as for INIT chunk Response.
<------------------------------------------- COOKIE ACK
| |
sctp_sf_do_5_1E_ca |
Call security_sctp_assoc_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 |
------------------------------------------------------------------
SCTP SELinux Support
====================
Security Hooks
--------------
The `SCTP LSM Support`_ chapter above 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_sctp_assoc_established()
security_sctp_assoc_request()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Passes the ``@asoc`` and ``@chunk->skb`` of the association INIT packet to the
security module. Returns 0 on success, error on failure.
::
@asoc - pointer to sctp association structure.
@skb - pointer to skbuff of association packet.
The security module performs the following operations:
IF this is the first association on ``@asoc->base.sk``, then set the peer
sid to that in ``@skb``. This will ensure there is only one peer sid
assigned to ``@asoc->base.sk`` that may support multiple associations.
ELSE validate the ``@asoc->base.sk peer_sid`` against the ``@skb peer sid``
to determine whether the association should be allowed or denied.
Set the sctp ``@asoc sid`` to socket's sid (from ``asoc->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 |
------------------------------------------------------------------
`SCTP LSM Support`_ 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 ``@asoc sid`` and
``@asoc peer sid`` respectively.
::
@asoc - pointer to current sctp association structure.
@sk - pointer to current sock structure.
@newsk - pointer to new sock structure.
security_sctp_assoc_established()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Called when a COOKIE ACK is received where it sets the connection's peer sid
to that in ``@skb``::
@asoc - pointer to sctp association 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: https://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.
@@ -0,0 +1,559 @@
====================
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 keyring
- 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. While 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
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
------------------------------------
While 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 while 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
while 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 groups_sort() should be
called before set_groups() or set_current_groups().
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.
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).
To avoid "confused deputy" privilege escalation attacks, access control checks
during subsequent operations on an opened file should use these credentials
instead of "current"'s credentials, as the file may have been passed to a more
privileged process.
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()``.
* ``vfs_coredump()``.
* nfs4recover.c.
@@ -0,0 +1,101 @@
==================================
Digital Signature Verification API
==================================
:Author: Dmitry Kasatkin
:Date: 06.10.2011
.. CONTENTS
1. Introduction
2. API
3. User-space utilities
Introduction
============
Digital signature verification API provides a method to verify digital signature.
Currently digital signatures are used by the IMA/EVM integrity protection subsystem.
Digital signature verification is implemented using cut-down kernel port of
GnuPG multi-precision integers (MPI) library. The kernel port provides
memory allocation errors handling, has been refactored according to kernel
coding style, and checkpatch.pl reported errors and warnings have been fixed.
Public key and signature consist of header and MPIs::
struct pubkey_hdr {
uint8_t version; /* key format version */
time_t timestamp; /* key made, always 0 for now */
uint8_t algo;
uint8_t nmpi;
char mpi[0];
} __packed;
struct signature_hdr {
uint8_t version; /* signature format version */
time_t timestamp; /* signature made */
uint8_t algo;
uint8_t hash;
uint8_t keyid[8];
uint8_t nmpi;
char mpi[0];
} __packed;
keyid equals to SHA1[12-19] over the total key content.
Signature header is used as an input to generate a signature.
Such approach insures that key or signature header could not be changed.
It protects timestamp from been changed and can be used for rollback
protection.
API
===
API currently includes only 1 function::
digsig_verify() - digital signature verification with public key
/**
* digsig_verify() - digital signature verification with public key
* @keyring: keyring to search key in
* @sig: digital signature
* @sigen: length of the signature
* @data: data
* @datalen: length of the data
* @return: 0 on success, -EINVAL otherwise
*
* Verifies data integrity against digital signature.
* Currently only RSA is supported.
* Normally hash of the content is used as a data for this function.
*
*/
int digsig_verify(struct key *keyring, const char *sig, int siglen,
const char *data, int datalen);
User-space utilities
====================
The signing and key management utilities evm-utils provide functionality
to generate signatures, to load keys into the kernel keyring.
Keys can be in PEM or converted to the kernel format.
When the key is added to the kernel keyring, the keyid defines the name
of the key: 5D2B05FC633EE3E8 in the example below.
Here is example output of the keyctl utility::
$ keyctl show
Session Keyring
-3 --alswrv 0 0 keyring: _ses
603976250 --alswrv 0 -1 \_ keyring: _uid.0
817777377 --alswrv 0 0 \_ user: kmk
891974900 --alswrv 0 0 \_ encrypted: evm-key
170323636 --alswrv 0 0 \_ keyring: _module
548221616 --alswrv 0 0 \_ keyring: _ima
128198054 --alswrv 0 0 \_ keyring: _evm
$ keyctl list 128198054
1 key in keyring:
620789745: --alswrv 0 0 user: 5D2B05FC633EE3E8
@@ -0,0 +1,23 @@
======================
Security Documentation
======================
.. toctree::
:maxdepth: 1
credentials
snp-tdx-threat-model
IMA-templates
IMA-export-delete
keys/index
lsm
lsm-development
sak
SCTP
self-protection
siphash
tpm/index
digsig
landlock
secrets/index
ipe
+446
View File
@@ -0,0 +1,446 @@
.. SPDX-License-Identifier: GPL-2.0
Integrity Policy Enforcement (IPE) - Kernel Documentation
=========================================================
.. NOTE::
This is documentation targeted at developers, instead of administrators.
If you're looking for documentation on the usage of IPE, please see
:doc:`IPE admin guide </admin-guide/LSM/ipe>`.
Historical Motivation
---------------------
The original issue that prompted IPE's implementation was the creation
of a locked-down system. This system would be born-secure, and have
strong integrity guarantees over both the executable code, and specific
*data files* on the system, that were critical to its function. These
specific data files would not be readable unless they passed integrity
policy. A mandatory access control system would be present, and
as a result, xattrs would have to be protected. This led to a selection
of what would provide the integrity claims. At the time, there were two
main mechanisms considered that could guarantee integrity for the system
with these requirements:
1. IMA + EVM Signatures
2. DM-Verity
Both options were carefully considered, however the choice to use DM-Verity
over IMA+EVM as the *integrity mechanism* in the original use case of IPE
was due to three main reasons:
1. Protection of additional attack vectors:
* With IMA+EVM, without an encryption solution, the system is vulnerable
to offline attack against the aforementioned specific data files.
Unlike executables, read operations (like those on the protected data
files), cannot be enforced to be globally integrity verified. This means
there must be some form of selector to determine whether a read should
enforce the integrity policy, or it should not.
At the time, this was done with mandatory access control labels. An IMA
policy would indicate what labels required integrity verification, which
presented an issue: EVM would protect the label, but if an attacker could
modify filesystem offline, the attacker could wipe all the xattrs -
including the SELinux labels that would be used to determine whether the
file should be subject to integrity policy.
With DM-Verity, as the xattrs are saved as part of the Merkel tree, if
offline mount occurs against the filesystem protected by dm-verity, the
checksum no longer matches and the file fails to be read.
* As userspace binaries are paged in Linux, dm-verity also offers the
additional protection against a hostile block device. In such an attack,
the block device reports the appropriate content for the IMA hash
initially, passing the required integrity check. Then, on the page fault
that accesses the real data, will report the attacker's payload. Since
dm-verity will check the data when the page fault occurs (and the disk
access), this attack is mitigated.
2. Performance:
* dm-verity provides integrity verification on demand as blocks are
read versus requiring the entire file being read into memory for
validation.
3. Simplicity of signing:
* No need for two signatures (IMA, then EVM): one signature covers
an entire block device.
* Signatures can be stored externally to the filesystem metadata.
* The signature supports an x.509-based signing infrastructure.
The next step was to choose a *policy* to enforce the integrity mechanism.
The minimum requirements for the policy were:
1. The policy itself must be integrity verified (preventing trivial
attack against it).
2. The policy itself must be resistant to rollback attacks.
3. The policy enforcement must have a permissive-like mode.
4. The policy must be able to be updated, in its entirety, without
a reboot.
5. Policy updates must be atomic.
6. The policy must support *revocations* of previously authored
components.
7. The policy must be auditable, at any point-of-time.
IMA, as the only integrity policy mechanism at the time, was
considered against these list of requirements, and did not fulfill
all of the minimum requirements. Extending IMA to cover these
requirements was considered, but ultimately discarded for a
two reasons:
1. Regression risk; many of these changes would result in
dramatic code changes to IMA, which is already present in the
kernel, and therefore might impact users.
2. IMA was used in the system for measurement and attestation;
separation of measurement policy from local integrity policy
enforcement was considered favorable.
Due to these reasons, it was decided that a new LSM should be created,
whose responsibility would be only the local integrity policy enforcement.
Role and Scope
--------------
IPE, as its name implies, is fundamentally an integrity policy enforcement
solution; IPE does not mandate how integrity is provided, but instead
leaves that decision to the system administrator to set the security bar,
via the mechanisms that they select that suit their individual needs.
There are several different integrity solutions that provide a different
level of security guarantees; and IPE allows sysadmins to express policy for
theoretically all of them.
IPE does not have an inherent mechanism to ensure integrity on its own.
Instead, there are more effective layers available for building systems that
can guarantee integrity. It's important to note that the mechanism for proving
integrity is independent of the policy for enforcing that integrity claim.
Therefore, IPE was designed around:
1. Easy integrations with integrity providers.
2. Ease of use for platform administrators/sysadmins.
Design Rationale:
-----------------
IPE was designed after evaluating existing integrity policy solutions
in other operating systems and environments. In this survey of other
implementations, there were a few pitfalls identified:
1. Policies were not readable by humans, usually requiring a binary
intermediary format.
2. A single, non-customizable action was implicitly taken as a default.
3. Debugging the policy required manual steps to determine what rule was violated.
4. Authoring a policy required an in-depth knowledge of the larger system,
or operating system.
IPE attempts to avoid all of these pitfalls.
Policy
~~~~~~
Plain Text
^^^^^^^^^^
IPE's policy is plain-text. This introduces slightly larger policy files than
other LSMs, but solves two major problems that occurs with some integrity policy
solutions on other platforms.
The first issue is one of code maintenance and duplication. To author policies,
the policy has to be some form of string representation (be it structured,
through XML, JSON, YAML, etcetera), to allow the policy author to understand
what is being written. In a hypothetical binary policy design, a serializer
is necessary to write the policy from the human readable form, to the binary
form, and a deserializer is needed to interpret the binary form into a data
structure in the kernel.
Eventually, another deserializer will be needed to transform the binary from
back into the human-readable form with as much information preserved. This is because a
user of this access control system will have to keep a lookup table of a checksum
and the original file itself to try to understand what policies have been deployed
on this system and what policies have not. For a single user, this may be alright,
as old policies can be discarded almost immediately after the update takes hold.
For users that manage computer fleets in the thousands, if not hundreds of thousands,
with multiple different operating systems, and multiple different operational needs,
this quickly becomes an issue, as stale policies from years ago may be present,
quickly resulting in the need to recover the policy or fund extensive infrastructure
to track what each policy contains.
With now three separate serializer/deserializers, maintenance becomes costly. If the
policy avoids the binary format, there is only one required serializer: from the
human-readable form to the data structure in kernel, saving on code maintenance,
and retaining operability.
The second issue with a binary format is one of transparency. As IPE controls
access based on the trust of the system's resources, it's policy must also be
trusted to be changed. This is done through signatures, resulting in needing
signing as a process. Signing, as a process, is typically done with a
high security bar, as anything signed can be used to attack integrity
enforcement systems. It is also important that, when signing something, that
the signer is aware of what they are signing. A binary policy can cause
obfuscation of that fact; what signers see is an opaque binary blob. A
plain-text policy, on the other hand, the signers see the actual policy
submitted for signing.
Boot Policy
~~~~~~~~~~~
IPE, if configured appropriately, is able to enforce a policy as soon as a
kernel is booted and usermode starts. That implies some level of storage
of the policy to apply the minute usermode starts. Generally, that storage
can be handled in one of three ways:
1. The policy file(s) live on disk and the kernel loads the policy prior
to a code path that would result in an enforcement decision.
2. The policy file(s) are passed by the bootloader to the kernel, who
parses the policy.
3. There is a policy file that is compiled into the kernel that is
parsed and enforced on initialization.
The first option has problems: the kernel reading files from userspace
is typically discouraged and very uncommon in the kernel.
The second option also has problems: Linux supports a variety of bootloaders
across its entire ecosystem - every bootloader would have to support this
new methodology or there must be an independent source. It would likely
result in more drastic changes to the kernel startup than necessary.
The third option is the best but it's important to be aware that the policy
will take disk space against the kernel it's compiled in. It's important to
keep this policy generalized enough that userspace can load a new, more
complicated policy, but restrictive enough that it will not overauthorize
and cause security issues.
The initramfs provides a way that this bootup path can be established. The
kernel starts with a minimal policy, that trusts the initramfs only. Inside
the initramfs, when the real rootfs is mounted, but not yet transferred to,
it deploys and activates a policy that trusts the new root filesystem.
This prevents overauthorization at any step, and keeps the kernel policy
to a minimal size.
Startup
^^^^^^^
Not every system, however starts with an initramfs, so the startup policy
compiled into the kernel will need some flexibility to express how trust
is established for the next phase of the bootup. To this end, if we just
make the compiled-in policy a full IPE policy, it allows system builders
to express the first stage bootup requirements appropriately.
Updatable, Rebootless Policy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As requirements change over time (vulnerabilities are found in previously
trusted applications, keys roll, etcetera), updating a kernel to meet
those security goals is not always a suitable option, as updates are not
always risk-free, and blocking a security update leaves systems vulnerable.
This means IPE requires a policy that can be completely updated (allowing
revocations of existing policy) from a source external to the kernel (allowing
policies to be updated without updating the kernel).
Additionally, since the kernel is stateless between invocations, and reading
policy files off the disk from kernel space is a bad idea(tm), then the
policy updates have to be done rebootlessly.
To allow an update from an external source, it could be potentially malicious,
so this policy needs to have a way to be identified as trusted. This is
done via a signature chained to a trust source in the kernel. Arbitrarily,
this is the ``SYSTEM_TRUSTED_KEYRING``, a keyring that is initially
populated at kernel compile-time, as this matches the expectation that the
author of the compiled-in policy described above is the same entity that can
deploy policy updates.
Anti-Rollback / Anti-Replay
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Over time, vulnerabilities are found and trusted resources may not be
trusted anymore. IPE's policy has no exception to this. There can be
instances where a mistaken policy author deploys an insecure policy,
before correcting it with a secure policy.
Assuming that as soon as the insecure policy is signed, and an attacker
acquires the insecure policy, IPE needs a way to prevent rollback
from the secure policy update to the insecure policy update.
Initially, IPE's policy can have a policy_version that states the
minimum required version across all policies that can be active on
the system. This will prevent rollback while the system is live.
.. WARNING::
However, since the kernel is stateless across boots, this policy
version will be reset to 0.0.0 on the next boot. System builders
need to be aware of this, and ensure the new secure policies are
deployed ASAP after a boot to ensure that the window of
opportunity is minimal for an attacker to deploy the insecure policy.
Implicit Actions:
~~~~~~~~~~~~~~~~~
The issue of implicit actions only becomes visible when you consider
a mixed level of security bars across multiple operations in a system.
For example, consider a system that has strong integrity guarantees
over both the executable code, and specific *data files* on the system,
that were critical to its function. In this system, three types of policies
are possible:
1. A policy in which failure to match any rules in the policy results
in the action being denied.
2. A policy in which failure to match any rules in the policy results
in the action being allowed.
3. A policy in which the action taken when no rules are matched is
specified by the policy author.
The first option could make a policy like this::
op=EXECUTE integrity_verified=YES action=ALLOW
In the example system, this works well for the executables, as all
executables should have integrity guarantees, without exception. The
issue becomes with the second requirement about specific data files.
This would result in a policy like this (assuming each line is
evaluated in order)::
op=EXECUTE integrity_verified=YES action=ALLOW
op=READ integrity_verified=NO label=critical_t action=DENY
op=READ action=ALLOW
This is somewhat clear if you read the docs, understand the policy
is executed in order and that the default is a denial; however, the
last line effectively changes that default to an ALLOW. This is
required, because in a realistic system, there are some unverified
reads (imagine appending to a log file).
The second option, matching no rules results in an allow, is clearer
for the specific data files::
op=READ integrity_verified=NO label=critical_t action=DENY
And, like the first option, falls short with the execution scenario,
effectively needing to override the default::
op=EXECUTE integrity_verified=YES action=ALLOW
op=EXECUTE action=DENY
op=READ integrity_verified=NO label=critical_t action=DENY
This leaves the third option. Instead of making users be clever
and override the default with an empty rule, force the end-user
to consider what the appropriate default should be for their
scenario and explicitly state it::
DEFAULT op=EXECUTE action=DENY
op=EXECUTE integrity_verified=YES action=ALLOW
DEFAULT op=READ action=ALLOW
op=READ integrity_verified=NO label=critical_t action=DENY
Policy Debugging:
~~~~~~~~~~~~~~~~~
When developing a policy, it is useful to know what line of the policy
is being violated to reduce debugging costs; narrowing the scope of the
investigation to the exact line that resulted in the action. Some integrity
policy systems do not provide this information, instead providing the
information that was used in the evaluation. This then requires a correlation
with the policy to evaluate what went wrong.
Instead, IPE just emits the rule that was matched. This limits the scope
of the investigation to the exact policy line (in the case of a specific
rule), or the section (in the case of a DEFAULT). This decreases iteration
and investigation times when policy failures are observed while evaluating
policies.
IPE's policy engine is also designed in a way that it makes it obvious to
a human of how to investigate a policy failure. Each line is evaluated in
the sequence that is written, so the algorithm is very simple to follow
for humans to recreate the steps and could have caused the failure. In other
surveyed systems, optimizations occur (sorting rules, for instance) when loading
the policy. In those systems, it requires multiple steps to debug, and the
algorithm may not always be clear to the end-user without reading the code first.
Simplified Policy:
~~~~~~~~~~~~~~~~~~
Finally, IPE's policy is designed for sysadmins, not kernel developers. Instead
of covering individual LSM hooks (or syscalls), IPE covers operations. This means
instead of sysadmins needing to know that the syscalls ``mmap``, ``mprotect``,
``execve``, and ``uselib`` must have rules protecting them, they must simply know
that they want to restrict code execution. This limits the amount of bypasses that
could occur due to a lack of knowledge of the underlying system; whereas the
maintainers of IPE, being kernel developers can make the correct choice to determine
whether something maps to these operations, and under what conditions.
Implementation Notes
--------------------
Anonymous Memory
~~~~~~~~~~~~~~~~
Anonymous memory isn't treated any differently from any other access in IPE.
When anonymous memory is mapped with ``+X``, it still comes into the ``file_mmap``
or ``file_mprotect`` hook, but with a ``NULL`` file object. This is submitted to
the evaluation, like any other file. However, all current trust properties will
evaluate to false, as they are all file-based and the operation is not
associated with a file.
.. WARNING::
This also occurs with the ``kernel_load_data`` hook, when the kernel is
loading data from a userspace buffer that is not backed by a file. In this
scenario all current trust properties will also evaluate to false.
Securityfs Interface
~~~~~~~~~~~~~~~~~~~~
The per-policy securityfs tree is somewhat unique. For example, for
a standard securityfs policy tree::
MyPolicy
|- active
|- delete
|- name
|- pkcs7
|- policy
|- update
|- version
The policy is stored in the ``->i_private`` data of the MyPolicy inode.
Tests
-----
IPE has KUnit Tests for the policy parser. Recommended kunitconfig::
CONFIG_KUNIT=y
CONFIG_SECURITY=y
CONFIG_SECURITYFS=y
CONFIG_PKCS7_MESSAGE_PARSER=y
CONFIG_SYSTEM_DATA_VERIFICATION=y
CONFIG_FS_VERITY=y
CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y
CONFIG_BLOCK=y
CONFIG_MD=y
CONFIG_BLK_DEV_DM=y
CONFIG_DM_VERITY=y
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
CONFIG_NET=y
CONFIG_AUDIT=y
CONFIG_AUDITSYSCALL=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_SECURITY_IPE=y
CONFIG_IPE_PROP_DM_VERITY=y
CONFIG_IPE_PROP_DM_VERITY_SIGNATURE=y
CONFIG_IPE_PROP_FS_VERITY=y
CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG=y
CONFIG_SECURITY_IPE_KUNIT_TEST=y
In addition, IPE has a python based integration
`test suite <https://github.com/microsoft/ipe/tree/test-suite>`_ that
can test both user interfaces and enforcement functionalities.
File diff suppressed because it is too large Load Diff
@@ -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 (FEKEK)
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 FEKEK, 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 FEKEK 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 FEKEK 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
@@ -0,0 +1,11 @@
===========
Kernel Keys
===========
.. toctree::
:maxdepth: 1
core
ecryptfs
request-key
trusted-encrypted
@@ -0,0 +1,207 @@
===================
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_tag(const struct key_type *type,
const char *description,
const struct key_tag *domain_tag,
const char *callout_info);
or::
struct key *request_key_with_auxdata(const struct key_type *type,
const char *description,
const struct key_tag *domain_tag,
const char *callout_info,
size_t callout_len,
void *aux);
or::
struct key *request_key_rcu(const struct key_type *type,
const char *description,
const struct key_tag *domain_tag);
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_tag() call is like the in-kernel request_key(), except that it
also takes a domain tag that allows keys to be separated by namespace and
killed off as a group.
The request_key_with_auxdata() calls is like the request_key_tag() call, 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 request_key_rcu() call is like the request_key_tag() call, except that it
doesn't check for keys that are under construction and doesn't attempt to
construct missing keys.
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 while 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_rcu) 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 request_key() is invoked, if CONFIG_KEYS_REQUEST_CACHE=y, a per-task
one-key cache is first checked for a match.
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. If CONFIG_KEYS_REQUEST_CACHE=y, then that key is placed in the
per-task cache, displacing the previous key. The cache is cleared on exit or
just prior to resumption of userspace.
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,617 @@
==========================
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 Trust Source 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 as Protected key
=============================
It is the secure way of keeping the keys in the kernel key-ring as Trusted-Key,
such that:
- Key-blob, an encrypted key-data, created to be stored, loaded and seen by
userspace.
- Key-data, the plain-key text in the system memory, to be used by
kernel space only.
Though key-data is not accessible to the user-space in plain-text, but it is in
plain-text in system memory, when used in kernel space. Even though kernel-space
attracts small surface attack, but with compromised kernel or side-channel
attack accessing the system memory can lead to a chance of the key getting
compromised/leaked.
In order to protect the key in kernel space, the concept of "protected-keys" is
introduced which will act as an added layer of protection. The key-data of the
protected keys is encrypted with Key-Encryption-Key(KEK), and decrypted inside
the trust source boundary. The plain-key text never available out-side in the
system memory. Thus, any crypto operation that is to be executed using the
protected key, can only be done by the trust source, which generated the
key blob.
Hence, if the protected-key is leaked or compromised, it is of no use to the
hacker.
Trusted keys as protected keys, with trust source having the capability of
generating:
- Key-Blob, to be loaded, stored and seen by user-space.
Trust Source
============
A trust source provides the source of security for Trusted Keys. This
section lists currently supported trust sources, along with their security
considerations. Whether or not a trust source is sufficiently safe depends
on the strength and correctness of its implementation, as well as the threat
environment for a specific use case. Since the kernel doesn't know what the
environment is, and there is no metric of trust, it is dependent on the
consumer of the Trusted Keys to determine if the trust source is sufficiently
safe.
* Root of trust for storage
(1) TPM (Trusted Platform Module: hardware device)
Rooted to Storage Root Key (SRK) which never leaves the TPM that
provides crypto operation to establish root of trust for storage.
(2) TEE (Trusted Execution Environment: OP-TEE based on Arm TrustZone)
Rooted to Hardware Unique Key (HUK) which is generally burnt in on-chip
fuses and is accessible to TEE only.
(3) CAAM (Cryptographic Acceleration and Assurance Module: IP on NXP SoCs)
When High Assurance Boot (HAB) is enabled and the CAAM is in secure
mode, trust is rooted to the OTPMK, a never-disclosed 256-bit key
randomly generated and fused into each SoC at manufacturing time.
Otherwise, a common fixed test key is used instead.
(4) DCP (Data Co-Processor: crypto accelerator of various i.MX SoCs)
Rooted to a one-time programmable key (OTP) that is generally burnt
in the on-chip fuses and is accessible to the DCP encryption engine only.
DCP provides two keys that can be used as root of trust: the OTP key
and the UNIQUE key. Default is to use the UNIQUE key, but selecting
the OTP key can be done via a module parameter (dcp_use_otp_key).
(5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStore)
Rooted to a unique, per-LPAR key, which is derived from a system-wide,
randomly generated LPAR root key. Both the per-LPAR keys and the LPAR
root key are stored in hypervisor-owned secure memory at runtime,
and the LPAR root key is additionally persisted in secure locations
such as the processor SEEPROMs and encrypted NVRAM.
* Execution isolation
(1) TPM
Fixed set of operations running in isolated execution environment.
(2) TEE
Customizable set of operations running in isolated execution
environment verified via Secure/Trusted boot process.
(3) CAAM
Fixed set of operations running in isolated execution environment.
(4) DCP
Fixed set of cryptographic operations running in isolated execution
environment. Only basic blob key encryption is executed there.
The actual key sealing/unsealing is done on main processor/kernel space.
(5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStore)
Fixed set of cryptographic operations done on on-chip hardware
cryptographic acceleration unit NX. Keys for wrapping and unwrapping
are managed by PowerVM Platform KeyStore, which stores keys in an
isolated in-memory copy in secure hypervisor memory, as well as in a
persistent copy in hypervisor-encrypted NVRAM.
* Optional binding to platform integrity state
(1) TPM
Keys can be 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.
(2) TEE
Relies on Secure/Trusted boot process for platform integrity. It can
be extended with TEE based measured boot process.
(3) CAAM
Relies on the High Assurance Boot (HAB) mechanism of NXP SoCs
for platform integrity.
(4) DCP
Relies on Secure/Trusted boot process (called HAB by vendor) for
platform integrity.
(5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStore)
Relies on secure and trusted boot process of IBM Power systems for
platform integrity.
* Interfaces and APIs
(1) TPM
TPMs have well-documented, standardized interfaces and APIs.
(2) TEE
TEEs have well-documented, standardized client interface and APIs. For
more details refer to ``Documentation/driver-api/tee.rst``.
(3) CAAM
Interface is specific to silicon vendor.
(4) DCP
Vendor-specific API that is implemented as part of the DCP crypto driver in
``drivers/crypto/mxs-dcp.c``.
(5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStore)
Platform Keystore has well documented interfaces in PAPR document.
Refer to ``Documentation/arch/powerpc/papr_hcalls.rst``
* Threat model
The strength and appropriateness of a particular trust source for a given
purpose must be assessed when using them to protect security-relevant data.
Key Generation
==============
Trusted Keys
------------
New keys are created from random numbers. They are encrypted/decrypted using
a child key in the storage key hierarchy. Encryption and decryption of the
child key must be protected by a strong access control policy within the
trust source. The random number generator in use differs according to the
selected trust source:
* TPM: hardware device based RNG
Keys are generated within the TPM. Strength of random numbers may vary
from one device manufacturer to another.
* TEE: OP-TEE based on Arm TrustZone based RNG
RNG is customizable as per platform needs. It can either be direct output
from platform specific hardware RNG or a software based Fortuna CSPRNG
which can be seeded via multiple entropy sources.
* CAAM: Kernel RNG
The normal kernel random number generator is used. To seed it from the
CAAM HWRNG, enable CRYPTO_DEV_FSL_CAAM_RNG_API and ensure the device
is probed.
* DCP (Data Co-Processor: crypto accelerator of various i.MX SoCs)
The DCP hardware device itself does not provide a dedicated RNG interface,
so the kernel default RNG is used. SoCs with DCP like the i.MX6ULL do have
a dedicated hardware RNG that is independent from DCP which can be enabled
to back the kernel RNG.
* PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStore)
The normal kernel random number generator is used to generate keys.
Users may override this by specifying ``trusted.rng=kernel`` on the kernel
command-line to override the used RNG with the kernel's random number pool.
Encrypted Keys
--------------
Encrypted keys do not depend on a trust source, and are faster, as they use AES
for encryption/decryption. New keys are created either from kernel-generated
random numbers or user-provided decrypted data, 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.
Usage
=====
Trusted Keys usage: TPM
-----------------------
TPM 1.2: By default, trusted keys are sealed under the SRK, which has the
default authorization value (20 bytes of 0s). This can be set at takeownership
time with the TrouSerS utility: "tpm_takeownership -u -z".
TPM 2.0: The user must first create a storage key and make it persistent, so the
key is available after reboot. This can be done using the following commands.
With the IBM TSS 2 stack::
#> tsscreateprimary -hi o -st
Handle 80000000
#> tssevictcontrol -hi o -ho 80000000 -hp 81000001
Or with the Intel TSS 2 stack::
#> tpm2_createprimary --hierarchy o -G rsa2048 -c key.ctxt
[...]
#> tpm2_evictcontrol -c key.ctxt 0x81000001
persistentHandle: 0x81000001
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
TPM 1.2: default 0x40000000 (SRK)
TPM 2.0: no default; must be passed every time
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.
Trusted Keys usage: TEE
-----------------------
Usage::
keyctl add trusted name "new keylen" ring
keyctl add trusted name "load hex_blob" ring
keyctl print keyid
"keyctl print" returns an ASCII hex copy of the sealed key, which is in format
specific to TEE device implementation. The key length for new keys is always
in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits).
Trusted Keys usage: CAAM
------------------------
Trusted Keys Usage::
keyctl add trusted name "new keylen" ring
keyctl add trusted name "load hex_blob" ring
keyctl print keyid
"keyctl print" returns an ASCII hex copy of the sealed key, which is in a
CAAM-specific format. The key length for new keys is always in bytes.
Trusted Keys can be 32 - 128 bytes (256 - 1024 bits).
Trusted Keys as Protected Keys Usage::
keyctl add trusted name "new keylen pk [options]" ring
keyctl add trusted name "load hex_blob [options]" ring
keyctl print keyid
where, 'pk' is used to direct trust source to generate protected key.
options:
key_enc_algo = For CAAM, supported enc algo are ECB(2), CCM(1).
"keyctl print" returns an ASCII hex copy of the sealed key, which is in a
CAAM-specific format. The key length for new keys is always in bytes.
Trusted Keys can be 32 - 128 bytes (256 - 1024 bits).
Trusted Keys usage: DCP
-----------------------
Usage::
keyctl add trusted name "new keylen" ring
keyctl add trusted name "load hex_blob" ring
keyctl print keyid
"keyctl print" returns an ASCII hex copy of the sealed key, which is in format
specific to this DCP key-blob implementation. The key length for new keys is
always in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits).
Trusted Keys usage: PKWM
------------------------
Usage::
keyctl add trusted name "new keylen [options]" ring
keyctl add trusted name "load hex_blob" ring
keyctl print keyid
options:
wrap_flags= ascii hex value of security policy requirement
0x00: no secure boot requirement (default)
0x01: require secure boot to be in either audit or
enforced mode
0x02: require secure boot to be in enforced mode
"keyctl print" returns an ASCII hex copy of the sealed key, which is in format
specific to PKWM key-blob implementation. The key length for new keys is
always in bytes. Trusted Keys can be 32 - 128 bytes (256 - 1024 bits).
Encrypted Keys usage
--------------------
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 "new [format] key-type:master-key-name keylen
decrypted-data" ring
keyctl add encrypted name "load hex_blob" ring
keyctl update keyid "update key-type:master-key-name"
Where::
format:= 'default | ecryptfs | enc32'
key-type:= 'trusted' | 'user'
Examples of trusted and encrypted key usage
-------------------------------------------
Create and save a trusted key named "kmk" of length 32 bytes.
Note: When using a TPM 2.0 with a persistent key with handle 0x81000001,
append 'keyhandle=0x81000001' to statements between quotes, such as
"new 32 keyhandle=0x81000001".
::
$ 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
Create and save a trusted key as protected key named "kmk" of length 32 bytes.
::
$ keyctl add trusted kmk "new 32 pk key_enc_algo=1" @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` key_enc_algo=1" @u
268728824
$ keyctl print 268728824
0101000000000000000001005d01b7e3f4a6be5709930f3b70a743cbb42e0cc95e18e915
3f60da455bbf1144ad12e4f92b452f966929f6105fd29ca28e4d4d5a031d068478bacb0b
27351119f822911b0a11ba3d3498ba6a32e50dac7f32894dd890eb9ad578e4e292c83722
a52e56a097e6a68b3f56f7a52ece0cdccba1eb62cad7d817f6dc58898b3ac15f36026fec
d568bd4a706cb60bb37be6d8f1240661199d640b66fb0fe3b079f97f450b9ef9c22c6d5d
dd379f0facd1cd020281dfa3c70ba21a3fa6fc2471dc6d13ecf8298b946f65345faa5ef0
f1f8fff03ad0acb083725535636addb08d73dedb9832da198081e5deae84bfaf0409c22b
e4a8aea2b607ec96931e6f4d4fe563ba
Reseal (TPM specific) 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 a platform integrity
state, 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
Instantiate an encrypted key "evm" using user-provided decrypted data::
$ evmkey=$(dd if=/dev/urandom bs=1 count=32 | xxd -c32 -p)
$ keyctl add encrypted evm "new default user:kmk 32 $evmkey" @u
794890253
$ keyctl print 794890253
default user:kmk 32 2375725ad57798846a9bbd240de8906f006e66c03af53b1b382d
bbc55be2a44616e4959430436dc4f2a7a9659aa60bb4652aeb2120f149ed197c564e0247
17c64 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 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``.
Another new format 'enc32' has been defined in order to support encrypted keys
with payload size of 32 bytes. This will initially be used for nvdimm security
but may expand to other usages that require 32 bytes payload.
TPM 2.0 ASN.1 Key Format
------------------------
The TPM 2.0 ASN.1 key format is designed to be easily recognisable,
even in binary form (fixing a problem we had with the TPM 1.2 ASN.1
format) and to be extensible for additions like importable keys and
policy::
TPMKey ::= SEQUENCE {
type OBJECT IDENTIFIER
emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL
parent INTEGER
pubkey OCTET STRING
privkey OCTET STRING
}
type is what distinguishes the key even in binary form since the OID
is provided by the TCG to be unique and thus forms a recognizable
binary pattern at offset 3 in the key. The OIDs currently made
available are::
2.23.133.10.1.3 TPM Loadable key. This is an asymmetric key (Usually
RSA2048 or Elliptic Curve) which can be imported by a
TPM2_Load() operation.
2.23.133.10.1.4 TPM Importable Key. This is an asymmetric key (Usually
RSA2048 or Elliptic Curve) which can be imported by a
TPM2_Import() operation.
2.23.133.10.1.5 TPM Sealed Data. This is a set of data (up to 128
bytes) which is sealed by the TPM. It usually
represents a symmetric key and must be unsealed before
use.
The trusted key code only uses the TPM Sealed Data OID.
emptyAuth is true if the key has well known authorization "". If it
is false or not present, the key requires an explicit authorization
phrase. This is used by most user space consumers to decide whether
to prompt for a password.
parent represents the parent key handle, either in the 0x81 MSO space,
like 0x81000001 for the RSA primary storage key. Userspace programmes
also support specifying the primary handle in the 0x40 MSO space. If
this happens the Elliptic Curve variant of the primary key using the
TCG defined template will be generated on the fly into a volatile
object and used as the parent. The current kernel code only supports
the 0x81 MSO form.
pubkey is the binary representation of TPM2B_PRIVATE excluding the
initial TPM2B header, which can be reconstructed from the ASN.1 octet
string length.
privkey is the binary representation of TPM2B_PUBLIC excluding the
initial TPM2B header which can be reconstructed from the ASN.1 octed
string length.
DCP Blob Format
---------------
.. kernel-doc:: security/keys/trusted-keys/trusted_dcp.c
:doc: dcp blob format
.. kernel-doc:: security/keys/trusted-keys/trusted_dcp.c
:identifiers: struct dcp_blob_fmt
@@ -0,0 +1,189 @@
.. SPDX-License-Identifier: GPL-2.0
.. Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net>
.. Copyright © 2019-2020 ANSSI
==================================
Landlock LSM: kernel documentation
==================================
:Author: Mickaël Salaün
:Date: March 2026
Landlock's goal is to create scoped access-control (i.e. sandboxing). To
harden a whole system, this feature should be available to any process,
including unprivileged ones. Because such a process may be compromised or
backdoored (i.e. untrusted), Landlock's features must be safe to use from the
kernel and other processes point of view. Landlock's interface must therefore
expose a minimal attack surface.
Landlock is designed to be usable by unprivileged processes while following the
system security policy enforced by other access control mechanisms (e.g. DAC,
LSM). A Landlock rule shall not interfere with other access-controls enforced
on the system, only add more restrictions.
Any user can enforce Landlock rulesets on their processes. They are merged and
evaluated against inherited rulesets in a way that ensures that only more
constraints can be added.
User space documentation can be found here:
Documentation/userspace-api/landlock.rst.
Guiding principles for safe access controls
===========================================
* A Landlock rule shall be focused on access control on kernel objects instead
of syscall filtering (i.e. syscall arguments), which is the purpose of
seccomp-bpf.
* To avoid multiple kinds of side-channel attacks (e.g. leak of security
policies, CPU-based attacks), Landlock rules shall not be able to
programmatically communicate with user space.
* Kernel access check shall not slow down access request from unsandboxed
processes.
* Computation related to Landlock operations (e.g. enforcing a ruleset) shall
only impact the processes requesting them.
* Resources (e.g. file descriptors) directly obtained from the kernel by a
sandboxed process shall retain their scoped accesses (at the time of resource
acquisition) whatever process uses them.
Cf. `File descriptor access rights`_.
* Access denials shall be logged according to system and Landlock domain
configurations. Log entries must contain information about the cause of the
denial and the owner of the related security policy. Such log generation
should have a negligible performance and memory impact on allowed requests.
Design choices
==============
Inode access rights
-------------------
All access rights are tied to an inode and what can be accessed through it.
Reading the content of a directory does not imply to be allowed to read the
content of a listed inode. Indeed, a file name is local to its parent
directory, and an inode can be referenced by multiple file names thanks to
(hard) links. Being able to unlink a file only has a direct impact on the
directory, not the unlinked inode. This is the reason why
``LANDLOCK_ACCESS_FS_REMOVE_FILE`` or ``LANDLOCK_ACCESS_FS_REFER`` are not
allowed to be tied to files but only to directories.
File descriptor access rights
-----------------------------
Access rights are checked and tied to file descriptors at open time. The
underlying principle is that equivalent sequences of operations should lead to
the same results, when they are executed under the same Landlock domain.
Taking the ``LANDLOCK_ACCESS_FS_TRUNCATE`` right as an example, it may be
allowed to open a file for writing without being allowed to
:manpage:`ftruncate` the resulting file descriptor if the related file
hierarchy doesn't grant that access right. The following sequences of
operations have the same semantic and should then have the same result:
* ``truncate(path);``
* ``int fd = open(path, O_WRONLY); ftruncate(fd); close(fd);``
Similarly to file access modes (e.g. ``O_RDWR``), Landlock access rights
attached to file descriptors are retained even if they are passed between
processes (e.g. through a Unix domain socket). Such access rights will then be
enforced even if the receiving process is not sandboxed by Landlock. Indeed,
this is required to keep access controls consistent over the whole system, and
this avoids unattended bypasses through file descriptor passing (i.e. confused
deputy attack).
.. _scoped-flags-interaction:
Interaction between scoped flags and other access rights
--------------------------------------------------------
The ``scoped`` flags in &struct landlock_ruleset_attr restrict the
use of *outgoing* IPC from the created Landlock domain, while they
permit reaching out to IPC endpoints *within* the created Landlock
domain.
In the future, scoped flags *may* interact with other access rights,
e.g. so that abstract UNIX sockets can be allow-listed by name, or so
that signals can be allow-listed by signal number or target process.
When introducing ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX``, we defined it to
implicitly have the same scoping semantics as a
``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` flag would have: connecting to
UNIX sockets within the same domain (where
``LANDLOCK_ACCESS_FS_RESOLVE_UNIX`` is used) is unconditionally
allowed.
The reasoning is:
* Like other IPC mechanisms, connecting to named UNIX sockets in the
same domain should be expected and harmless. (If needed, users can
further refine their Landlock policies with nested domains or by
restricting ``LANDLOCK_ACCESS_FS_MAKE_SOCK``.)
* We reserve the option to still introduce
``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` in the future. (This would
be useful if we wanted to have a Landlock rule to permit IPC access
to other Landlock domains.)
* But we can postpone the point in time when users have to deal with
two interacting flags visible in the userspace API. (In particular,
it is possible that it won't be needed in practice, in which case we
can avoid the second flag altogether.)
* If we *do* introduce ``LANDLOCK_SCOPE_PATHNAME_UNIX_SOCKET`` in the
future, setting this scoped flag in a ruleset does *not reduce* the
restrictions, because access within the same scope is already
allowed based on ``LANDLOCK_ACCESS_FS_RESOLVE_UNIX``.
Tests
=====
Userspace tests for backward compatibility, ptrace restrictions and filesystem
support can be found here: `tools/testing/selftests/landlock/`_.
Kernel structures
=================
Object
------
.. kernel-doc:: security/landlock/object.h
:identifiers:
Filesystem
----------
.. kernel-doc:: security/landlock/fs.h
:identifiers:
Process credential
------------------
.. kernel-doc:: security/landlock/cred.h
:identifiers:
Ruleset and domain
------------------
A domain is a read-only ruleset tied to a set of subjects (i.e. tasks'
credentials). Each time a ruleset is enforced on a task, the current domain is
duplicated and the ruleset is imported as a new layer of rules in the new
domain. Indeed, once in a domain, each rule is tied to a layer level. To
grant access to an object, at least one rule of each layer must allow the
requested action on the object. A task can then only transit to a new domain
that is the intersection of the constraints from the current domain and those
of a ruleset provided by the task.
The definition of a subject is implicit for a task sandboxing itself, which
makes the reasoning much easier and helps avoid pitfalls.
.. kernel-doc:: security/landlock/ruleset.h
:identifiers:
.. kernel-doc:: security/landlock/domain.h
:identifiers:
Additional documentation
========================
* Documentation/userspace-api/landlock.rst
* Documentation/admin-guide/LSM/landlock.rst
* https://landlock.io
.. Links
.. _tools/testing/selftests/landlock/:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/tools/testing/selftests/landlock/
@@ -0,0 +1,17 @@
=================================
Linux Security Module Development
=================================
Based on https://lore.kernel.org/r/20071026073721.618b4778@laptopd505.fenrus.org,
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/admin-guide/LSM/``.
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 ``security/security.c`` and associated structures:
.. kernel-doc:: security/security.c
:export:
+131
View File
@@ -0,0 +1,131 @@
========================================================
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 was 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 work was
incorporated in the mainstream in December of 2003. This technical
report provides an overview of the framework and the capabilities
security module.
LSM Framework
=============
The LSM framework 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 sandboxing. By itself, the
framework does not provide any additional security; it merely provides
the infrastructure to support security modules. The LSM framework is
optional, requiring `CONFIG_SECURITY` to be enabled. The capabilities
logic is implemented as a security module.
This capabilities module is discussed further in
`LSM Capabilities Module`_.
The LSM framework includes security fields in kernel data structures and
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 security modules.
An interface `/sys/kernel/security/lsm` reports a comma separated list
of security modules that are active on the system.
The LSM security fields are simply ``void*`` pointers.
The data is referred to as a blob, which may be managed by
the framework or by the individual security modules that use it.
Security blobs that are used by more than one security module are
typically managed by the framework.
For process and
program execution security information, security fields are included in
:c:type:`struct task_struct <task_struct>` and
:c:type:`struct cred <cred>`.
For filesystem
security information, a security field is included in :c:type:`struct
super_block <super_block>`. For pipe, file, and socket security
information, security fields are included in :c:type:`struct inode
<inode>` and :c:type:`struct file <file>`.
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.
For packet and
network device security information, security fields were added to
:c:type:`struct sk_buff <sk_buff>` and
:c:type:`struct scm_cookie <scm_cookie>`.
Unlike the other security module data, the data used here is a
32-bit integer. The security modules are required to map or otherwise
associate these values with real security attributes.
LSM hooks are maintained in lists. A list is maintained for each
hook, and the hooks are called in the order specified by CONFIG_LSM.
Detailed documentation for each hook is
included in the `security/security.c` source file.
The LSM framework provides for a close approximation of
general security module stacking. It defines
security_add_hooks() to which each security module passes a
:c:type:`struct security_hooks_list <security_hooks_list>`,
which are added to the lists.
The LSM framework does not provide a mechanism for removing hooks that
have been registered. The SELinux security module has implemented
a way to remove itself, however the feature has been deprecated.
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 security_inode_alloc() and security_inode_free()
These hooks are used to allocate
and free security structures for inode objects.
An example of the second category of hooks
is the security_inode_permission() hook.
This hook checks permission when accessing an inode.
LSM Capabilities Module
=======================
The POSIX.1e capabilities logic is maintained as a security module
stored in the file ``security/commoncap.c``. The capabilities
module uses the order field of the :c:type:`lsm_info` description
to identify it as the first security module to be registered.
The capabilities security module does not use the general security
blobs, unlike other modules. The reasons are historical and are
based on overhead, complexity and performance concerns.
@@ -0,0 +1,91 @@
=========================================
Linux Secure Attention Key (SAK) handling
=========================================
:Date: 18 March 2001
:Author: Andrew Morton
An operating system's Secure Attention Key is a security tool which is
provided as protection against trojan password capturing programs. It
is an undefeatable way of killing all programs which could be
masquerading as login applications. Users need to be taught to enter
this key sequence before they log in to the system.
From the PC keyboard, Linux has two similar but different ways of
providing SAK. One is the ALT-SYSRQ-K sequence. You shouldn't use
this sequence. It is only available if the kernel was compiled with
sysrq support.
The proper way of generating a SAK is to define the key sequence using
``loadkeys``. This will work whether or not sysrq support is compiled
into the kernel.
SAK works correctly when the keyboard is in raw mode. This means that
once defined, SAK will kill a running X server. If the system is in
run level 5, the X server will restart. This is what you want to
happen.
What key sequence should you use? Well, CTRL-ALT-DEL is used to reboot
the machine. CTRL-ALT-BACKSPACE is magical to the X server. We'll
choose CTRL-ALT-PAUSE.
In your rc.sysinit (or rc.local) file, add the command::
echo "control alt keycode 101 = SAK" | /bin/loadkeys
And that's it! Only the superuser may reprogram the SAK key.
.. note::
1. Linux SAK is said to be not a "true SAK" as is required by
systems which implement C2 level security. This author does not
know why.
2. On the PC keyboard, SAK kills all applications which have
/dev/console opened.
Unfortunately this includes a number of things which you don't
actually want killed. This is because these applications are
incorrectly holding /dev/console open. Be sure to complain to your
Linux distributor about this!
You can identify processes which will be killed by SAK with the
command::
# ls -l /proc/[0-9]*/fd/* | grep console
l-wx------ 1 root root 64 Mar 18 00:46 /proc/579/fd/0 -> /dev/console
Then::
# ps aux|grep 579
root 579 0.0 0.1 1088 436 ? S 00:43 0:00 gpm -t ps/2
So ``gpm`` will be killed by SAK. This is a bug in gpm. It should
be closing standard input. You can work around this by finding the
initscript which launches gpm and changing it thusly:
Old::
daemon gpm
New::
daemon gpm < /dev/null
Vixie cron also seems to have this problem, and needs the same treatment.
Also, one prominent Linux distribution has the following three
lines in its rc.sysinit and rc scripts::
exec 3<&0
exec 4>&1
exec 5>&2
These commands cause **all** daemons which are launched by the
initscripts to have file descriptors 3, 4 and 5 attached to
/dev/console. So SAK kills them all. A workaround is to simply
delete these lines, but this may cause system management
applications to malfunction - test everything well.
@@ -0,0 +1,103 @@
.. SPDX-License-Identifier: GPL-2.0
==============================
Confidential Computing secrets
==============================
This document describes how Confidential Computing secret injection is handled
from the firmware to the operating system, in the EFI driver and the efi_secret
kernel module.
Introduction
============
Confidential Computing (coco) hardware such as AMD SEV (Secure Encrypted
Virtualization) allows guest owners to inject secrets into the VMs
memory without the host/hypervisor being able to read them. In SEV,
secret injection is performed early in the VM launch process, before the
guest starts running.
The efi_secret kernel module allows userspace applications to access these
secrets via securityfs.
Secret data flow
================
The guest firmware may reserve a designated memory area for secret injection,
and publish its location (base GPA and length) in the EFI configuration table
under a ``LINUX_EFI_COCO_SECRET_AREA_GUID`` entry
(``adf956ad-e98c-484c-ae11-b51c7d336447``). This memory area should be marked
by the firmware as ``EFI_RESERVED_TYPE``, and therefore the kernel should not
be use it for its own purposes.
During the VM's launch, the virtual machine manager may inject a secret to that
area. In AMD SEV and SEV-ES this is performed using the
``KVM_SEV_LAUNCH_SECRET`` command (see [sev]_). The structure of the injected
Guest Owner secret data should be a GUIDed table of secret values; the binary
format is described in ``drivers/virt/coco/efi_secret/efi_secret.c`` under
"Structure of the EFI secret area".
On kernel start, the kernel's EFI driver saves the location of the secret area
(taken from the EFI configuration table) in the ``efi.coco_secret`` field.
Later it checks if the secret area is populated: it maps the area and checks
whether its content begins with ``EFI_SECRET_TABLE_HEADER_GUID``
(``1e74f542-71dd-4d66-963e-ef4287ff173b``). If the secret area is populated,
the EFI driver will autoload the efi_secret kernel module, which exposes the
secrets to userspace applications via securityfs. The details of the
efi_secret filesystem interface are in [secrets-coco-abi]_.
Application usage example
=========================
Consider a guest performing computations on encrypted files. The Guest Owner
provides the decryption key (= secret) using the secret injection mechanism.
The guest application reads the secret from the efi_secret filesystem and
proceeds to decrypt the files into memory and then performs the needed
computations on the content.
In this example, the host can't read the files from the disk image
because they are encrypted. Host can't read the decryption key because
it is passed using the secret injection mechanism (= secure channel).
Host can't read the decrypted content from memory because it's a
confidential (memory-encrypted) guest.
Here is a simple example for usage of the efi_secret module in a guest
to which an EFI secret area with 4 secrets was injected during launch::
# ls -la /sys/kernel/security/secrets/coco
total 0
drwxr-xr-x 2 root root 0 Jun 28 11:54 .
drwxr-xr-x 3 root root 0 Jun 28 11:54 ..
-r--r----- 1 root root 0 Jun 28 11:54 736870e5-84f0-4973-92ec-06879ce3da0b
-r--r----- 1 root root 0 Jun 28 11:54 83c83f7f-1356-4975-8b7e-d3a0b54312c6
-r--r----- 1 root root 0 Jun 28 11:54 9553f55d-3da2-43ee-ab5d-ff17f78864d2
-r--r----- 1 root root 0 Jun 28 11:54 e6f5a162-d67f-4750-a67c-5d065f2a9910
# hd /sys/kernel/security/secrets/coco/e6f5a162-d67f-4750-a67c-5d065f2a9910
00000000 74 68 65 73 65 2d 61 72 65 2d 74 68 65 2d 6b 61 |these-are-the-ka|
00000010 74 61 2d 73 65 63 72 65 74 73 00 01 02 03 04 05 |ta-secrets......|
00000020 06 07 |..|
00000022
# rm /sys/kernel/security/secrets/coco/e6f5a162-d67f-4750-a67c-5d065f2a9910
# ls -la /sys/kernel/security/secrets/coco
total 0
drwxr-xr-x 2 root root 0 Jun 28 11:55 .
drwxr-xr-x 3 root root 0 Jun 28 11:54 ..
-r--r----- 1 root root 0 Jun 28 11:54 736870e5-84f0-4973-92ec-06879ce3da0b
-r--r----- 1 root root 0 Jun 28 11:54 83c83f7f-1356-4975-8b7e-d3a0b54312c6
-r--r----- 1 root root 0 Jun 28 11:54 9553f55d-3da2-43ee-ab5d-ff17f78864d2
References
==========
See [sev-api-spec]_ for more info regarding SEV ``LAUNCH_SECRET`` operation.
.. [sev] Documentation/virt/kvm/x86/amd-memory-encryption.rst
.. [secrets-coco-abi] Documentation/ABI/testing/securityfs-secrets-coco
.. [sev-api-spec] https://www.amd.com/system/files/TechDocs/55766_SEV-KM_API_Specification.pdf
@@ -0,0 +1,9 @@
.. SPDX-License-Identifier: GPL-2.0
=====================
Secrets documentation
=====================
.. toctree::
coco
@@ -0,0 +1,316 @@
======================
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 ``__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, to avoid reuse
attacks that rely on the old contents of memory. E.g., clear stack on a
syscall return (``CONFIG_KSTACK_ERASE``), wipe heap memory on a
free. 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.
@@ -0,0 +1,199 @@
===========================
SipHash - a short input PRF
===========================
:Author: Written by Jason A. Donenfeld <jason@zx2c4.com>
SipHash is a cryptographically secure PRF -- a keyed hash function -- that
performs very well for short inputs, hence the name. It was designed by
cryptographers Daniel J. Bernstein and Jean-Philippe Aumasson. It is intended
as a replacement for some uses of: `jhash`, `md5_transform`, `sha1_transform`,
and so forth.
SipHash takes a secret key filled with randomly generated numbers and either
an input buffer or several input integers. It spits out an integer that is
indistinguishable from random. You may then use that integer as part of secure
sequence numbers, secure cookies, or mask it off for use in a hash table.
Generating a key
================
Keys should always be generated from a cryptographically secure source of
random numbers, either using get_random_bytes or get_random_once::
siphash_key_t key;
get_random_bytes(&key, sizeof(key));
If you're not deriving your key from here, you're doing it wrong.
Using the functions
===================
There are two variants of the function, one that takes a list of integers, and
one that takes a buffer::
u64 siphash(const void *data, size_t len, const siphash_key_t *key);
And::
u64 siphash_1u64(u64, const siphash_key_t *key);
u64 siphash_2u64(u64, u64, const siphash_key_t *key);
u64 siphash_3u64(u64, u64, u64, const siphash_key_t *key);
u64 siphash_4u64(u64, u64, u64, u64, const siphash_key_t *key);
u64 siphash_1u32(u32, const siphash_key_t *key);
u64 siphash_2u32(u32, u32, const siphash_key_t *key);
u64 siphash_3u32(u32, u32, u32, const siphash_key_t *key);
u64 siphash_4u32(u32, u32, u32, u32, const siphash_key_t *key);
If you pass the generic siphash function something of a constant length, it
will constant fold at compile-time and automatically choose one of the
optimized functions.
Hashtable key function usage::
struct some_hashtable {
DECLARE_HASHTABLE(hashtable, 8);
siphash_key_t key;
};
void init_hashtable(struct some_hashtable *table)
{
get_random_bytes(&table->key, sizeof(table->key));
}
static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
{
return &table->hashtable[siphash(input, sizeof(*input), &table->key) & (HASH_SIZE(table->hashtable) - 1)];
}
You may then iterate like usual over the returned hash bucket.
Security
========
SipHash has a very high security margin, with its 128-bit key. So long as the
key is kept secret, it is impossible for an attacker to guess the outputs of
the function, even if being able to observe many outputs, since 2^128 outputs
is significant.
Linux implements the "2-4" variant of SipHash.
Struct-passing Pitfalls
=======================
Often times the XuY functions will not be large enough, and instead you'll
want to pass a pre-filled struct to siphash. When doing this, it's important
to always ensure the struct has no padding holes. The easiest way to do this
is to simply arrange the members of the struct in descending order of size,
and to use offsetofend() instead of sizeof() for getting the size. For
performance reasons, if possible, it's probably a good thing to align the
struct to the right boundary. Here's an example::
const struct {
struct in6_addr saddr;
u32 counter;
u16 dport;
} __aligned(SIPHASH_ALIGNMENT) combined = {
.saddr = *(struct in6_addr *)saddr,
.counter = counter,
.dport = dport
};
u64 h = siphash(&combined, offsetofend(typeof(combined), dport), &secret);
Resources
=========
Read the SipHash paper if you're interested in learning more:
https://131002.net/siphash/siphash.pdf
-------------------------------------------------------------------------------
===============================================
HalfSipHash - SipHash's insecure younger cousin
===============================================
:Author: Written by Jason A. Donenfeld <jason@zx2c4.com>
On the off-chance that SipHash is not fast enough for your needs, you might be
able to justify using HalfSipHash, a terrifying but potentially useful
possibility. HalfSipHash cuts SipHash's rounds down from "2-4" to "1-3" and,
even scarier, uses an easily brute-forcable 64-bit key (with a 32-bit output)
instead of SipHash's 128-bit key. However, this may appeal to some
high-performance `jhash` users.
HalfSipHash support is provided through the "hsiphash" family of functions.
.. warning::
Do not ever use the hsiphash functions except for as a hashtable key
function, and only then when you can be absolutely certain that the outputs
will never be transmitted out of the kernel. This is only remotely useful
over `jhash` as a means of mitigating hashtable flooding denial of service
attacks.
On 64-bit kernels, the hsiphash functions actually implement SipHash-1-3, a
reduced-round variant of SipHash, instead of HalfSipHash-1-3. This is because in
64-bit code, SipHash-1-3 is no slower than HalfSipHash-1-3, and can be faster.
Note, this does *not* mean that in 64-bit kernels the hsiphash functions are the
same as the siphash ones, or that they are secure; the hsiphash functions still
use a less secure reduced-round algorithm and truncate their outputs to 32
bits.
Generating a hsiphash key
=========================
Keys should always be generated from a cryptographically secure source of
random numbers, either using get_random_bytes or get_random_once::
hsiphash_key_t key;
get_random_bytes(&key, sizeof(key));
If you're not deriving your key from here, you're doing it wrong.
Using the hsiphash functions
============================
There are two variants of the function, one that takes a list of integers, and
one that takes a buffer::
u32 hsiphash(const void *data, size_t len, const hsiphash_key_t *key);
And::
u32 hsiphash_1u32(u32, const hsiphash_key_t *key);
u32 hsiphash_2u32(u32, u32, const hsiphash_key_t *key);
u32 hsiphash_3u32(u32, u32, u32, const hsiphash_key_t *key);
u32 hsiphash_4u32(u32, u32, u32, u32, const hsiphash_key_t *key);
If you pass the generic hsiphash function something of a constant length, it
will constant fold at compile-time and automatically choose one of the
optimized functions.
Hashtable key function usage
============================
::
struct some_hashtable {
DECLARE_HASHTABLE(hashtable, 8);
hsiphash_key_t key;
};
void init_hashtable(struct some_hashtable *table)
{
get_random_bytes(&table->key, sizeof(table->key));
}
static inline hlist_head *some_hashtable_bucket(struct some_hashtable *table, struct interesting_input *input)
{
return &table->hashtable[hsiphash(input, sizeof(*input), &table->key) & (HASH_SIZE(table->hashtable) - 1)];
}
You may then iterate like usual over the returned hash bucket.
Performance
===========
hsiphash() is roughly 3 times slower than jhash(). For many replacements, this
will not be a problem, as the hashtable lookup isn't the bottleneck. And in
general, this is probably a good sacrifice to make for the security and DoS
resistance of hsiphash().
@@ -0,0 +1,253 @@
======================================================
Confidential Computing in Linux for x86 virtualization
======================================================
.. contents:: :local:
By: Elena Reshetova <elena.reshetova@intel.com> and Carlos Bilbao <carlos.bilbao.osdev@gmail.com>
Motivation
==========
Kernel developers working on confidential computing for virtualized
environments in x86 operate under a set of assumptions regarding the Linux
kernel threat model that differ from the traditional view. Historically,
the Linux threat model acknowledges attackers residing in userspace, as
well as a limited set of external attackers that are able to interact with
the kernel through various networking or limited HW-specific exposed
interfaces (USB, thunderbolt). The goal of this document is to explain
additional attack vectors that arise in the confidential computing space
and discuss the proposed protection mechanisms for the Linux kernel.
Overview and terminology
========================
Confidential Computing (CoCo) is a broad term covering a wide range of
security technologies that aim to protect the confidentiality and integrity
of data in use (vs. data at rest or data in transit). At its core, CoCo
solutions provide a Trusted Execution Environment (TEE), where secure data
processing can be performed and, as a result, they are typically further
classified into different subtypes depending on the SW that is intended
to be run in TEE. This document focuses on a subclass of CoCo technologies
that are targeting virtualized environments and allow running Virtual
Machines (VM) inside TEE. From now on in this document will be referring
to this subclass of CoCo as 'Confidential Computing (CoCo) for the
virtualized environments (VE)'.
CoCo, in the virtualization context, refers to a set of HW and/or SW
technologies that allow for stronger security guarantees for the SW running
inside a CoCo VM. Namely, confidential computing allows its users to
confirm the trustworthiness of all SW pieces to include in its reduced
Trusted Computing Base (TCB) given its ability to attest the state of these
trusted components.
While the concrete implementation details differ between technologies, all
available mechanisms aim to provide increased confidentiality and
integrity for the VM's guest memory and execution state (vCPU registers),
more tightly controlled guest interrupt injection, as well as some
additional mechanisms to control guest-host page mapping. More details on
the x86-specific solutions can be found in
:doc:`Intel Trust Domain Extensions (TDX) </arch/x86/tdx>` and
`AMD Memory Encryption <https://www.amd.com/system/files/techdocs/sev-snp-strengthening-vm-isolation-with-integrity-protection-and-more.pdf>`_.
The basic CoCo guest layout includes the host, guest, the interfaces that
communicate guest and host, a platform capable of supporting CoCo VMs, and
a trusted intermediary between the guest VM and the underlying platform
that acts as a security manager. The host-side virtual machine monitor
(VMM) typically consists of a subset of traditional VMM features and
is still in charge of the guest lifecycle, i.e. create or destroy a CoCo
VM, manage its access to system resources, etc. However, since it
typically stays out of CoCo VM TCB, its access is limited to preserve the
security objectives.
In the following diagram, the "<--->" lines represent bi-directional
communication channels or interfaces between the CoCo security manager and
the rest of the components (data flow for guest, host, hardware) ::
+-------------------+ +-----------------------+
| CoCo guest VM |<---->| |
+-------------------+ | |
| Interfaces | | CoCo security manager |
+-------------------+ | |
| Host VMM |<---->| |
+-------------------+ | |
| |
+--------------------+ | |
| CoCo platform |<--->| |
+--------------------+ +-----------------------+
The specific details of the CoCo security manager vastly diverge between
technologies. For example, in some cases, it will be implemented in HW
while in others it may be pure SW.
Existing Linux kernel threat model
==================================
The overall components of the current Linux kernel threat model are::
+-----------------------+ +-------------------+
| |<---->| Userspace |
| | +-------------------+
| External attack | | Interfaces |
| vectors | +-------------------+
| |<---->| Linux Kernel |
| | +-------------------+
+-----------------------+ +-------------------+
| Bootloader/BIOS |
+-------------------+
+-------------------+
| HW platform |
+-------------------+
There is also communication between the bootloader and the kernel during
the boot process, but this diagram does not represent it explicitly. The
"Interfaces" box represents the various interfaces that allow
communication between kernel and userspace. This includes system calls,
kernel APIs, device drivers, etc.
The existing Linux kernel threat model typically assumes execution on a
trusted HW platform with all of the firmware and bootloaders included on
its TCB. The primary attacker resides in the userspace, and all of the data
coming from there is generally considered untrusted, unless userspace is
privileged enough to perform trusted actions. In addition, external
attackers are typically considered, including those with access to enabled
external networks (e.g. Ethernet, Wireless, Bluetooth), exposed hardware
interfaces (e.g. USB, Thunderbolt), and the ability to modify the contents
of disks offline.
Regarding external attack vectors, it is interesting to note that in most
cases external attackers will try to exploit vulnerabilities in userspace
first, but that it is possible for an attacker to directly target the
kernel; particularly if the host has physical access. Examples of direct
kernel attacks include the vulnerabilities CVE-2019-19524, CVE-2022-0435
and CVE-2020-24490.
Confidential Computing threat model and its security objectives
===============================================================
Confidential Computing adds a new type of attacker to the above list: a
potentially misbehaving host (which can also include some part of a
traditional VMM or all of it), which is typically placed outside of the
CoCo VM TCB due to its large SW attack surface. It is important to note
that this doesn’t imply that the host or VMM are intentionally
malicious, but that there exists a security value in having a small CoCo
VM TCB. This new type of adversary may be viewed as a more powerful type
of external attacker, as it resides locally on the same physical machine
(in contrast to a remote network attacker) and has control over the guest
kernel communication with most of the HW::
+------------------------+
| CoCo guest VM |
+-----------------------+ | +-------------------+ |
| |<--->| | Userspace | |
| | | +-------------------+ |
| External attack | | | Interfaces | |
| vectors | | +-------------------+ |
| |<--->| | Linux Kernel | |
| | | +-------------------+ |
+-----------------------+ | +-------------------+ |
| | Bootloader/BIOS | |
+-----------------------+ | +-------------------+ |
| |<--->+------------------------+
| | | Interfaces |
| | +------------------------+
| CoCo security |<--->| Host/Host-side VMM |
| manager | +------------------------+
| | +------------------------+
| |<--->| CoCo platform |
+-----------------------+ +------------------------+
While traditionally the host has unlimited access to guest data and can
leverage this access to attack the guest, the CoCo systems mitigate such
attacks by adding security features like guest data confidentiality and
integrity protection. This threat model assumes that those features are
available and intact.
The **Linux kernel CoCo VM security objectives** can be summarized as follows:
1. Preserve the confidentiality and integrity of CoCo guest's private
memory and registers.
2. Prevent privileged escalation from a host into a CoCo guest Linux kernel.
While it is true that the host (and host-side VMM) requires some level of
privilege to create, destroy, or pause the guest, part of the goal of
preventing privileged escalation is to ensure that these operations do not
provide a pathway for attackers to gain access to the guest's kernel.
The above security objectives result in two primary **Linux kernel CoCo
VM assets**:
1. Guest kernel execution context.
2. Guest kernel private memory.
The host retains full control over the CoCo guest resources, and can deny
access to them at any time. Examples of resources include CPU time, memory
that the guest can consume, network bandwidth, etc. Because of this, the
host Denial of Service (DoS) attacks against CoCo guests are beyond the
scope of this threat model.
The **Linux CoCo VM attack surface** is any interface exposed from a CoCo
guest Linux kernel towards an untrusted host that is not covered by the
CoCo technology SW/HW protection. This includes any possible
side-channels, as well as transient execution side channels. Examples of
explicit (not side-channel) interfaces include accesses to port I/O, MMIO
and DMA interfaces, access to PCI configuration space, VMM-specific
hypercalls (towards Host-side VMM), access to shared memory pages,
interrupts allowed to be injected into the guest kernel by the host, as
well as CoCo technology-specific hypercalls, if present. Additionally, the
host in a CoCo system typically controls the process of creating a CoCo
guest: it has a method to load into a guest the firmware and bootloader
images, the kernel image together with the kernel command line. All of this
data should also be considered untrusted until its integrity and
authenticity is established via attestation.
The table below shows a threat matrix for the CoCo guest Linux kernel but
does not discuss potential mitigation strategies. The matrix refers to
CoCo-specific versions of the guest, host and platform.
.. list-table:: CoCo Linux guest kernel threat matrix
:widths: auto
:align: center
:header-rows: 1
* - Threat name
- Threat description
* - Guest malicious configuration
- A misbehaving host modifies one of the following guest's
configuration:
1. Guest firmware or bootloader
2. Guest kernel or module binaries
3. Guest command line parameters
This allows the host to break the integrity of the code running
inside a CoCo guest, and violates the CoCo security objectives.
* - CoCo guest data attacks
- A misbehaving host retains full control of the CoCo guest's data
in-transit between the guest and the host-managed physical or
virtual devices. This allows any attack against confidentiality,
integrity or freshness of such data.
* - Malformed runtime input
- A misbehaving host injects malformed input via any communication
interface used by the guest's kernel code. If the code is not
prepared to handle this input correctly, this can result in a host
--> guest kernel privilege escalation. This includes traditional
side-channel and/or transient execution attack vectors.
* - Malicious runtime input
- A misbehaving host injects a specific input value via any
communication interface used by the guest's kernel code. The
difference with the previous attack vector (malformed runtime input)
is that this input is not malformed, but its value is crafted to
impact the guest's kernel security. Examples of such inputs include
providing a malicious time to the guest or the entropy to the guest
random number generator. Additionally, the timing of such events can
be an attack vector on its own, if it results in a particular guest
kernel action (i.e. processing of a host-injected interrupt).
resistant to supplied host input.
@@ -0,0 +1,13 @@
=====================================
Trusted Platform Module documentation
=====================================
.. toctree::
tpm_event_log
tpm-security
tpm_tis
tpm_vtpm_proxy
xen-tpmfront
tpm_ftpm_tee
tpm_ffa_crb
@@ -0,0 +1,216 @@
.. SPDX-License-Identifier: GPL-2.0-only
TPM Security
============
The object of this document is to describe how we make the kernel's
use of the TPM reasonably robust in the face of external snooping and
packet alteration attacks (called passive and active interposer attack
in the literature). The current security document is for TPM 2.0.
Introduction
------------
The TPM is usually a discrete chip attached to a PC via some type of
low bandwidth bus. There are exceptions to this such as the Intel
PTT, which is a software TPM running inside a software environment
close to the CPU, which are subject to different attacks, but right at
the moment, most hardened security environments require a discrete
hardware TPM, which is the use case discussed here.
Snooping and Alteration Attacks against the bus
-----------------------------------------------
The current state of the art for snooping the `TPM Genie`_ hardware
interposer which is a simple external device that can be installed in
a couple of seconds on any system or laptop. Recently attacks were
successfully demonstrated against the `Windows Bitlocker TPM`_ system.
Most recently the same `attack against TPM based Linux disk
encryption`_ schemes. The next phase of research seems to be hacking
existing devices on the bus to act as interposers, so the fact that
the attacker requires physical access for a few seconds might
evaporate. However, the goal of this document is to protect TPM
secrets and integrity as far as we are able in this environment and to
try to insure that if we can't prevent the attack then at least we can
detect it.
Unfortunately, most of the TPM functionality, including the hardware
reset capability can be controlled by an attacker who has access to
the bus, so we'll discuss some of the disruption possibilities below.
Measurement (PCR) Integrity
---------------------------
Since the attacker can send their own commands to the TPM, they can
send arbitrary PCR extends and thus disrupt the measurement system,
which would be an annoying denial of service attack. However, there
are two, more serious, classes of attack aimed at entities sealed to
trust measurements.
1. The attacker could intercept all PCR extends coming from the system
and completely substitute their own values, producing a replay of
an untampered state that would cause PCR measurements to attest to
a trusted state and release secrets
2. At some point in time the attacker could reset the TPM, clearing
the PCRs and then send down their own measurements which would
effectively overwrite the boot time measurements the TPM has
already done.
The first can be thwarted by always doing HMAC protection of the PCR
extend and read command meaning measurement values cannot be
substituted without producing a detectable HMAC failure in the
response. However, the second can only really be detected by relying
on some sort of mechanism for protection which would change over TPM
reset.
Secrets Guarding
----------------
Certain information passing in and out of the TPM, such as key sealing
and private key import and random number generation, is vulnerable to
interception which HMAC protection alone cannot protect against, so
for these types of command we must also employ request and response
encryption to prevent the loss of secret information.
Establishing Initial Trust with the TPM
---------------------------------------
In order to provide security from the beginning, an initial shared or
asymmetric secret must be established which must also be unknown to
the attacker. The most obvious avenues for this are the endorsement
and storage seeds, which can be used to derive asymmetric keys.
However, using these keys is difficult because the only way to pass
them into the kernel would be on the command line, which requires
extensive support in the boot system, and there's no guarantee that
either hierarchy would not have some type of authorization.
The mechanism chosen for the Linux Kernel is to derive the primary
elliptic curve key from the null seed using the standard storage seed
parameters. The null seed has two advantages: firstly the hierarchy
physically cannot have an authorization, so we are always able to use
it and secondly, the null seed changes across TPM resets, meaning if
we establish trust on the null seed at start of day, all sessions
salted with the derived key will fail if the TPM is reset and the seed
changes.
Obviously using the null seed without any other prior shared secrets,
we have to create and read the initial public key which could, of
course, be intercepted and substituted by the bus interposer.
However, the TPM has a key certification mechanism (using the EK
endorsement certificate, creating an attestation identity key and
certifying the null seed primary with that key) which is too complex
to run within the kernel, so we keep a copy of the null primary key
name, which is what is exported via sysfs so user-space can run the
full certification when it boots. The definitive guarantee here is
that if the null primary key certifies correctly, you know all your
TPM transactions since start of day were secure and if it doesn't, you
know there's an interposer on your system (and that any secret used
during boot may have been leaked).
Stacking Trust
--------------
In the current null primary scenario, the TPM must be completely
cleared before handing it on to the next consumer. However the kernel
hands to user-space the name of the derived null seed key which can
then be verified by certification in user-space. Therefore, this chain
of name handoff can be used between the various boot components as
well (via an unspecified mechanism). For instance, grub could use the
null seed scheme for security and hand the name off to the kernel in
the boot area. The kernel could make its own derivation of the key
and the name and know definitively that if they differ from the handed
off version that tampering has occurred. Thus it becomes possible to
chain arbitrary boot components together (UEFI to grub to kernel) via
the name handoff provided each successive component knows how to
collect the name and verifies it against its derived key.
Session Properties
------------------
All TPM commands the kernel uses allow sessions. HMAC sessions may be
used to check the integrity of requests and responses and decrypt and
encrypt flags may be used to shield parameters and responses. The
HMAC and encryption keys are usually derived from the shared
authorization secret, but for a lot of kernel operations that is well
known (and usually empty). Thus, every HMAC session used by the
kernel must be created using the null primary key as the salt key
which thus provides a cryptographic input into the session key
derivation. Thus, the kernel creates the null primary key once (as a
volatile TPM handle) and keeps it around in a saved context stored in
tpm_chip for every in-kernel use of the TPM. Currently, because of a
lack of de-gapping in the in-kernel resource manager, the session must
be created and destroyed for each operation, but, in future, a single
session may also be reused for the in-kernel HMAC, encryption and
decryption sessions.
Protection Types
----------------
For every in-kernel operation we use null primary salted HMAC to
protect the integrity. Additionally, we use parameter encryption to
protect key sealing and parameter decryption to protect key unsealing
and random number generation.
Null Primary Key Certification in Userspace
===========================================
Every TPM comes shipped with a couple of X.509 certificates for the
primary endorsement key. This document assumes that the Elliptic
Curve version of the certificate exists at 01C00002, but will work
equally well with the RSA certificate (at 01C00001).
The first step in the certification is primary creation using the
template from the `TCG EK Credential Profile`_ which allows comparison
of the generated primary key against the one in the certificate (the
public key must match). Note that generation of the EK primary
requires the EK hierarchy password, but a pre-generated version of the
EC primary should exist at 81010002 and a TPM2_ReadPublic() may be
performed on this without needing the key authority. Next, the
certificate itself must be verified to chain back to the manufacturer
root (which should be published on the manufacturer website). Once
this is done, an attestation key (AK) is generated within the TPM and
it's name and the EK public key can be used to encrypt a secret using
TPM2_MakeCredential. The TPM then runs TPM2_ActivateCredential which
will only recover the secret if the binding between the TPM, the EK
and the AK is true. the generated AK may now be used to run a
certification of the null primary key whose name the kernel has
exported. Since TPM2_MakeCredential/ActivateCredential are somewhat
complicated, a more simplified process involving an externally
generated private key is described below.
This process is a simplified abbreviation of the usual privacy CA
based attestation process. The assumption here is that the
attestation is done by the TPM owner who thus has access to only the
owner hierarchy. The owner creates an external public/private key
pair (assume elliptic curve in this case) and wraps the private key
for import using an inner wrapping process and parented to the EC
derived storage primary. The TPM2_Import() is done using a parameter
decryption HMAC session salted to the EK primary (which also does not
require the EK key authority) meaning that the inner wrapping key is
the encrypted parameter and thus the TPM will not be able to perform
the import unless is possesses the certified EK so if the command
succeeds and the HMAC verifies on return we know we have a loadable
copy of the private key only for the certified TPM. This key is now
loaded into the TPM and the Storage primary flushed (to free up space
for the null key generation).
The null EC primary is now generated using the Storage profile
outlined in the `TCG TPM v2.0 Provisioning Guidance`_; the name of
this key (the hash of the public area) is computed and compared to the
null seed name presented by the kernel in
/sys/class/tpm/tpm0/null_name. If the names do not match, the TPM is
compromised. If the names match, the user performs a TPM2_Certify()
using the null primary as the object handle and the loaded private key
as the sign handle and providing randomized qualifying data. The
signature of the returned certifyInfo is verified against the public
part of the loaded private key and the qualifying data checked to
prevent replay. If all of these tests pass, the user is now assured
that TPM integrity and privacy was preserved across the entire boot
sequence of this kernel.
.. _TPM Genie: https://www.nccgroup.trust/globalassets/about-us/us/documents/tpm-genie.pdf
.. _Windows Bitlocker TPM: https://dolosgroup.io/blog/2021/7/9/from-stolen-laptop-to-inside-the-company-network
.. _attack against TPM based Linux disk encryption: https://www.secura.com/blog/tpm-sniffing-attacks-against-non-bitlocker-targets
.. _TCG EK Credential Profile: https://trustedcomputinggroup.org/resource/tcg-ek-credential-profile-for-tpm-family-2-0/
.. _TCG TPM v2.0 Provisioning Guidance: https://trustedcomputinggroup.org/resource/tcg-tpm-v2-0-provisioning-guidance/
@@ -0,0 +1,55 @@
.. SPDX-License-Identifier: GPL-2.0
=============
TPM Event Log
=============
This document briefly describes what TPM log is and how it is handed
over from the preboot firmware to the operating system.
Introduction
============
The preboot firmware maintains an event log that gets new entries every
time something gets hashed by it to any of the PCR registers. The events
are segregated by their type and contain the value of the hashed PCR
register. Typically, the preboot firmware will hash the components to
who execution is to be handed over or actions relevant to the boot
process.
The main application for this is remote attestation and the reason why
it is useful is nicely put in the very first section of [1]:
"Attestation is used to provide information about the platform’s state
to a challenger. However, PCR contents are difficult to interpret;
therefore, attestation is typically more useful when the PCR contents
are accompanied by a measurement log. While not trusted on their own,
the measurement log contains a richer set of information than do the PCR
contents. The PCR contents are used to provide the validation of the
measurement log."
UEFI event log
==============
UEFI provided event log has a few somewhat weird quirks.
Before calling ExitBootServices() Linux EFI stub copies the event log to
a custom configuration table defined by the stub itself. Unfortunately,
the events generated by ExitBootServices() don't end up in the table.
The firmware provides so called final events configuration table to sort
out this issue. Events gets mirrored to this table after the first time
EFI_TCG2_PROTOCOL.GetEventLog() gets called.
This introduces another problem: nothing guarantees that it is not called
before the Linux EFI stub gets to run. Thus, it needs to calculate and save the
final events table size while the stub is still running to the custom
configuration table so that the TPM driver can later on skip these events when
concatenating two halves of the event log from the custom configuration table
and the final events table.
References
==========
- [1] https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/
- [2] The final concatenation is done in drivers/char/tpm/eventlog/efi.c
@@ -0,0 +1,65 @@
.. SPDX-License-Identifier: GPL-2.0
========================
TPM CRB over FF-A Driver
========================
The TPM Command Response Buffer (CRB) interface is a standard TPM interface
defined in the TCG PC Client Platform TPM Profile (PTP) Specification [1]_.
The CRB provides a structured set of control registers a client uses when
interacting with a TPM as well as a data buffer for storing TPM commands and
responses. A CRB interface can be implemented in:
- hardware registers in a discrete TPM chip
- in memory for a TPM running in isolated environment where shared memory
allows a client to interact with the TPM
The Firmware Framework for Arm A-profile (FF-A) [2]_ is a specification
that defines interfaces and protocols for the following purposes:
- Compartmentalize firmware into software partitions that run in the Arm
Secure world environment (also know as TrustZone)
- Provide a standard interface for software components in the Non-secure
state, for example OS and Hypervisors, to communicate with this firmware.
A TPM can be implemented as an FF-A secure service. This could be a firmware
TPM or could potentially be a TPM service that acts as a proxy to a discrete
TPM chip. An FF-A based TPM abstracts hardware details (e.g. bus controller
and chip selects) away from the OS and can protect locality 4 from access
by an OS. The TCG-defined CRB interface is used by clients to interact
with the TPM service.
The Arm TPM Service Command Response Buffer Interface Over FF-A [3]_
specification defines FF-A messages that can be used by a client to signal
when updates have been made to the CRB.
How the Linux CRB driver interacts with FF-A is summarized below:
- The tpm_crb_ffa driver registers with the FF-A subsystem in the kernel
with an architected TPM service UUID defined in the CRB over FF-A spec.
- If a TPM service is discovered by FF-A, the probe() function in the
tpm_crb_ffa driver runs, and the driver initializes.
- The probing and initialization of the Linux CRB driver is triggered
by the discovery of a TPM advertised via ACPI. The CRB driver can
detect the type of TPM through the ACPI 'start' method. The start
method for Arm FF-A was defined in TCG ACPI v1.4 [4]_.
- When the CRB driver performs its normal functions such as signaling 'start'
and locality request/relinquish it invokes the tpm_crb_ffa_start() funnction
in the tpm_crb_ffa driver which handles the FF-A messaging to the TPM.
References
==========
.. [1] **TCG PC Client Platform TPM Profile (PTP) Specification**
https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/
.. [2] **Arm Firmware Framework for Arm A-profile (FF-A)**
https://developer.arm.com/documentation/den0077/latest/
.. [3] **Arm TPM Service Command Response Buffer Interface Over FF-A**
https://developer.arm.com/documentation/den0138/latest/
.. [4] **TCG ACPI Specification**
https://trustedcomputinggroup.org/resource/tcg-acpi-specification/
@@ -0,0 +1,27 @@
=============================================
Firmware TPM Driver
=============================================
This document describes the firmware Trusted Platform Module (fTPM)
device driver.
Introduction
============
This driver is a shim for firmware implemented in ARM's TrustZone
environment. The driver allows programs to interact with the TPM in the same
way they would interact with a hardware TPM.
Design
======
The driver acts as a thin layer that passes commands to and from a TPM
implemented in firmware. The driver itself doesn't contain much logic and is
used more like a dumb pipe between firmware and kernel/userspace.
The firmware itself is based on the following paper:
https://www.microsoft.com/en-us/research/wp-content/uploads/2017/06/ftpm1.pdf
When the driver is loaded it will expose ``/dev/tpmX`` character devices to
userspace which will enable userspace to communicate with the firmware TPM
through this device.
@@ -0,0 +1,46 @@
.. SPDX-License-Identifier: GPL-2.0
=========================
TPM FIFO interface driver
=========================
TCG PTP Specification defines two interface types: FIFO and CRB. The former is
based on sequenced read and write operations, and the latter is based on a
buffer containing the full command or response.
FIFO (First-In-First-Out) interface is used by the tpm_tis_core dependent
drivers. Originally Linux had only a driver called tpm_tis, which covered
memory mapped (aka MMIO) interface but it was later on extended to cover other
physical interfaces supported by the TCG standard.
For historical reasons above the original MMIO driver is called tpm_tis and the
framework for FIFO drivers is named as tpm_tis_core. The postfix "tis" in
tpm_tis comes from the TPM Interface Specification, which is the hardware
interface specification for TPM 1.x chips.
Communication is based on a 20 KiB buffer shared by the TPM chip through a
hardware bus or memory map, depending on the physical wiring. The buffer is
further split into five equal-size 4 KiB buffers, which provide equivalent
sets of registers for communication between the CPU and TPM. These
communication endpoints are called localities in the TCG terminology.
When the kernel wants to send commands to the TPM chip, it first reserves
locality 0 by setting the requestUse bit in the TPM_ACCESS register. The bit is
cleared by the chip when the access is granted. Once it completes its
communication, the kernel writes the TPM_ACCESS.activeLocality bit. This
informs the chip that the locality has been relinquished.
Pending localities are served in order by the chip in descending order, one at
a time:
- Locality 0 has the lowest priority.
- Locality 5 has the highest priority.
Further information on the purpose and meaning of the localities can be found
in section 3.2 of the TCG PC Client Platform TPM Profile Specification.
References
==========
TCG PC Client Platform TPM Profile (PTP) Specification
https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/
@@ -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
@@ -0,0 +1,124 @@
=============================
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.