linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/13] Implement Trusted Security Event Modeling.
@ 2023-07-10 10:23 Dr. Greg
  2023-07-10 10:23 ` [PATCH 01/13] Update MAINTAINERS file Dr. Greg
                   ` (12 more replies)
  0 siblings, 13 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

Good morning, I hope this note finds the week starting well for
everyone.

This is the second release of a patch series that implements
Trusted Security Event Modeling (TSEM) as a new Linux Security
Module (LSM) architecture.

TSEM provides kernel infrastructure for implementing security
controls based on either deterministic or machine learning
models.  It also provides a framework for implementing Host Based
Intrusion Detection (HIDS) and/or anomaly detection architectures
without the need to write kernel code or implement kernel
modules.

TSEM is designed to support the concept of a Trust Orchestration
System (TOS).  Trust orchestration involves the process of
modeling the security behavior of a workload, or a platform at
large, and defining whether or not a process is to be trusted,
based on whether or not the security events produced are
consistent with a security model that has been unit tested for a
workload or platform.

TSEM operates under the premise, that security, like all other
physical phenomena in science and engineering, can be
mathematically modeled.  TSEM notionally treats the LSM security
event hooks as a basis set of parameters that are capable of
generating a functional value for the security state of a system.

TSEM, in and of itself, does not implement security policy.  That
capability is invested in an entity known as a Trusted Modeling
Agent (TMA).  A TMA can be implemented in the kernel itself or
the security event descriptions can be exported to userspace for
processing in a non-kernel based TMA.

To support this architecture, TSEM implements entirely within the
context of the LSM architecture, the concept of security modeling
namespaces that are akin to other resource namespaces.  A
security modeling namespace is paired with a TMA that implements
the root of trust for a security modeling namespace.

A TMA implementation uses the characteristics of the calling
process and the descriptive parameters of a security event to
compute coefficients for each security event that occurs in a
security modeling namespace.  The sum of these coefficients,
represents the security 'state' of the model.

TSEM supports any number of security modeling namespaces that act
independently of one another and of the root security modeling
namespace.  Each namespace can be configured with its own unique
security model definition that can be configured to be modeled
internally or externally.  The cryptographic hash function used
to generate the security state coefficients can be configured at
the namespace level as can the source of resolution for UID/GID
values.

Security models to be enforced by a trust orchestrator in a
security modeling namespace are developed by unit testing of a
workload.  These security models are designed to be distributed
as a manifest that defines the desired security behavior of a
workload.

TSEM represents a security architecture that is designed to be
driven by modern software development strategies that embrace
resource containerization and continuous integration and delivery
principles.  The objective of TSEM, along with the Quixote TOS
implementation, is to bring to Linux security architecture what
Docker brought to Linux resource namespaces.

Included in the patch series is an extensive documentation file that
can be found in the following location after the series is applied:

Documentation/admin-guide/LSM/tsem.rst

Reviewers, and others who are interested, are referred to this
document for a more extensive discussion into the rationale,
design and implementation of the TSEM architecture.

Control of TSEM is surfaced entirely in the securityfs filesystem
through the following directory heirarchy:

/sys/kernel/security/tsem

TSEM is designed to be largely self-contained and independent of
the kernel at large and with other LSM's with which it stacks.
It operates without the need for filesystem labeling or
cryptographic integrity protection of filesystem metadata.

The TSEM in-kernel TMA implements a very simple deterministic
security model.  Moving forward, the TSEM architecture is
designed to provide a flexible framework to support the
implementation of more advanced models that use stochastics,
inference and generative machine learning.

Version 1.5 of the Quixote userspace utilities that support this
TSEM kernel release can be obtained from the following URL:

ftp://ftp.enjellic.com/pub/Quixote

In addition to source there is a binary utility package that has
been compiled and statically linked with MUSL libc that should
install and run, without dependencies, on any TSEM enabled
kernel.

Included are implementations of trust orchestrator's for the
following TMA trust roots:

Kernel.

Userspace process.

SGX enclave.

Xen hypervisor stub-domain.

Hardware based security coprocessors.

Among the objectives of Quixote/TSEM is to provide a framework
for developing next generation hardware assisted security
co-processor technology that extends beyond what is currently
represented in the form of Trusted Platform Modules.

Included with the Quixote TOS is an implementation of a security
co-processor based on the Nordic NRF52840-DONGLE
micro-controller.  This is a 32-bit ARM based USB form factor
device that is currently being used for projects such as GOOGLE's
OpenSK security key initiative and 3mdeb's Fobnail attestation
server project.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity

V1:
- Initial release.	  

V2:
- V1: https://lore.kernel.org/linux-security-module/20230204050954.11583-1-greg@enjellic.com/T/#t
- Allow compile time configuration of the Platform Configuration
  Register used to extend security coefficients in the root
  security modeling namespace.
- Allow both internal and external modeling of security events
  that are called in atomic context.
- Use JSON to encode security event characteristics.
- Use securityfs for TSEM control plane rooted at
  /sys/kernel/security/tsem.
- Use framework of separate directories for internal TMA's to
  protect ABI compatability.
- Use key=value arguments for control plane commands.
- Allow cryptographic hash function used for coefficient
  generation to be configured on a namespace by namespace basis.
- Allow selection of initial or current user namespace as the
  reference for UID/GID resolution to be configured on a namespace
  by namespace basis.
- Allow the size of modeling and export structures to be configured
  on a namespace by namespace basis.
- Extensively document all globally visible enumerations and structures.
- Use CAP_ML rather than CAP_TRUST for modeling capability bit.
- Implement orchestrator<->process mutual authentication.
- Implement occupancy counts for security state coefficients.
- Move TSEM to the first LSM in the LSM list.

Dr. Greg (13):
  Update MAINTAINERS file.
  Add TSEM specific documentation.
  Implement CAP_TRUST capability.
  Add TSEM master header file.
  Add primary TSEM implementation file.
  Add root domain trust implementation.
  Implement TSEM control plane.
  Add namespace implementation.
  Add security event description export facility.
  Add event description implementation.
  Implement security event mapping.
  Implement an internal Trusted Modeling Agent.
  Activate the configuration and build of the TSEM LSM.

 Documentation/ABI/testing/tsem                |  828 +++++++
 Documentation/admin-guide/LSM/index.rst       |    1 +
 Documentation/admin-guide/LSM/tsem.rst        | 1526 +++++++++++++
 .../admin-guide/kernel-parameters.txt         |   18 +
 MAINTAINERS                                   |    8 +
 include/uapi/linux/capability.h               |    6 +-
 security/Kconfig                              |   11 +-
 security/Makefile                             |    1 +
 security/selinux/include/classmap.h           |    2 +-
 security/tsem/Kconfig                         |   36 +
 security/tsem/Makefile                        |    2 +
 security/tsem/event.c                         |  669 ++++++
 security/tsem/export.c                        |  394 ++++
 security/tsem/fs.c                            | 1336 +++++++++++
 security/tsem/map.c                           |  531 +++++
 security/tsem/model.c                         |  714 ++++++
 security/tsem/namespace.c                     |  347 +++
 security/tsem/trust.c                         |  220 ++
 security/tsem/tsem.c                          | 1987 +++++++++++++++++
 security/tsem/tsem.h                          | 1516 +++++++++++++
 20 files changed, 10146 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/ABI/testing/tsem
 create mode 100644 Documentation/admin-guide/LSM/tsem.rst
 create mode 100644 security/tsem/Kconfig
 create mode 100644 security/tsem/Makefile
 create mode 100644 security/tsem/event.c
 create mode 100644 security/tsem/export.c
 create mode 100644 security/tsem/fs.c
 create mode 100644 security/tsem/map.c
 create mode 100644 security/tsem/model.c
 create mode 100644 security/tsem/namespace.c
 create mode 100644 security/tsem/trust.c
 create mode 100644 security/tsem/tsem.c
 create mode 100644 security/tsem/tsem.h

-- 
2.39.1


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 01/13] Update MAINTAINERS file.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-07-10 20:00   ` Randy Dunlap
  2023-07-10 10:23 ` [PATCH 02/13] Add TSEM specific documentation Dr. Greg
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

Add an entry to the MAINTAINERS file to document the maintainer's
address and files relevant to the Trusted Security Event Modeling
system (TSEM).

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 35e19594640d..4660c972d5e3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19026,6 +19026,14 @@ F:	include/uapi/linux/selinux_netlink.h
 F:	scripts/selinux/
 F:	security/selinux/
 
+TSEM SECURITY MODULE
+M:	Greg Wettstein <greg@enjellic.com>
+S:	Maintained
+L:	linux-security-module@vger.kernel.org
+F:	Documentation/admin-guide/LSM/tsem.rst
+F:	Documentation/ABI/testing/tsemfs
+F:	security/tsem/
+
 SENSABLE PHANTOM
 M:	Jiri Slaby <jirislaby@kernel.org>
 S:	Maintained
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 02/13] Add TSEM specific documentation.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
  2023-07-10 10:23 ` [PATCH 01/13] Update MAINTAINERS file Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-07-11  4:37   ` Randy Dunlap
                     ` (2 more replies)
  2023-07-10 10:23 ` [PATCH 03/13] Implement CAP_TRUST capability Dr. Greg
                   ` (10 subsequent siblings)
  12 siblings, 3 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

An entry was added to the ABI testing documentation to document
the files in the TSEM management filesystem.

The file documenting the kernel command-line parameters was
updated to document the TSEM specific command-line parameters

The primary TSEM documentation file was added to the LSM
administration guide and the file was linked to the index of LSM
documentation.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 Documentation/ABI/testing/tsem                |  828 +++++++++
 Documentation/admin-guide/LSM/index.rst       |    1 +
 Documentation/admin-guide/LSM/tsem.rst        | 1526 +++++++++++++++++
 .../admin-guide/kernel-parameters.txt         |   18 +
 4 files changed, 2373 insertions(+)
 create mode 100644 Documentation/ABI/testing/tsem
 create mode 100644 Documentation/admin-guide/LSM/tsem.rst

diff --git a/Documentation/ABI/testing/tsem b/Documentation/ABI/testing/tsem
new file mode 100644
index 000000000000..cfb013b5f1f4
--- /dev/null
+++ b/Documentation/ABI/testing/tsem
@@ -0,0 +1,828 @@
+What:		/sys/kernel/security/tsem
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The /sys/kernel/security/tsem directory contains files
+		and directories that implement the control plane for
+		the Trusted Security Event Modeling (TSEM) LSM.
+
+		The files in this directory hierarchy, with the
+		exception of the aggregate file, when read, reflect
+		the values for the security modeling namespace that
+		the process reading the files is operating in.
+
+What:		/sys/kernel/security/tsem/id
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The id file contains the ASCII base 10 representation
+		of the model domain/namespace identifier that the
+		reading process is operating in.
+
+		The root security modeling namespace has a value of
+		zero, a non-zero value indicates a modeling namespace
+		subordinate to the root model.
+
+		Each externally modeled domain will have a file, with
+		this id number, created in the
+		/sys/kernel/security/tsem/ExternalTMA directory that
+		is documented below.
+
+What:		/sys/kernel/security/tsem/aggregate
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The aggregate file contains the ASCII base 16
+		representation of the 256 bit hardware platform
+		aggregate that TSEM is modeling under.  The platform
+		aggregate is the linear extension measurement of the
+		Trusted Platform Module PCR registers 0 through 8.
+
+		On a platform without a TPM this value will be all
+		null bytes.
+
+What:		/sys/kernel/security/tsem/control
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The control file is the only writable file in the
+		filesystem and is used by the trust orchestrator's to
+		configure and control the behavior of the TSEM
+		implementation.
+
+		The following keyword and arguments are recognized:
+
+		internal
+			The internal keyword causes an internally
+			modeled domain to be created for the calling
+			process.
+
+		external
+			The external keyword causes an externally
+			modeled domain to be created for the calling
+			process.
+
+			A modeling namespace created by these commands
+			accept the following set of key=value pairs
+			that configure the namespace:
+
+			nsref=initial|current
+				The nsref key specifies the namespace
+				that is to be referenced when
+				determining the UID/GID values that
+				define a COE or CELL identity.
+
+				The initial keyword specifies that the
+				initial user namespace be used.  The
+				current keyword specifies that the
+				user namespace of the process that is
+				invoking a security event handler
+				(hook) is used.
+
+			digest=digestname
+				The digest key is used to specify the
+				cryptographic hash function that is to
+				be used in the namespace for the
+				creation of COE and CELL identities.
+
+				The digestname is the name used by the
+				Linux kernel cryptographic API to
+				identify the hash function.  Examples
+				would include sha256, sha3-256, sm3
+				etc.  The source files for the
+				cryptographic hash function in the crypto
+				directory of the kernel source has the
+				names for hash functions implemented
+				in the kernel.
+
+				The sha256 hash function is the
+				default function for the root modeling
+				domain.  This can be modified by the
+				tsem_digest command-line parameter.
+
+				A hash function, used by the root
+				modeling domain, must be built into
+				the kernel.
+
+			cache=NN
+				The cache key specifies the size of
+				the caches to be used for holding
+				pointers to structures used for the
+				modeling or export of security events
+				that are called while the invoking
+				process is in atomic context.
+
+				The value NN is the ASCII base 10
+				representation of the number of
+				entries in the cache.
+
+				By default, the root modeling
+				namespace and an externally modeled
+				namespace will have 96 entries.  An
+				internally modeled namespace will have
+				16 entries.
+
+			key=HEXID
+				The key argument is used to specify
+				the authentication key that will be
+				used by a trust orchestrator to
+				authenticate trust control requests to
+				a process running in the security
+				modeling namespace.
+
+				The HEXID value is the ASCII base16
+				encoded key that is to be used.  The
+				length of this key, in binary, must be
+				equal to the size of the digest
+				produced by the cryptographic hash
+				function that is being used in the
+				modeling namespace.
+
+		enforce
+			The enforce keyword causes the modeling
+			domain/namespace of the process to enter
+			enforcing mode.  In this mode, a value of
+			-EPERM will be returned for a security event
+			coefficient that does not map into the current
+			set of allowed coefficients for the security
+			model being implemented in the namespace.
+
+		seal
+			The seal keyword causes the security model
+			being implemented for the namespace to be
+			placed in a sealed state.  In this state, the
+			current set of security coefficients is
+			considered to be the only set of valid
+			coefficients for the model.  Any subsequent
+			events that map to a coefficient not in the
+			current model will be considered a violation
+			of the model.
+
+		trusted pid=PID key=HEXID
+			The trusted keyword is used by a trust
+			orchestrator to indicate that the process
+			identified by the PID argument should be
+			allowed to run in trusted status after the
+			modeling of a security event.
+
+			The HEXID argument is the authentication key
+			that has been configured by a trust
+			orchestrator for the namespace at the time of
+			its creation.
+
+		untrusted pid=PID key=HEXID
+			The untrusted keyword is used by a trust
+			orchestrator to indicate that the process
+			identified by the PID argument should be
+			designated as an untrusted process.
+
+			The HEXID argument is the authentication key
+			that has been configured by a trust
+			orchestrator for the namespace at the time
+			its creation.
+
+		state value=HEXID
+			The state keyword is used to indicate that the
+			security state coefficient identified by the
+			ASCII base 16 encoded value specified by HEXID
+			should be loaded into the current security
+			model as a valid security event coefficient.
+
+		pseudonym valid=HEXID
+			The pseudonym keyword is used to indicate that
+			the pathname, identified by the ASCII base 16
+			encoded value HEXID, should be designated to
+			return a constant digest value for the
+			contents of the file named by the pseudonym.
+
+			The HEXID value is computed with the following
+			function:
+
+			HEXID = HF(PATHNAME_LENGTH || PATHNAME)
+
+			WHERE HF is the cryptographic hash function
+			that has been designated for use by the
+			security modeling namespace.
+
+		base value=HEXID
+			The base keyword is used to indicate that the
+			ASCII base 16 encoded value HEXID should be
+			registered as the value used to generate
+			security state coefficients for the model
+			implemented in the modeling namespace.
+
+			The binary length of the value specified by
+			HEXID must match the digest size of the
+			cryptographic hash function specified for use
+			in the security modeling namespace.
+
+			A model specific base value is designed to be
+			used as a 'freshness' nonce, similar to an
+			attestation nonce, to prove that a model state
+			value or measurement is current and not being
+			replayed.
+
+What:		/sys/kernel/security/tsem/InternalTMA
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+
+		This directory will contain directories that will be
+		used to hold files that surface model parameters for
+		Trusted Modeling Agents (TMA's) for internally modeled
+		security namespaces.
+
+		There is currently only one internal TMA that is
+		surfaced through the following directory:
+
+		/sys/kernel/security/tsem/InternalTMA/model0
+
+		The subsequent descriptions for the files implemented
+		in this directory will use ROOTDIR to represent the
+		above directory for space conservation purposes.
+
+What:		ROOTDIR/measurement
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The measurement file contains the ASCII base 16
+		representation of the time dependent linear extension
+		value of all the security state coefficients in the
+		model implemented by the namespace of the calling
+		process.
+
+What:		ROOTDIR/state
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The state file contains the ASCII base 16
+		representation of the functional value of a security
+		modeling namespace.
+
+		The state value is a time independent representation
+		of the measurement of a security model, and unlike the
+		measurement value, is a time independent
+		representation of the state.
+
+		This value is designed to be a single value that can
+		be attested to represent whether or not a workload has
+		deviated from a defined security behavior.
+
+What:		ROOTDIR/trajectory
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The trajectory file contains a description of the
+		security events that have occurred in a security
+		modeling namespace
+
+		Each entry in this file represents a single security
+		event and consists of a JSON encoded record with key
+		values that define the characteristics of the event.
+
+		Each line in a trajectory, or forensics, file will
+		always have the event and COE keys.  The event key
+		describes the characteristics of a security event
+		while the COE field describes the Context Of Execution
+		that is requesting execution of a security event.
+
+		The event key consists of the following
+		characteristic definitions:
+
+			process: COMM
+				Where COMM is the ASCII representation
+				of the name of the process executing
+				the event.
+
+			type: EVENT_TYPE
+				The value field for a type key is the
+				name of the security event that is
+				being modeled.  The list of EVENT_TYPE
+				names is defined in the following
+				source file:
+
+				security/tsem/tsem.c
+
+				If the security event is a generically
+				modeled event the EVENT_TYPE will be
+				generic_event.  In this case the CELL
+				characteristics for the event will be
+				described by a generic_event: key
+
+			task_id: HEXID
+				The value of the task_id key will the
+				ASCII base 16 representation of the
+				identity of the task that is executing
+				the security handler.  The length of
+				HEXID will match the size of the
+				digest value of the cryptographic hash
+				function selected for use by the
+				security modeling namespace.
+
+				The following documentation file:
+
+				Documentation/admin-guide/LSM/TSEM.rst
+
+				Describes how the TASK_ID value is
+				generated.
+
+		The COE key has the following characteristic keys.
+		Keys that involve discretionary access values
+		(uids/gids) will have their numeric value computed
+		based on the user namespace reference value that is
+		being implemented in the security modeling namespace.
+
+			uid: NN
+				The ASCII base 10 representation of
+				the numeric value of the discretionary
+				user id of the process that is
+				executing the security event.
+
+			euid: NN
+				The ASCII base 10 representation of
+				the numeric value of the effective
+				discretionary user id of the process
+				that is executing the security event.
+
+			euid: NN
+				The ASCII base 10 representation of
+				the numeric value of the effective
+				discretionary user id of the process
+				that is executing the security event.
+
+			suid: NN
+				The ASCII base 10 representation of
+				the numeric value of the saved user id
+				of the process that is executing the
+				security event.
+
+			gid: NN
+				The ASCII base 10 representation of
+				the numeric value of the discretionary
+				group id of the process that is
+				executing the security event.
+
+			egid: NN
+				The ASCII base 10 representation of
+				the numeric value of the discretionary
+				effective group id of the process that
+				is executing the security event.
+
+			egid: NN
+				The ASCII base 10 representation of
+				the numeric value of the discretionary
+				effective group id of the process that
+				is executing the security event.
+
+			sgid: NN
+				The base 10 ASCII representation of
+				the numeric value of the saved
+				discretionary group id of the process
+				that is executing the security event.
+
+			fsuid: NN
+				The base 10 ASCII representation of
+				the numeric value of the discretionary
+				filesystem user id of the process that
+				is executing the security event.
+
+			fsgid: NN
+				The ASCII base 10 representation of
+				the numeric value of the discretionary
+				filesystem group id of the process
+				that is executing the security event.
+
+			capeff: 0xNNN
+				The ASCII base 16 representation of
+				the numeric value of effective
+				capabilities of the process that is
+				executing the security event.
+
+		If the CELL value for a security event includes the
+		definition of a file a file: key value will be
+		included.  The following characteristics will be
+		encoded in this field:
+
+			flags: NN
+				The ASCII base 10 representation of
+				the flags value of the 'struct file'
+				structure that is the source of the
+				file description.
+
+			uid: NN
+				The ASCII base 10 representation of
+				the discretionary user id of the file.
+
+			gid: NN
+				The base 10 ASCII representation of
+				the discretionary group id of the
+				file.
+
+			mode: 0NNN
+				The ASCII base 8 representation of the
+				mode bits of the file.
+
+			name_length: NN
+				The ASCII base 10 representation of
+				the length of the pathname that will
+				be encoded in the name= characteristic.
+
+			name: NN
+				The ASCII hexadecimal representation
+				of the SHA256 checksum of the pathname
+				of the file that is pre-pended with
+				the little-endian binary value of the
+				length of the pathname.
+
+			s_magic: 0xNN
+				The ASCII base 16 representation of the
+				magic number of the filesystem that
+				contains the file.
+
+			s_id: NAME
+				The ASCII name of the block device for
+				the filesystem that contains the file.
+
+			s_UUID: HEX
+				The ASCII base 16 representation of
+				the hexadecimal value of the UUID of
+				the filesystem that contains the file.
+
+			digest: HEX
+				The ASCII base 16 representation of
+				the SHA256 digest of the file.
+
+		If the event type is the memory mapping of a file a
+		mmap_file key value will be included with
+		the following characteristics:
+
+			type: N
+				Where N is an ASCII 0 or 1 to indicate
+				whether or not the mapping is file
+				backed or anonymous.  A value of 1 is
+				used to indicate an anonymous mapping.
+
+			reqprot: NN
+				Where N is ASCII base 10
+				representation of the protections
+				requested for the mapping.
+
+			prot: NN
+				Where N is the ASCII base 10
+				representation of the protections that
+				will be applied to the mapping.
+
+			flags: NN
+				Where N is the ASCII base 10
+				representation of the flags that will
+				be used for the memory mapping operation.
+
+		If the event type is a socket creation event a
+		socket_create key value will be included with the
+		following characteristics:
+
+			family: N
+				Where N is the ASCII base 10
+				representation of the family type of
+				the socket.
+
+			type: N
+				Where N is the ASCII base 10
+				representation of the type of socket
+				being created.
+
+			protocol: N
+				Where N is the ASCII base 10
+				representation of the protocol family
+				for the socket.
+
+			kern: 0 | 1
+				Where 0 or 1 is used to indicate
+				whether or not the socket is kernel
+				based.  A value of 1 implies it is
+				kernel based.
+
+		If the event type is a socket_connect or a
+		socket_bind, a socket_connect: or a socket_bind: key
+		value will be included that will be characterized
+		based on an encoding of either an IPV4, IPV6, AF_UNIX
+		or a generic socket description.
+
+			family: N
+				Where N is the ASCII base 10
+				representation of the family type of
+				the socket.
+
+			port: N
+				Where N is the base ASCII base 10
+				representation of the port number that
+				is being used for either an IPV4 or
+				IPV6 socket connection or bind.
+
+			addr: N | PATH | HEXID
+				In the case of an IPV4 socket the
+				value for the addr key will be the
+				ASCII base 10 representation of the 32
+				bit IPV4 address being bound or
+				connected to.
+
+				In the case of an IPV6 connection the
+				value to the key will be the ASCII
+				base 16 representation of the 128 bit
+				address being bound connected.
+
+				In the case of an AF_UNIX connection
+				the value will be the pathname of the
+				socket in the mount namespace that the
+				process is running in.
+
+				In the case of any other type of
+				socket the addr value will be the
+				ASCII base 16 representation of the
+				cryptographic digest value of the
+				entire length of the address
+				description.  The length of the
+				representation will be the size of the
+				digest produced by the cryptographic
+				hash function that has been specified
+				for the modeling namespace.
+
+			flow: N
+				For an IPV6 socket the value of the
+				flow key will be the ASCII base 10
+				representation of the flow identifier
+				assigned to the socket.
+
+			scope: N
+				For an IPV6 socket the value of the
+				scope key will be the ASCII base 10
+				representation of the scope identifier
+				assigned to the socket.
+
+		If the event type is a socket_accept a socket_accept
+		key value will be included that characterizes either
+		an IPV4, IPV6 or a generic socket description with the
+		following event descriptions:
+
+			family: N
+				Where N is the ASCII base 10
+				representation of the family type of
+				the socket.
+
+			type: N
+				Where N is the ASCII base 10
+				representation of the type of the
+				socket being created.
+
+			port: N
+				Where N is the base ASCII base 10
+				representation of the port number that
+				is being used for either an IPV4 or
+				IPV6 socket connection or bind.
+
+			addr: N | PATH | HEXID
+				In the case of an IPV4 socket the
+				value for the addr key will be the
+				ASCII base 10 representation of the 32
+				bit IPV4 address being bound or
+				connected to.
+
+				In the case of an IPV6 connection the
+				value to the key will be the ASCII
+				base 16 representation of the 128 bit
+				address being bound connected.
+
+				In the case of an AF_UNIX connection
+				the value will be the pathname of the
+				socket in the mount namespace that the
+				process is running in.
+
+				In the case of any other type of
+				socket the addr value will be the
+				ASCII base 16 representation of the
+				cryptographic digest value of the
+				entire length of the address
+				description.  The length of the
+				representation will be the size of the
+				digest produced by the cryptographic
+				hash function that has been specified
+				for the modeling namespace.
+
+What:		ROOTDIR/trajectory_coefficients
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The trajectory_coefficients file will output the ASCII
+		base16 representation of each security state
+		coefficient that has been generated by the security
+		modeling namespace of the calling process.
+
+		The length of each point will be the ASCII
+		representation of the size of the cryptographic hash
+		function that has been specified for the model.
+
+What:		ROOTDIR/trajectory_counts
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The trajectory_coefficients file will output the ASCII
+		base10 representation of the number of times each
+		security state coefficient has been generated by the
+		security modeling namespace of the calling process.
+
+What:		ROOTDIR/forensics
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The forensics file contains the descriptions of
+		security events that are inconsistent with the
+		security model that the security namespace is
+		implementing.  Forensics events are generated after a
+		security model is 'sealed' and the events represent
+		security state coefficients that have not already been
+		generated by the model.
+
+		The format of lines in this file are identical to the
+		output generated by the ROOTDIR/trajectory file
+		that is documented above.
+
+What:		ROOTDIR/forensics_coefficients
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The forensics_coefficients file will output the ASCII
+		base16 representation of each security state
+		coefficient that have been generated by forensics
+		events in the security modeling namespace of the
+		calling process.
+
+		The length of each point will be the ASCII
+		representation of the size of the cryptographic hash
+		function that has been specified for the model.
+
+What:		ROOTDIR/forensics_counts
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The forensics_counts file will output the ASCII base10
+		representation of the number of times each security
+		state coefficient, generated by a forensics event, has
+		been generated by the security modeling namespace of
+		the calling process.
+
+What:		/sys/kernel/security/tsem/ExternalTMA
+Date:		July 2023
+Contact:	Greg Wettstein <greg@enjellic.com>
+Description:
+		The ExternalTMA directory is a container directory
+		that hold files that will be used to export the
+		security events, and their associated parameters, for
+		externally modeled security modeling namespaces.
+
+		The files created in this directory will be named by
+		the base 10 ASCII representation of the id value
+		assigned to the security modeling namespace.  See the
+		documentation for the /sys/kernel/security/tsem/id
+		file in this documentation for more details on this
+		value.
+
+		This file will is a read-only file that can be polled
+		by a userspace trust orchestrator implementation to
+		process security events that are to be modeled by an
+		external Trusted Modeling Agent.
+
+		Each exported event is a JSON encoded record
+		describing the event that is to be processed.
+
+		Each record will have an 'export' key that has a
+		structure associated with it that has a 'type' key in
+		it.  The 'type' key has a string value associated with
+		it that defines the type of event that is being
+		processed.
+
+		The following export 'type' strings are defined:
+
+		aggregate:
+			The aggregate key has an associated structure
+			value that defines a key named 'value' that
+			has a string value associated with it that
+			represents the hardware aggregate for the
+			platform.
+
+			The hardware aggregate string is expressed as
+			the ASCII base16 representation of the
+			platform hardware aggregate value.  The length
+			of the string will be the size of the digest
+			produced by the cryptographic hash function
+			that has been specified for the security
+			modeling namespace of the process generating
+			the event.
+
+		async_event:
+			If the type of the export is async_event there
+			will be a key named 'event' that has a structure
+			value associated with it.
+
+			The structure associated with the 'event' key
+			will be identical to the structure generated
+			for the 'event' key that is described below.
+
+		event:
+			If the type of the export is event there will
+			be a key named 'event' that has a structure
+			value associated with it that contains the
+			follow key: value pairs.
+
+			pid: NNN
+				Where the NNN is the ASCII base 10
+				value of the id of the process that is
+				executing the security event that will
+				be modeled.
+
+			process: COMM
+				Where COMM is the ASCII representation
+				of the name of the process executing
+				the event.
+
+			type: EVENT_TYPE
+				The value field for a type key is the
+				name of the security event that is
+				being modeled.  The list of EVENT_TYPE
+				names is defined in the following
+				source file:
+
+				security/tsem/tsem.c
+
+				If the security event is a generically
+				modeled event the EVENT_TYPE will be
+				generic_event.  In this case the CELL
+				characteristics for the event will be
+				described by a generic_event: key
+
+			task_id: HEXID
+				The value of the task_id key will the
+				ASCII base 16 representation of the
+				identity of the task that is executing
+				the security handler.  The length of
+				HEXID will match the size of the
+				digest value of the cryptographic hash
+				function selected for use by the
+				security modeling namespace.
+
+				The following documentation file:
+
+				Documentation/admin-guide/LSM/TSEM.rst
+
+				Describes how the TASK_ID value is
+				generated.
+
+			There will be a COE key that references a
+			value structure that has the same format as
+			the COE key that is emitted for a trajectory
+			or forensics event.
+
+			The record will have a key value that is
+			identical to the value associated with the
+			'type' key documented above.  The 'type' key
+			will have a structure value that contains a
+			definition of the event.  The definitions for
+			the event will be identical to the description
+			of the event that is emitted for a trajectory
+			or forensics event in the internal TMA
+			implementation.
+
+		log:
+			An export type of log is emitted when an
+			untrusted task attempts to execute a security
+			event.
+
+			There will be a 'log' key in the record that
+			references a structure containing the
+			following key values:
+
+			process: COMM
+				The process key has a string value
+				associated with it that will contain
+				the COMM name of the untrusted process
+				that invoked processing of the
+				security event.
+
+			event: NAME
+				The event key has a string value
+				associated with that will contain the
+				name of the security event hook that
+				was called by an untrusted process.
+
+				The names for the security events are
+				defined in the following source file:
+
+				security/tsem/tsem.c
+
+			action: TYPE
+				The action key has a string value that
+				describes the action take by the TSEM
+				security hook in response to being
+				called by an untrusted process.
+
+				This string value will be either LOG
+				or DENY.
diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst
index a6ba95fbaa9f..cebd3b02598d 100644
--- a/Documentation/admin-guide/LSM/index.rst
+++ b/Documentation/admin-guide/LSM/index.rst
@@ -47,3 +47,4 @@ subdirectories.
    tomoyo
    Yama
    SafeSetID
+   tsem
diff --git a/Documentation/admin-guide/LSM/tsem.rst b/Documentation/admin-guide/LSM/tsem.rst
new file mode 100644
index 000000000000..3810dd3b6e6d
--- /dev/null
+++ b/Documentation/admin-guide/LSM/tsem.rst
@@ -0,0 +1,1526 @@
+====
+TSEM
+====
+
+	"This is the story of the wine of Brule, and it shows what
+	 men love is never money itself but their own way, and
+	 that human beings love sympathy and pageant above all
+	 things."
+				- Hilaire Belloc
+				  The Path to Rome
+
+TSEM is the Trusted Security Event Modeling system.  TSEM is the
+kernel infrastructure that provides a platform for implementing
+security policies based on either deterministic or machine learning
+models.  It also provides a framework for implementing Host Based
+Intrusion Detection (HIDS) and anomaly detection without the need to
+write kernel code or implement kernel loadable modules
+
+The design and implementation of TSEM is inspired by the notion that
+the security behavior of a platform, or a workload, like all other
+physical phenomenon, can be mathematically modeled.
+
+Security, is at once, both a technical and economic problem.  One of
+the objectives of TSEM is to address inherent and structural economic
+barriers to security, by introducing technology that reduces the skill
+and time needed to implement a level of security, equivalent to what
+can be achieved by mandatory access controls, through unit testing of
+an application stack.
+
+A second objective is to reduce the skill, complexity and
+infrastructure needed to create trusted and remotely attestable
+platforms and/or workloads.
+
+To achieve these objectives, TSEM implements the concept of a security
+modeling namespace that reduces the complexity of a security model and
+allows it to be scoped to the level of a single process hierarchy or a
+container.
+
+TSEM is the Linux kernel component of a security concept introduced by
+the Quixote Project, the notion of a Trust Orchestration System (TOS).
+The concept of a TOS is to have a system with a minimal Trusted
+Computing Base (TCB) that supervises and maintains subordinate
+security modeling namespaces in a known state of trust.
+
+TSEM is implemented as a Linux Security Module (LSM) and is designed
+to be self-contained with little or no dependency on kernel
+infrastructure, other than the LSM hooks themselves.  It can be
+stacked in any order with existing LSM's.  It is implemented as the
+first LSM in the call sequence since it provides infrastructure that
+can be used, for example, to validate extended attributes that may be
+used by subsequently invoked LSM's.
+
+TSEM implements its equivalent of mandatory access controls, without a
+requirement for extended attributes, filesystem labeling or the need
+to protect filesystem metadata against offline attack.  A mathematical
+defined security model, generated by unit testing of a workload, is the
+entity that carries the security guarantee for system or workload.
+
+TBDHTTRAD
+=========
+
+A quick summary for those interested in experimenting with trust
+orchestration and security modeling but are constrained by: 'Too Busy
+Don't Have Time To Read Any Documentation'.
+
+A kernel with TSEM support in its list of enabled LSM's must be
+available for use.  A TSEM enabled kernel will have the tsem keyword
+in the following file:
+
+/sys/kernel/security/lsm
+
+For experimentation, or integrating TSEM modeling into a Continuous
+Integration/Continous Development (CI/CD) workflow, modeling
+can be restricted to subordinate security namespaces by booting a kernel
+with the following kernel command-line option:
+
+tsem_mode=1
+
+This disables modeling of the root security namespace and only
+implements modeling for subordinate namespaces.
+
+The Quixote trust orchestration utilities either need to be built or
+the statically compiled sample utilities need to be installed.  Source
+for the userspace utilities and compiled sample programs are available
+at the following location:
+
+ftp://ftp.enjellic.com/pub/Quixote
+
+After installing the utilities, two shell sessions will be needed with
+root privileges in each shell.
+
+The following directories need to be in the PATH variable of each shell:
+
+/opt/Quixote/sbin
+/opt/Quixote/bin
+
+Execute the following command to start a process in an independent
+security namespace with the modeling being done in the kernel:
+
+quixote -P -c test -o test.model
+
+In the second shell session, run the following command to display the
+security execution trajectory of the model:
+
+quixote-console -p test -T
+
+In the shell session provided by the trust orchestrator, run the
+following command:
+
+grep SOME_STRING /etc/passwd
+
+Then exit the shell.
+
+The orchestrator will indicate that the security model definition has
+been written to the test.model file.
+
+Run the following command to execute a shell in an enforced security
+model obtained from the previous session:
+
+quixote -P -c test -m test.model -e
+
+In the shell that is provided, run the following command:
+
+cat /etc/passwd
+
+The command will fail.
+
+Running the following command in the second shell session will output
+forensics on the command that failed:
+
+quixote-console -p test -F
+
+Executing additional commands in the trust orchestrated shell will
+cause additional entries to be added to the forensics trajectory.
+
+The test can be repeated using the quixote-us trust orchestrator.
+This test will model the security namespace in a userspace process
+rather than in the kernel based trusted modeling agent.
+
+Mandatory Access Controls
+=========================
+
+	"If I have seen further it is by standing on the shoulders of
+	 Giants."
+				- Sir Isaac Newton
+
+It is assumed that astute readers will be familiar with classic
+subject/object based mandatory access controls; or at least astute
+enough to use a search engine to develop a modicum of secundem artem
+in the discipline.
+
+Very simplistically, subject/object based mandatory access controls
+can be thought of as being implemented with a two dimensional access
+vector matrix, with some type of a description of a process (subject)
+on one axis and a description of a data sync/source (object),
+typically an inode, on the second axis.  The descriptions are
+commonly referred to as subjects and objects.
+
+A security policy is developed that assigns a boolean value for each
+element of the matrix that specifies whether or not permission should
+be granted for the subject to access the object.
+
+These schemes are frequently referred to as 'mandatory access
+controls', since only the kernel has the ability to implement the
+labeling and decision processes.  In these systems, the root or
+administrative user has no ability to affect kernel decision making
+with respect to whether or not permission is granted or denied.
+
+These systems were derived from governmental and military information
+classification systems and are capable of delivering security
+guarantees appropriate to classified and high sensitivity assets.  The
+delivery of these security guarantees comes with it a reputation for
+complexity and fragility.
+
+Development of a system wide security policy is a complex process and
+administration of such systems is frequently done in an iterative
+fashion.  The system is monitored for permission denials with
+modifications to correct these false denials folded back into the
+policy.  In many cases, mandatory access control systems are run in
+warning rather than enforcing mode and used as an indicator for
+potential security violations.
+
+One of the additional challenges is that the integrity of labels is
+fundamental to the ability of these systems to deliver their security
+guarantees.  This requires that the labeling process be conducted
+under security controlled conditions, with the labels subsequently
+protected against offline modification by cryptographic integrity
+guarantees.
+
+Mandatory access controls had their origin in centralized multi-user
+platforms, and before the now widely accepted, strategy of using
+resource compartmentalization (namespaces) to isolate applications
+from each other and the system at large.  A legitimate technical
+argument can be made as to whether or not enforcement of a system wide
+security policy is suitable for these environments.
+
+At the other end of the spectrum, in embedded systems, structural
+economic barriers incent very little attention to security, where time
+to market is the primary goal.  These systems are pushed into the
+field, many time for multi-year operational lifetimes, with little
+prospect for upgrades or any notion of an iterative tuning process of
+a security policy.
+
+Security Event Modeling
+=======================
+
+	"We can no longer speak of the behavior of the particle
+	 independently of the process of observation. As a final
+	 consequence, the natural laws formulated mathematically in
+	 quantum theory no longer deal with the elementary particles
+	 themselves but with our knowledge of them. Nor is it any
+	 longer possible to ask whether or not these particles exist in
+	 space and time objectively ... When we speak of the picture of
+	 nature in the exact science of our age, we do not mean a
+	 picture of nature so much as a picture of our relationships
+	 with nature.  ...Science no longer confronts nature as an
+	 objective observer, but sees itself as an actor in this
+	 interplay between man and nature. The scientific method of
+	 analysing, explaining and classifying has become conscious of
+	 its limitations, which arise out of the fact that by its
+	 intervention science alters and refashions the object of
+	 investigation. In other words, method and object can no longer
+	 be separated."
+				- Werner Karl Heisenberg
+
+Security Event Modeling (SEM), is an alternative strategy to implement
+the security guarantees of mandatory access and integrity controls, in
+a manner that is consistent with emerging application development
+strategies such as namespaces and CI/CD workflows.
+
+As was noted at the start of this document, the premise for SEM is
+that the security behavior of a platform, or alternatively a workload,
+can be modeled like any other physical phenomenon in science and
+engineering.
+
+Inspiration for this came from the primary TSEM author/architect
+having trained as a quantum chemist, conducting very early research in
+the development of multi-scale modeling strategies for molecules of
+size to be of interest to pharmaceutical intents.
+
+SEM is premised on the theory that kernel security architects have
+instrumented the LSM security event hooks to be called from all
+locations, with appropriate descriptive parameters, that are relevant
+to the security posture of the kernel.  With respect to modeling, the
+security event hooks are conceptualized as representing the
+independent variables of a basis set that yields a functional
+definition for the security state of an execution trajectory.
+
+SEM can be framed in the context of classic subject/object mandatory
+access controls, by the notion that a unique identity can be generated
+for each element of an access vector matrix, rather than a boolean
+value.  In SEM, a security execution trajectory is defined by the set
+of security state coefficients that a process hierarchy (workload)
+generates.  This execution trajectory produces a vector of identities,
+whose sum in an appropriate form, yields a functional definition of
+the security state of the system.
+
+Two subordinate identities are combined to yield a security event
+state coefficient.  These subordinate identities are referred to as the
+Context Of Execution (COE) and the CELL, which are conceptually
+similar to the subject and object in mandatory access control.  The
+COE identity is derived from the parameters that describe the security
+relevant characteristics of a process, while the CELL value is derived
+from the parameters used by a security event hook to describe the
+characteristics of the event.
+
+A security policy is implemented by a modeling algorithm that
+translates COE and CELL event parameters into their respective
+identities.  The COE and CELL are combined to yield a security state
+coefficient that uniquely describes the security event in the security
+model.  Different security policies and criteria can be developed by
+modifying how the modeling algorithm utilizes the COE and CELL
+characteristics.
+
+Since the security policy is implemented with a modeling algorithm, a
+single platform can support multiple and arbitrary security policies.
+The equivalent of a resource namespace in SEM is referred to as a
+security modeling namespace.
+
+The formation of the security state coefficients from existing kernel
+parameters eliminates the need for the use of extended attributes to
+hold security label definitions.  In SEM, a cryptographically signed
+security model definition, designed to be interpreted by a modeling
+algorithm, becomes the bearer's token for the security of the modeled
+workload, rather than information encoded in filesystem security
+attributes.
+
+Trusted Security Event Modeling
+===============================
+
+	"Do you see over yonder, friend Sancho, thirty or forty
+	 hulking giants?  I intend to do battle with them and slay
+	 them."
+				- Don Quixote
+
+In TSEM, the modeling algorithm is implemented in an entity known as a
+Trusted Modeling Agent (TMA), in a 'trusted' environment where
+modeling is immune from modification or alteration by any activity on
+the platform or in a workload.  The notion of a TMA provides a
+framework for next generation security co-processors that extend
+functionality beyond what is defined by the concept of a Trusted
+Platform Module (TPM).
+
+In addition to providing an attestation of an execution trajectory, a
+TMA, in contrast to a TPM, has the ability to advise an operating
+system on whether or not an event being modeled is consistent with the
+security model that is being enforced.  In this manner, it introduces
+a prospective rather than a retrospective trust model.
+
+TSEM is designed to support Trust Orchestration Systems (TOS).  In a
+TOS, the trust orchestrators are supervisory programs that run
+workloads in independent modeling namespaces , enforcing a workload
+specific security model.  Each trust orchestrator is paired with a
+'trusted partner TMA', known as a Sancho, that implements the workload
+specific modeling algorithm.
+
+The root of trust for a workload modeling namespace is based on where
+the TMA instance is implemented.  As an example, the Quixote TOS
+implementation currently offers orchestrators for the following TMA
+execution localities:
+
+- Kernel.
+
+- Userspace process.
+
+- SGX enclave.
+
+- Xen stub domain.
+
+- Micro-controller.
+
+This partitioning of trust results in the concept of security modeling
+namespaces being referred to as internally or externally modeled.  A
+TMA implementation run in the kernel is referred to as an internally
+modeled namespace; TMA's run outside of the kernel are referred to as
+an externally modeled namespace.
+
+The TMA, regardless of locality, is responsible for processing the
+characteristics that describe a security event, computing the identity
+for the COE and CELL and then combining these two identities to create
+a security state coefficient.  With respect to modeling theory, the
+coefficient is a task specific value representing the event in a
+security model.
+
+TSEM is dispassionate with respect to the type of algorithm that is
+implemented.  The processing of the security event characteristics and
+their conversion to security coefficients, is driven by the security
+model/policy that will be implemented for the workload.  The
+architecture is designed to support security modeling algorithms that
+are either deterministic or embrace approximations, stochastic
+inference and machine learning algorithms in response to specific
+workload, platform or device requirements.
+
+A security model, to be enforced by a trust orchestrator, is
+implemented by providing the TMA with a set of security state
+coefficients that are to be observed.  A TMA processes the
+characteristics of a security event and converts the characteristics
+to a security state coefficient that is evaluated against the
+coefficients provided to the TMA as the reference security model for a
+workload.
+
+A security event that translates to one of the provided 'good'
+coefficients, will cause the TMA to indicate to the trust orchestrator
+that the process is to be allowed to run as a trusted process.  A
+security event that does not map to a known good coefficient, results
+in the trust orchestrator designating that the process be labeled as
+an untrusted process.
+
+Trust orchestrators and their associated TMA's, are designed to
+support signed security models.  This results in the elimination of
+the requirement to verify or appraise extended attributes and other
+measures currently required to protect labeled security systems
+against offline attacks.
+
+The use of a cryptographic hash function to generate the security
+coefficient results in the definition of very specific security
+behaviors, that are sensitive to any variation in their
+characteristics.  Any offline modifications to files will result in a
+coefficient that is inconsistent with a signed model provided to a
+TMA.
+
+In order to support the development of TSEM based security models, a
+TMA is designed to run in one of three separate modes, referred to as
+follows:
+
+- Free modeling.
+
+- Sealed.
+
+- Enforcing.
+
+In a free modeling configuration, the TMA adds the security state
+coefficient for the characteristics of a security event to the current
+set of known good states.  In addition, the description of the
+security event is retained as a member of the security execution
+trajectory for the model.  This mode is used, in combination with unit
+testing of a workload, to generate a security model for subsequent
+enforcement.
+
+Placing a TMA in 'sealed' mode implies that any subsequent security
+coefficients, that do not map into a known security state, are to be
+considered 'forensic' violations to the security state of the model.
+
+This mode is designed to provide the ability to either fine tune a
+model or provide early warning of a potential attempt to subvert the
+security status of a workload.  The characteristics of the violating
+event are registered in the forensics trajectory of the model for use
+in subsequent evaluation of the violating event and/or model
+refinement.
+
+Placing a TMA model in 'enforcing' status implies that the model is in
+a sealed state and any subsequent violations to the model will result
+in the violating process being placed in untrusted status and a
+permissions violation returned to the task invoking the security
+event.
+
+Process and Platform Trust Status
+=================================
+
+A fundamental concept in TSEM is the notion of providing a precise
+definition for what it means for a platform or workload to be trusted.
+A trusted platform or workload is one where there has not been an
+attempt by a process to execute a security relevant event that does
+not map into a known security state coefficient.
+
+The process trust status is a characteristic of the process that is
+passed to any subordinate processes that are descendants of that
+process.  Once a process is tagged as untrusted, that characteristic
+cannot be removed from the process.  In a 'fruit from the poisoned
+vine' paradigm, all subordinate processes created by an untrusted
+process are untrusted as well.
+
+On entry into each TSEM security event handler, the trust status of a
+process is checked before an attempt to model the event is made.  An
+attempt to execute a security event by an untrusted process will cause
+the event, and its characteristics, to be logged.  The return status
+of the hook will be determined by the enforcement state of the model.
+A permission denial is only returned if the TMA is running in
+enforcing mode.
+
+If the platform running the TSEM LSM has a TPM, the hardware aggregate
+value is computed at the time that TSEM is initialized.  This hardware
+aggregate value is the linear extension sum over Platform
+Configuration Registers (PCR's) 0 through 7.  This is the same
+aggregate value that is computed by the Integrity Measurement
+Architecture (IMA) and is the industry standard method of providing an
+evaluation measurement of the hardware platform state.
+
+Internally modeled namespaces have the hardware aggregate measurement
+included as the first event in the security model.  Externally modeled
+namespaces export the hardware aggregate value to the TMA for
+inclusion as the first event of the model maintained by the external
+TMA.
+
+The root security model extends each security state coefficient into a
+PCR.  The default PCR is 11 but is configurable through the kernel
+configuration process.  The use of a separate PCR from IMA allows
+hardware based TSEM measurements to coexist with IMA measurement
+values.  This hardware measurement value is designed to allow
+attestation to the hardware state that the root model is running in.
+
+TSEM is designed to support a philosophy where the root security
+namespace will be a minimum Trusted Computing Base implementation that
+will only be running trust orchestrators.  Subordinate modeling
+namespaces are non-hierarchical so as to decrease model complexity in
+the subordinate namespaces in order to support a single functional
+value describing the security status of a modeling namespace.
+
+The Linux TSEM Implementation
+=============================
+
+	"Sometimes the questions are complicated and the answers are
+	 simple."
+				- Dr. Seuss
+
+The Linux TSEM implementation is deliberately simplistic and consists
+of the following two generic components:
+
+- Modeling namespace and security event export functionality.
+
+- Internal trusted modeling agent.
+
+The modeling namespace and export functionality is designed to be
+generic infrastructure that allows security namespaces to be created that
+are either internally or externally modeled.  The TSEM implementation
+does not pose any constraints on what type of modeling can or should
+be implemented in these namespaces.
+
+On the theory that security event handlers represent all of the
+security relevant action points in the kernel, any security or
+integrity model can be implemented using the TSEM infrastructure.  For
+example, basic IMA functionality could be implemented by a TMA that
+maps the digests of files accessed, or mapped executable, by the root
+user as the security state coefficients.
+
+A primary intent of the Linux TSEM implementation is to provide a
+generic method for implementing security policy in userspace rather
+than the kernel.  This is consistent with what has been the historic
+understanding in Linux architecture, that policy decisions should be
+delegated, when possible, to userspace rather than to kernel based
+implementations.
+
+The model is extremely simplistic; a TMA interprets a security event
+and its characteristics and advises whether or not the kernel should
+designate the process as trusted or untrusted after event processing
+is complete.
+
+The following sections discuss various aspects of the infrastructure
+used to implement this architecture.
+
+Internal vs external modeling
+-----------------------------
+
+When a TSEM modeling namespace is created, a designation is made as to
+whether the namespace is to be internally or externally modeled.
+
+In an internally modeled namespace, the security event handlers pass the
+event type and its characteristics to the designated internal trusted
+modeling agent.  The agent provides the permission value for the
+security event handler to return as the result of the event and sets
+the trust status of the process executing the event.
+
+In an externally modeled namespace, the event type and parameters are
+exported to userspace for processing by a trust orchestrator with an
+associated TMA.  The trust orchestrator communicates the result of the
+modeling back to the kernel to support the setting of the process
+trust status.
+
+The exception to this model are for security event handlers that are
+called in atomic, ie. non-sleeping context.  The export of these
+security event descriptions are done asynchronously in order to avoid
+having the TSEM implementation attempt to sleep in atomic context
+while the userspace trust orchestrator is scheduled for execution.
+
+It is up to the trust orchestrator and its security policy to
+determine how it handles events that violate the security model being
+enforced.  The Quixote trust orchestrators shut down the entire
+workload running in the security namespace if an asynchronously
+modeled event violates the security model being enforced and the model
+is running in enforcing mode.
+
+Internally modeled domains are able to provide immediate interception
+and modification of the trust status of a process that is violating
+the security model.  This has implications for the root security
+namespace that is running on a system with a TPM, since the security
+event coefficients are logged to the Platform Configuration Register
+that is being used by TSEM.
+
+Issuing the TPM transaction would cause the process to attempt to
+sleep while it waits for the TPM transaction to complete.  In order to
+address this issue the TPM transactions are deferred to an ordered
+workqueue for execution.  The use of an ordered workqueue maintains
+the time dependency of the security coefficients being registered.
+
+In order to handle modeling of security events in atomic context the
+TSEM implementation maintains caches (magazines) of structures that
+are needed to implement the modeling and export of events.  The size
+of this cache can be configured independently for each individual
+security modeling namespace that is created.  The default
+implementation is for a cache size of 16 for internally modeled
+namespaces and 96 for externally modeled namespaces.
+
+By default the root security namespace uses a cache size of 96.  This
+value can be configured by the 'tsem_cache' kernel command-line
+parameter to an alternate value.
+
+Trust Orchestrator/Process authentication
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The process identifier values (PID's) that are exported in the
+security event descriptions are the unique global PID values, not the
+value as seen through the lens of a PID namespace.
+
+PID values are, by default, not considered to be a stable identifier
+between the kernel and userspace.  In the case of TSEM external
+modeling, the threat model for a namespace is whether or not an
+adversarial process, running in either the root modeling namespace or
+another subordinate modeling namespace, can kill a process that is
+being orchestrated and substitute an alternate process with an
+identical PID value.
+
+The trust orchestrator would then be deluded into setting the trust
+status of the adversarial process rather than the one that had emitted
+the security event characteristics.  The threat interval is the
+latency time required for the processing of the security event
+description by the trust orchestrator and its associated TMA.
+
+Exploiting this theoretical race is extremely complex and requires an
+in depth understanding of the TSEM architecture.  Rather than discuss
+the conditions that must be met and their implications, this
+discussion will focus on the generic threat model and the mechanisms
+that TSEM implements in order to mitigate this threat.
+
+In short, a process in an adversarial security modeling namespace would
+want to execute security events that are barred from its security
+model with the hope of having them approved by an alternate namespace.
+
+In order to exploit the race, an adversarial process would have to
+force the termination of a process in the target namespace and then
+fork and exit a process a sufficient number of times in order to have
+a process under its control match the PID value of the process that
+was waiting for an orchestration response.
+
+Measured modeling latency times for a trust orchestrator running the
+deterministic Quixote TMA in userspace, on current generation 3.x
+x86_64 hardware, averages 170 micro-seconds.  In a worst case
+scenario from the perspective of an adversary, there would be a need
+to force the termination of the target process and then fork and
+execute a sufficient number of times to force the PID collision
+during this time interval.
+
+As a generic protection, TSEM in the tsem_task_kill() handler, blocks
+the notion of 'cross-model' signals, ie. a signal originating from an
+external modeling namespace.  This would require the adversary to
+reliably force a process termination through a mechanism other than
+signaling, for example, through the OOM killer whose signal
+transmission would not be blocked by this policy control.
+
+When a subordinate security modeling namespace is created, the id
+number of the namespace is registered in the tsem_task structure of
+the trust orchestrator that is creating the namespace.  The TSEM
+driver will refuse to honor control plane requests affecting the trust
+status of a process whose trust orchestrator security namespace id
+does not match the id of the process that it is being asked to act on.
+
+As an additional protection, TSEM uses an authentication strategy that
+allows a process running in a security modeling namespace to verify
+that a control request is coming from the trust orchestrator that
+initiated the namespace the process is running in.  As part of the
+setup of a security modeling namespace, a trust orchestrator is
+required to provide a hexadecimally encoded authentication key that
+matches the length of the cryptographic hash function being used to
+generate security state coefficient in the modeling namespace.  This
+authentication key must be provided by the trust orchestrator for
+every subsequent control plane request.
+
+The process that is being transferred to a subordinate security
+modeling namespace generates a second random key that is hashed with
+the authentication key provided by the trust orchestrator, using the
+hash function that has been defined for the security namespace.  The
+resultant digest value is compared to a list of authentication keys
+for all currently executing namespaces.  The selection of the second
+random key is repeated until a globally unique key is generated.
+
+This randomly generated authentication key is stored in the tsem_task
+structure of the process and propagated to any subsequent processes
+that are created in the namespace.  The hash product of this key and
+the orchestration authentication key, ie. the globally unique key, is
+placed in the tsem_task control structure of the orchestration
+process.
+
+When a control plane request is received, the authentication key
+provided by the trust orchestrator is used to re-generate an
+authentication key based on the randomly generated namespace key held
+by the process whose trust status is being updated and compared to the
+key in the tsem_task structure of the processing issuing the
+orchestration call.  The control plane will refuse to honor a control
+plane request if the call specific key does not match the key that was
+generated at the time the security namespace was created.
+
+Explicit vs generic modeling
+----------------------------
+
+In addition to the COE characteristics, TMA's have the ability to
+include the parameters that characterize the CELL of the security
+event into the generation of the security state coefficient for the
+event.  The inclusion of specific CELL characteristics is considered
+explicit modeling of the event.
+
+TMA's also have the ability to consider only the COE characteristics
+and the type of the event.  This is referred to as generic modeling of
+the event.
+
+In the current Linux TSEM implementation, the security event handlers
+differentiate, primarily due to current numerical resolution
+requirements of the models being implemented, some events to be
+generically modeled.  For these events, in addition to the COE
+characteristics and task identity, a default event specific CELL value
+is used in the computation of the security state coefficient.
+
+As was noted in the section on 'internal vs external modeling', the
+most common violation of trust is the initial execution of a binary or
+access to a file.  The inclusion of events, as generically modeled,
+allows the capture of security behaviors that are inconsistent with a
+proscribed security model, even if full characterization of the event
+is not implemented.
+
+As a further example.  If security workload unit testing has not
+included the ability of the workload to issue a request for creating
+and installing a BPF program, the mere request to do so is considered
+sufficient to place the workload in an untrusted state.
+
+In the following ABI document:
+
+Documentation/ABI/testing/tsemfs
+
+Documentation for the following control plane interface:
+
+/sys/kernel/security/tsem/InternalTMA/model0/trajectory
+
+Documents the security event parameters that are available for
+modeling by both internally and externally modeled namespaces.
+
+Event modeling
+--------------
+
+The generation of security state coefficients is a functional process
+that uses a cryptographic hash function for the creation of the
+various identity coefficient that make up the expression of the
+security state coefficient.
+
+TSEM can use any cryptographic hash function available to the Linux
+kernel for this purpose.  The hash function to be used for a security
+modeling namespace is specified as a parameter to the namespace
+creation process.
+
+By default, the root security namespace uses SHA256.  This value can
+be modified through the tsem_digest kernel command-line parameter.
+
+Since TSEM is active before the kernel has the ability to load
+modules, the root modeling domain must be a cryptographic hash
+function that is statically compiled into the kernel.  By default the
+TSEM configuration selects for the presence of the SHA256 hash
+function.
+
+TSEM security event modeling is based on the following functional
+definition for a security event coefficient:
+
+Coeff = HF(HF(EVENT_ID) || TASK_ID || HF(COE) || HF(CELL))
+
+	Where:
+		Coeff	 = A security state coefficient that is equal
+			   in length to the digest value of the
+			   cryptographic hash function in use for the
+			   modeling namespace.
+
+		||       = Concatenation operator.
+
+		HF	 = Security namespace specific hash function.
+
+		EVENT_ID = ASCII name of event.
+
+		TASK_ID  = The process specific identity of the
+			   executable code that is initiating modeling
+			   of the security event.
+
+		COE      = Characteristics of the context of execution
+			   of the event.
+
+		CELL	 = Characteristics of the event that is being
+			   modeled.
+
+Workload or platform specific security state coefficient definitions
+are generated by a TMA, using whatever COE or CELL characteristics
+that are considered relevant for the model being implemented, to
+determine whether or not an event should lead to the process being
+considered trusted or untrusted.
+
+The TASK_ID component of the function above is important with respect
+to the generation of the security state coefficients.  The notion of a
+task identity serves to link the concepts of system integrity and
+security access control
+
+The TASK_ID is defined by the following function:
+
+TASK_ID = HF(HF(EVENT) || NULL_ID || HF(COE) || HF(CELL))
+
+	Where:
+		TASK_ID	  = The executable identity of the process
+			    expressed as a digest value of length
+			    equal to the cryptographic hash function
+			    the modeling namespace is using.
+
+		||        = Concatenation operator.
+
+		EVENT	  = The string "bprm_set_creds".
+
+		NULL_ID	  = A buffer a set of null bytes equal to the
+			    digest size of the hash function being
+			    used for the namespace.
+
+		COE	  = Characteristics of the context of execution
+			    calling the bprm_creds_for_exec LSM hook.
+
+		CELL	  = The characteristics of the file provided
+			    by the linux_binprm structure passed to
+			    the security bprm_set_creds handler.
+
+An informed reader will quickly conclude, correctly, that the TASK_ID
+function generates an executable specific security coefficient for the
+bprm_creds_for_exec security hook.  The function is the same as the
+standard security state coefficient; with the exception that the task
+identity is replaced with a 'null id', consisting of the number of
+null bytes in the digest size of the namespace specific hash function.
+
+One of the CELL characteristics, used in the computation of the task
+identity, is the digest of the executable file.  Modifying an
+executable, or attempting to execute a binary not considered in the
+security model, will result in an alteration of the task identity that
+propagates to the generation of invalid state coefficients.
+
+The task identity is saved in the TSEM specific task structure and is
+used to compute the state coefficients for any security events that
+the task subsequently executes.  As noted in the previous paragraph,
+incorporating the TASK_ID into the computation of security state
+coefficients results in the security state coefficient values becoming
+specific to the corpus of executable code that initiated a process.
+This affords a very high degree of specificity with respect to the
+security models that can be implemented.
+
+As was demonstrated in the TBDHTTRAD section, TSEM will discriminate
+the following commands as different events/coefficients in a security
+model:
+
+cat /etc/shadow
+
+grep something /etc/shadow
+
+while read input
+do
+	echo $input;
+done < /etc/shadow
+
+An important, and perhaps subtle issue to note, is how these events
+result in the change of process trust status.  In the first two cases,
+if access to the /etc/shadow file is not permitted by the operative
+security model, the cat and grep process will become untrusted.
+
+In the third example, the shell process itself would become untrusted.
+This would cause any subsequent attempts to execute a binary to be
+considered untrusted events, even if access to the binary is a
+permitted coefficient in the model.
+
+Since the modeling operates at the level of a mandatory security
+control, these permission denials would occur even if the process is
+running with root privilege levels.  This is secondary to the notion
+that security and trust status are invested in the trust orchestrator
+and ultimately the TMA.
+
+From a hardware perspective, this is important with respect to the
+notion of a TMA being a model for a successor to the TPM.  From a
+system trust or integrity perspective, a TPM is designed to provide a
+retrospective assessment of the actions that have occurred on a
+platform.  A verifying party uses the TPM event log and a PCR based
+summary measurement, to verify what actions have occurred on the host,
+in order to allow a determination of whether or not the platform
+should be 'trusted'.
+
+In contrast, a TSEM/TMA based system enforces, on a real time basis,
+that a platform or workload remains in a trusted state.  Security
+relevant actions cannot be conducted unless the TMA authorizes the
+actions as being trusted.
+
+This is particularly important with respect to embedded systems.  A
+TPM based architecture would not prevent a system from having its
+trust status altered.  Maintaining the system in a trusted state would
+require attestation polling of the system, and presumably, executing
+actions if the platform has engaged in untrusted behavior.
+
+Conversely, a trust orchestrated software implementation enforces that
+a system or workload remain in a security/trust state that it's
+security model was unit tested to.
+
+Security model functional definitions
+-------------------------------------
+
+Previously, classic trusted system implementations supported the
+notion of the 'measurement' of the system.  The measurement is the
+value of a linear extension function of all the security relevant
+actions recorded by a trust measurement system such as IMA.
+
+In TPM based trust architectures, this measurement is maintained in a
+PCR.  A measurement value is submitted to the TPM that extends the
+current measurement using the following formula:
+
+MEASUREMENT = HASH(CURRENT || NEW)
+
+	Where:
+		MEASUREMENT = The new measurement value to be maintained
+			      in the register for the system.
+
+		||	    = Concatenation operator.
+
+		HASH	    = A cryptographic hash function supported
+			      by the TPM device.
+
+		CURRENT     = The current measurement value.
+
+		NEW	    = A new measurement value to be added to
+			      the current measurement.
+
+In TPM1 based systems, the HASH function was SHA1.  Due to well
+understood security concerns about the cryptographic vitality of this
+function, TPM2 based systems provide additional HASH functions with
+stronger integrity guarantees, most principally SHA related functions
+with longer digest values such as SHA256, SHA384 and SM3.
+
+The use of a cryptographic function produces a non-commutative sum
+that can be used to verify the integrity of a series of measurements.
+With respect to security modeling theory, this can be thought of as a
+'time-dependent' measurement of the system.  Stated more simply, the
+measurement value is sensitive to the order in which the measurements
+were made.
+
+In systems such as IMA, the measurement value reflects the sum of
+digest values of what are considered to be security critical entities,
+most principally, files that are accessed, based on various policies.
+
+In TSEM based TMA's, the measurement of a modeling namespace is the
+sum of the security state coefficients generated by the operative
+security model being enforced.  As previously noted, on systems with a
+TPM, the root modeling namespace measurement is maintained by default
+in PCR 11 or the PCR that was selected at kernel configuration time.
+
+The challenge associated with classic integrity measurements is the
+time dependent nature of using a non-commutative summing function.
+The almost universal embrace of SMP based hardware architectures, in
+addition to standard kernel task scheduling issues, makes the
+measurement values non-deterministic.  This requires a verifying party
+to evaluate an event log, verified by a measurement value, to
+determine whether or not the system is in a security appropriate
+state.
+
+TSEM addresses this issue by implementing a strategy designed to
+produce a single functional value that represents the security state
+of a model.  This allows a TMA to attest to the trust/security status
+of a platform or workload by signing this singular value and
+presenting it to a verifying party.
+
+In TSEM nomenclature, this singular value is referred to as the
+'state' of the model.  The attestation model is to use trust
+orchestrators to generate the state value of a workload by unit
+testing.  This state value can be packaged with a utility or container
+to represent a summary trust characteristic that can be attested by a
+TMA, eliminating the need for a verifying partner to review and verify
+an event log.
+
+TMA's implement this architecture by maintaining a single instance
+vector of the set of security state coefficients that have been
+generated.  A state measurement is generated by sorting the vector in
+big-endian hash format and then generating a standard measurement
+digest over this new vector.
+
+Any security event that generates an associated state coefficient that
+is not in the model will resulted in a perturbed state function value.
+That perturbed value would be interpreted by a verifying party as an
+indication of an untrusted system.
+
+Since the TMA maintains the security event descriptions in time
+ordered form, the option to provide a classic event log and
+measurement are preserved and available.  Extensive experience in the
+development of TSEM modeled systems has demonstrated the superiority
+of state value interpretation over classic measurement schemes.
+
+A TMA may choose to incorporate a 'base nonce' into a security model
+that it is implementing, this base nonce is designed to serve in a
+manner similar to an attestation nonce.  If used, the trust
+orchestrator is responsible for negotiating a random base nonce with a
+verifying party at the time of initialization of a modeling namespace
+and providing it to the TMA.
+
+The TMA uses the base nonce to extend each security event coefficient
+that is generated by the model.  This causes the state and measurement
+values of the model to become dependent on this base nonce, a process
+that can be used to defeat a replay attack against the security model.
+
+Control plane
+-------------
+
+Both primary functions of TSEM: security modeling namespace management
+and the internal TMA modeling implementation, are controlled by
+pseudo-files in the securityfs filesystem.  The following directory
+is the top level implementation directory for the TSEM control plane:
+
+/sys/kernel/security/tsem
+
+The following file documents, in detail, the interfaces provided by
+the filesystem:
+
+Documentation/ABI/testing/tsemfs
+
+This filesystem is primarily intended for use by trust orchestrators
+to create and manage security modeling namespaces.
+
+The files are process context sensitive.  Writing to the control file,
+or reading from the informational files, will act on or reference the
+security namespace that the accessing process is assigned to.
+
+The following files and directories are provided in the root directory
+of the TSEM control plane and implement global controls for the TSEM
+LSM:
+
+	id
+	control
+	aggregate
+
+The 'id' file is used to determine the modeling namespace that the
+process is running in.  The namespace id value of 0 is reserved for
+the root modeling namespace, a non-zero value indicates that the process
+is running in a subordinate modeling namespace.
+
+The TSEM implementation is controlled by the only writable file, which
+is the 'control' file.
+
+The following keywords are used by trust orchestrators to place the
+process writing to the file in an internally or externally modeled
+security namespace:
+
+	internal
+	external
+
+Each argument accepts key=value pairs that configure the namespace.
+The following key values are currently accepted:
+
+	nsref
+	digest
+	cache
+	key
+
+The 'nsref' keyword takes one of the following two values:
+
+	initial
+	current
+
+The initial argument indicates that the UID/GID values for the COE or
+the CELL characteristics are derived from the initial user namespace.
+This is the default characteristic if the nsref key is not specified.
+
+The current argument indicates that the UID/GID values are derived
+from the user namespace that the process is running in, when the
+request is made to model an event.
+
+The 'digest' keyword is used to specify the cryptographic hash
+function that is to be used to create the functional values for the
+security state coefficients for the namespace.  The value to this
+keyword is the name by which the hash function is defined by the
+cryptographic API in the kernel.
+
+Examples of suitable strings are as follows:
+
+	sha256
+	sha3-256
+	sm3
+
+Definitions for the names of the cryptographic hashes can be found in
+the source files for the various cryptographic hash functions in the
+'crypto' directory of the Linux source tree.
+
+The 'cache' keyword is used to specify the size of the caches used to
+hold pointers to data structures used for the modeling of security
+events or the export of the security event to external trust
+orchestrators.  These pre-allocated structures are used to service
+security event hooks that are called while the process is running in
+atomic context and thus cannot sleep or allocate memory.
+
+The argument to these keyword is a numeric value specifying the
+number of structures that are to be held in reserve for the namespace.
+
+By default the root modeling namespace and externally modeled
+namespaces have a default value of 96 entries.  An internally modeled
+namespace has a default value of 16 entries.
+
+The 'key' keyword is used to specify the authentication key that is to
+be used to support the authentication of trust control requests from a
+trust orchestrator to processes running in a security modeling
+namespace.  The argument to this keyword is the ASCII base16
+representation of the key that is to be used.  The length of the key
+must be equal to the size of the digest function defined for the
+namespace.
+
+The following keywords and arguments are used by trust orchestrators
+to set the trust status of a process after the processing of a
+security event by an external TMA:
+
+	trusted pid=PID key=HEXID
+	untrusted pid=PID key=HEXID
+
+	PID is the process identifier that is provided to the TMA in
+	the security event description.  HEXID is the base16 ASCII
+	representation of the authentication key that the security
+	modeling namespace was configured with when the namespace was
+	created.
+
+By default a modeling namespace runs in free modeling mode.  The modeling
+mode is changed by writing the following keywords to the control file:
+
+	seal
+	enforce
+
+The following keyword and argument are used to load a security model
+into an internal modeling namespace:
+
+	state value=HEXID
+
+	Where HEXID is the ASCII base 16 representation of a security
+	state coefficient that represents a valid security event in the
+	model.
+
+	After writing a series of state values the trust orchestrator
+	writes the 'seal' keyword to the control file to complete
+	creation of a security model.  Writing the 'enforce' keyword
+	to the control file will result in that model being enforced.
+
+	A security model for a namespace is loaded by writing the
+	valid security coefficients for a model file to the control
+	plane.  This will result in the 'trajectory' file having no
+	event descriptions for a sealed model, since the event
+	description vector is only populated when a new state
+	coefficient is added to the model.
+
+	Since the state state coefficients are generated with a
+	cryptographic hash function, the first pre-image resistance
+	characteristics of the function prevents a security model
+	description from disclosing information about the
+	characteristics of the workload.
+
+The following keyword and argument is used to set a base nonce for the
+internal TMA:
+
+	base value=HEXID
+
+	Where HEXID is the ASCII base 16 representation of a value
+	that each measurement is to be extended with before being
+	committed as a measurement value for the model.
+
+The following keyword and argument is used to create a file digest
+pseudonym for the internal TMA:
+
+	pseudonym value=HEXID
+
+	Where HEXID is the ASCII base 16 representation of a file
+	digest pseudonym that is to be maintained by the model.  See
+	the ABI documentation for how the argument to this verb is
+	generated.
+
+The 'aggregate' file is used by trust orchestrators for internally
+modeled namespaces to obtain the hardware measurement value for
+inclusion in a security model. A trust orchestrator for an externally
+modeled namespace can capture this value, since it is exported as the
+first event that occurs in a security modeling namespace.
+
+The following two directories are implemented in the top level TSEM
+control directory in order to support interfaces to internally and
+externally modeled namespaces:
+
+	ExternalTMA
+	InternalTMA
+
+The ExternalTMA directory holds a file, that is created when the
+request to create an externally model security namespace is made, and
+are named for the id number of the security modeling namespace.  The
+descriptions for security events that occur in the context of the
+namespace are exported in JSON format to the external trust
+orchestrator that is managing the namespace.
+
+The InternalTMA directory is a container directory that holds
+directories for the control of each internal TMA that is implemented
+in the kernel.
+
+There is currently only a single kernel based TMA that is managed
+through the following directory:
+
+/sys/kernel/security/tsem/InternalTMA/model0
+
+The following files are implemented for this model:
+
+	measurement
+	state
+
+	trajectory
+	trajectory_coefficients
+	trajectory_counts
+
+	forensics
+	forensics_coefficient
+	forensics_counts
+
+The 'measurement' file outputs the classic linear extension value of
+the security state coefficients that are generated in the context of
+the security modeling namespace.  This value is time dependent and can
+be used to verify the order of the security events that occurred in
+the model
+
+The 'state' file outputs a time independent functional value of
+security state of the modeling namespace.  This value and its
+generation and motivation are discussed in the 'Security model
+functional definitions' section of this document.
+
+The 'trajectory' file outputs the description of each security event
+recorded by the model in time dependent form.  The ABI documentation
+file contains a complete description of the output that is generated
+by this file and the 'forensics' file described below.
+
+The 'trajectory_coefficients' file outputs the set of security state
+coefficients in the model.  These coefficients are the values of the
+event descriptions that are output in the 'trajectory' file.
+
+The 'trajectory_counts" file outputs the number of times that each
+security state coefficient, output by the 'trajectory_coefficients'
+file, has been experienced in the security namespace.  This value can
+be used to verify that a security sensitive event has occurred or for
+statistical inference as to the anomaly status of the namespace.
+
+The 'forensics' file outputs the description of security events that
+have occurred when the namespace security model is running in a sealed
+state.  These events are useful for characterizing a security
+intrusion that has occurred or for refinement of a security model.
+
+The 'forensics_coefficients' file outputs the security state
+coefficients that are generated by the forensics events that have
+been captured by the model and available through the 'forensics' file.
+
+The 'forensics_counts" file outputs the number of times that each
+security state coefficient output by the 'forensics_coefficients' file
+has been experienced in the security namespace.  This value can can be
+used for statistical inference as to the anomaly status of the
+namespace.
+
+Trust orchestrators
+===================
+
+In security modeling, the need for a trust orchestrator is embodied in
+Heisenberg's reflections on quantum mechanical modeling.  A modeled
+system cannot model itself without affecting the functional value of
+the security model being implemented.  An external entity is needed to
+setup, configure and monitor the state of a modeled system, in a
+manner that does affect the state of the modeled system itself.
+
+After creating and configuring a security modeling namespace, the
+orchestrator is responsible for executing and monitoring a process
+that is run in the context of the namespace.  The trust orchestrator
+is also responsible for providing access to the status of the security
+model being implemented by the TMA.
+
+Trust orchestrators for externally modeled namespaces, have an
+associated TMA that is responsible for implementing the security model
+for a namespace.  The TMA represents the the root of trust for the
+modeled namespace.  The TMA advises the trust orchestrator as to what
+the trust status for a process should be set to, based on the modeling
+of the security event characteristics that are presented to it by the
+trust orchestrator.
+
+In a trust orchestration architecture, secondary to their integral
+role in maintaining the trust state of the system, the trust
+orchestrators are the highest value security asset running on the
+system.  In order to support this, the Linux TSEM implementation
+implements a new security capability, CAP_ML, only trust orchestrators
+are designed to run with this capability.
+
+The CAP_ML capability is defined as a capability that allows the
+ability of it's holder to use namespace creation and security modeling
+to define the trust status of a system.
+
+Trust orchestrators are designed to drop the CAP_ML capability before
+forking the process that will be responsible for launching a modeled
+workload.  This provides an architecture where the root of trust for
+the system can be predicated on a small body of well audited
+orchestration utilities, that can be linked to a hardware root of
+trust implemented by a TPM or a hardware based TMA.
+
+Quixote
+=======
+
+	"He is awkward, past his prime and engaged in a task beyond his
+	 capacities."
+				- Don Quixote's able mount Rocinante
+
+The Quixote Trust Orchestration System, released in concert with TSEM,
+is an implementation of a trust orchestration environment that
+embodies the characteristics described above.  It provides all off the
+basic functionality needed to build and run security architectures
+based on TSEM using either internal or external TMA implementations.
+
+It is anticipated that Quixote would not be the only such system to
+take advantage of TSEM.  Given the burgeoning capability set of
+systemd, it would be an architecturally valid concept to have systemd,
+or other system init equivalents, gain the ability to launch critical
+system services in security modeled environments.
+
+The source code for Quixote, and TSEM patches for some LTS kernels are
+available at the following URL:
+
+ftp://ftp.enjellic.com/pub/Quixote
+
+The build of Quixote is somewhat formidable, given that it spans the
+range from system programming though SGX programming and into embedded
+micro-controller systems.  In order to facilitate experimentation,
+binaries statically compiled against MUSL libc are provided that have
+virtually no system dependencies, other than a TSEM enabled kernel.
+
+Sample utilities
+----------------
+
+The Quixote TSEM implementation implements a separate trust
+orchestration utility for each TMA environment, nee Sancho partner,
+that is supported:
+
+quixote	     -> TMA run in the kernel for internally modeled namespaces.
+
+quixote-us   -> TMA run in a userspace process.
+
+quixote-xen  -> TMA run in a Xen based stub domain.
+
+quixote-sgx  -> TMA run in an SGX enclave.
+
+quixote-mcu* -> TMA run in a micro-controller implementation.
+
+* = See discussion below.
+
+Each utility runs in one of two modes: process or container
+
+In process mode, a shell process is run as the workload process in a
+modeling namespace.  This mode is selected with the -P command-line
+option.
+
+In container mode, the default, the OCI runc utility is run as the
+workload process, with a 'bundle' argument that specifies a directory
+that contains a JSON container definition for a directory hierarchy in
+the bundle directory.  The /var/lib/Quixote/Magazine directory
+contains the bundle directories.
+
+The -c command-line option selects container mode, the argument to the
+option specifies the bundle directory for the runc utility.
+
+In order to support the creation of security models, each utility
+supports the -o command-line option to specify that a security model
+description be output when the modeled workload terminates.  The model
+is written to the name of the file supplied via the command-line
+option.
+
+If the -t command-line option is also specified, the security
+execution trajectory, rather than a model consisting of security state
+coefficients, is written to the output file.  This trajectory
+represents the description of the security events that were modeled.
+This trajectory can be converted to security state coefficients with
+the generate-states utility that is also provided in the utilities
+package.
+
+The -m command-line option is used to specify a model that is to be
+loaded into the TMA and optionally enforced.  By default the security
+model output with the -o command-line option will place the TMA in a
+sealed modeling state.  Any security events that are non-compliant
+with the model will be registered as forensics events.
+
+Adding the -e command-line option, with the '-m FILENAME' option, will
+cause the loaded model to be enforced.  Any forensic events will cause
+a permission denial to be returned to the caller of a TSEM LSM hook
+implementation.
+
+The Quixote package also includes the quixote-console utility, for
+interrogating the model state of both external and internal TMA's.
+The following command-line options request output of the following
+characteristics of the model:
+
+-C -> The current execution trajectory coefficient counts.
+
+-E -> The log of denied events.
+
+-F -> The current forensics execution trajectory.
+
+-M -> A definition for the current security model.
+
+-P -> The current security state coefficients.
+
+-S -> The state value of the model.
+
+-T -> The current security execution trajectory.
+
+Executing the utility, without these arguments, will cause a
+command-line version of the utility to be presented that takes the
+following arguments:
+
+show trajectory
+
+show coefficients
+
+show counts
+
+show forensics
+
+show forensics_coefficients
+
+show forensics_counts
+
+show state
+
+show model
+
+quit
+
+It is important to note that any of the values output, represent the
+current state of the model and do not reflect a cumulative model of
+the workload.  Capturing a complete workload model requires the use of
+the -m command-line argument to the trust orchestrators to capture a
+model that is representative of the entire execution trajectory of the
+workload after it completes.
+
+As an example, the following security model definition represents the
+execution and termination of a shell session run on a system with a
+hardware TPM:
+
+aggregate de2b9c37eb1ceefa4bcbc6d8412920693d3272f30eb5ba98d51d2f898d620289
+state 97b29769580b412fbf55e326a98d6a1b97c6ebf446aaf78ea38c884e954ca5b2
+state 7c435854b4fa421175ec0a5d3ca7c156480913d85c03155ea3305afa56c9717d
+state 554d9f62693d522c9a43acf40780065f99cea3d67ca629ac4eaab4e22d4e63c2
+state 1b228046c4c2e7aa14db9a29fcff6f718f4f852afbfb76c8a45af7bf0485f9ce
+state 24fd04b10e2b5016e0061952f3bdea959e0fa80a55ff0f4e8e13f9f72ede7498
+state da6038511db71b08c49a838d178ed055e0b7bfc42548b4c2d71eca046e9a222e
+state 94b24ad4c8902f8ecb578a702408e8458e72c0774c402c3bd09ec5f390c4d0ae
+state 5ffa5a2a38f42d89ae74a6d58be8b687c1baed9746d9c6a7ae3c632a2e7c082f
+state a2e309d84bd4a52466c22779a622254c65ad1208583d70113751c4624baa7804
+state e93ceb0b1bf3cd58373a9e9ab4aca11a507782bbfde395ff68f8bfaf1678ed43
+state bf42388d63887368605fac9816134bc67314762c3a97b440cc48c5a30c07fdb9
+state eaa342599d682d63be4b64e159b98f21d85f0133ef5b28588e444ad12e446bf6
+state 2b9c86bc34202504c398c2f177d1dcf807b2f267c160bf8ebda863a9b427917f
+state 686fc3c958f2e4f2ce3b2c6a2cb3fff44ccc4db98869bd377b14e557a5191231
+state 613c39fd2a58413b32f448c13ea4d6bc38b77966dfc5560e39e4b37d2b2f5675
+state 70e276bfd7c20262cd9c9f5b09a922f11d16d1e3a602e8005d68e9ed6afc9b5d
+state 456aaedc5c1fc63f852ee97ae9561aba2a06c416154ecb9d7a1bf9d9a8c9c064
+state 97507c4c91af4a9b34b4d66118f6cc0ba1f8b55b8bb6e623dcafe27b100aea07
+state ea635c48031f81140b3561ed2291a3b1790a302e6adf5244320593b08a5af924
+state 2fd6a4d6ea1869a193926e998fbdf855916b510257d379762f48a1df63a810d4
+state 9c4cb7ef4848be1e29f9eb35fadaf5bfdc1fa3cbb22b6407cbd31b7088257026
+state 66640cbf9ae772515070f8613182b6852bf46220df0833fbe6b330a418fad95b
+state 6b0d1890cbd78c627e23d7a564e77a5ee88fb20e0662ce5e66f3727ebf75fa1d
+state bd28fa43b34850591fdf6fb2aa5542f33c21c20ee91b4bc2034e199b4e09edc1
+state 04425354419e53e6e73cde7d61856ff27763c2be01934e9990c1ae9f8d2a0b6e
+state 2650d86382f6404367b7fdeec07f873b67b9ce26caef09d035b4dff09fce04d5
+state df2f91f5fd84ca4621092420eaf1b0a3743b328a95e3f9e0b7b1281468462aa2
+state c730c66ecfabe99480e61a7f25962582ca7bb6f2b17983048e77adde1fe7f72b
+state 0fc937b71d0067fcc2c2f37c060763de250b3142e621174ffedc1b2520cdf6fd
+state 7f267400a3ccf462c77ae5129799558c2c62d8bc5b388882caec813ab4cf7b7f
+seal
+end
+
+As was previously discussed, the model should be cryptographically
+secure against the elucidation of the security events that resulted in
+the described security states.
+
+The Quixote userspace implementation also contains utilities for
+generating signed versions of these security models.
+
+* MCU TMA's
+-----------
+
+One of the objectives of TSEM/Quixote is to explore architectures for
+trusted systems that extend beyond what is provided by the TPM model
+for security co-processors.  The MCU based reference implementations
+allow experimentation with hardware based TMA's.
+
+The Quixote TSEM utilities include TMA implementations for the
+following following ARM32 based micro-controller platforms:
+
+STM32L496
+
+STM32L562
+
+NRF52840-DK
+
+NRF52840-DONGLE
+
+The STM32L496 platform, in addition to the base TMA implementation,
+includes support for a CAT1-M based cellular modem.  This demonstrates
+the ability of an external TMA to conduct remote, out-of-band,
+signaling of security violations for modeled platforms/workloads and
+the downloading of security models outside the context of the platform
+itself.
+
+The STM32L562 platform is a low power MCU designed for security
+focused IOT implementations.  It includes hardware hashing, hardware
+asymmetric encryption and Trust Zone support.
+
+Of primary interest may be the NRF52840-DONGLE implementation.  This
+is a 'USB fob' form factor board that GOOGLE uses as the basis for
+their OpenSK security key implementation.  This form factor allows the
+development and experimentation with easily deployable hardware based
+TMA implementations.
+
+The NRF52840-DONGLE architecture was chosen by the NLnet sponsored
+'FobNail' project, that is developing a hardware based attestation
+server:
+
+https://fobnail.3mdeb.com/
+
+The Fobnail projects discusses the notion of their architecture
+expanding to provide protection for a Linux system at large.
+Quixote/TSEM, running on the NRF52840-DONGLE micro-controller, is a
+demonstration of such an implementation.
+
+===============
+Closing Remarks
+===============
+
+	"Sometimes it is the people no one can imagine anything of who
+	 do the things no one can imagine.
+				- Alan Turing
+
+While this document is of some length and detail, it hopefully
+fulfills its obligation to provide sufficient prose for the
+justification of the security model that TSEM addresses, and in
+combination with trust orchestrators, implements.
+
+The MAINTAINERS file has contact information for feedback, patches
+and/or questions regarding TSEM and its reference TOS implementation.
+
+     The Quixote Team - Flailing at the Travails of Cybersecurity
+
+	With all due respect to Miguel de Cervantes Saavedra.
+
+   From the glacial moraine lake country of West-Central Minnesota.
+
+ LocalWords:  TSEM Brule Hilaire Belloc attestable namespace TOS TCB LSM LSM's
+ LocalWords:  filesystem metadata TBDHTTRAD tsem Continous workflow namespaces
+ LocalWords:  userspace quixote secundem artem inode boolean multi incent SEM
+ LocalWords:  analysing workflows COE TMA TPM orchestrators SGX Xen TMA's PCR's
+ LocalWords:  IMA PCR namesapces ie workqueue PID's PID OOM ABI SHA bprm creds
+ LocalWords:  linux binprm SMP endian tsemfs ExternalTMA HEXID pre Rocinante de
+ LocalWords:  systemd init LTS MUSL libc xen sgx mcu OCI runc JSON eb ceefa ba
+ LocalWords:  bcbc fbf ebf aaf ec afa acf cea eaab aa fcff afbfb af ce fd bdea
+ LocalWords:  ede da bfc eca ecb bd ae ffa baed ceb cd aca bbfde bfaf fac bc ef
+ LocalWords:  fdb eaa dcf ebda fc cb fff ccc dfc bfd afc aaedc ee aba bb dcafe
+ LocalWords:  aea adf fbdf df fadaf bfdc cbb cbd cbf fbe fb fdf edc cde fdeec
+ LocalWords:  caef dff fce eaf ecfabe adde fe fcc ffedc cdf ccf caec STM NRF DK
+ LocalWords:  IOT USB GOOGLE OpenSK deployable NLnet FobNail Fobnail Saavedra
+ LocalWords:  Cybersecurity hexadecimally BPF Coeff securityfs nsref UID GID sm
+ LocalWords:  API sha crypto InternalTMA HIDS pid FILENAME
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 9e5bab29685f..0e6640a78936 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -6468,6 +6468,24 @@
 			with CPUID.16h support and partial CPUID.15h support.
 			Format: <unsigned int>
 
+	tsem_mode=	[TSEM] Set the mode that the Trusted Security Event
+			Modeling LSM is to run in.
+			Format: 1
+			1 -- Disable root domain modeling.
+
+	tsem_cache=	[TSEM] Define the size of the caches used to hold
+			pointers to structures that will be used to model
+			security events occurring in the root modeling
+			namespace that are called in atomic context.
+			Format: <integer>
+			Default: 96
+
+	tsem_digest=	[TSEM] Define the cryptographic hash function that
+			will be used to create security event coefficients
+			for in the root modeling namespace.
+			Format: {name of the cryptographic hash function}
+			Default: sha256
+
 	tsx=		[X86] Control Transactional Synchronization
 			Extensions (TSX) feature in Intel processors that
 			support TSX control.
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 03/13] Implement CAP_TRUST capability.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
  2023-07-10 10:23 ` [PATCH 01/13] Update MAINTAINERS file Dr. Greg
  2023-07-10 10:23 ` [PATCH 02/13] Add TSEM specific documentation Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-08-07 20:21   ` Casey Schaufler
  2023-07-10 10:23 ` [PATCH 04/13] Add TSEM master header file Dr. Greg
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

TSEM was designed to support a Trust Orchestration System (TOS)
security architecture.  A TOS based system uses the concept of a
minimum Trusted Computing Base of utilities, referred to as trust
orchestrators, that maintain workloads in a trusted execution
state.  The trust orchestrators are thus, from a security
perspective, the most security privileged processes running on
the platform.

The CAP_ML (machine modeling) capability is defined as a
capability that allows a process to alter the modeling and hence
the trust status of the platform.  In a fully orchestrated system
only the trust orchestrator carry this capability bit and then
drop the capability for the execution of the workload.  This is
designed to prevent a security vulnerability in workloads to be
leveraged to create an entity that could conduct adversarial
modifications to the trust status of the platform.

With the introduction of TSEM there are three generic mechanisms
for implementing security contols, each with its own capability
bit for management, ie:

DAC - CAP_DAC_ADMIN

MAC - CAP_MAC_ADMIN

Security modeling - CAP_ML

Having a separate capability bit for security modeling allows DAC
and classic label or path based MAC systems to be implemented in
the context of a security modeling namespace.  Looking forward it
is not unreasonable to consider the implementation of a modeling
policy that would verify the status of extended attributes being
used for label based MAC controls.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 include/uapi/linux/capability.h     | 6 +++++-
 security/selinux/include/classmap.h | 2 +-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h
index 3d61a0ae055d..4a17c9774505 100644
--- a/include/uapi/linux/capability.h
+++ b/include/uapi/linux/capability.h
@@ -417,7 +417,11 @@ struct vfs_ns_cap_data {
 
 #define CAP_CHECKPOINT_RESTORE	40
 
-#define CAP_LAST_CAP         CAP_CHECKPOINT_RESTORE
+/* Allow modifications to the trust status of the system */
+
+#define CAP_ML	41
+
+#define CAP_LAST_CAP         CAP_ML
 
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index a3c380775d41..f367c269bbdb 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -30,7 +30,7 @@
 		"wake_alarm", "block_suspend", "audit_read", "perfmon", "bpf", \
 		"checkpoint_restore"
 
-#if CAP_LAST_CAP > CAP_CHECKPOINT_RESTORE
+#if CAP_LAST_CAP > CAP_ML
 #error New capability defined, please update COMMON_CAP2_PERMS.
 #endif
 
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 04/13] Add TSEM master header file.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (2 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 03/13] Implement CAP_TRUST capability Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-08-07 20:39   ` Casey Schaufler
  2023-07-10 10:23 ` [PATCH 05/13] Add primary TSEM implementation file Dr. Greg
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

TSEM is designed, from a functional perspective, to be contained
entirely in its own directory.

The tsem.h header file defines the enumeration types, structure
definitions and externally visiable functions that are referenced
by all of the compilation units of the TSEM LSM implementation in
that directory.

The structure and enumeration types are extensively documented
and are the recommended starting point for understanding TSEM
implementation and functionality.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/tsem.h | 1516 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1516 insertions(+)
 create mode 100644 security/tsem/tsem.h

diff --git a/security/tsem/tsem.h b/security/tsem/tsem.h
new file mode 100644
index 000000000000..03915f47529b
--- /dev/null
+++ b/security/tsem/tsem.h
@@ -0,0 +1,1516 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * This is the single include file that documents all of the externally
+ * visible types and functions that are used by TSEM.  This file is
+ * currently organized into four major sections in the following order;
+ *
+ * includes used by all compilation units
+ * CPP definitions
+ * enumeration types
+ * structure definitions
+ * function declarations
+ * inline encapsulation functions.
+ *
+ * Include files that are referenced by more than a single compilation
+ * should be included in this file.  Includes that are needed to
+ * satisfy compilation requirements for only a single file should be
+ * included in the file needing that include.
+ *
+ * Understanding the overall implementation and architecture of TSEM
+ * will be facilitated by reviewing the documentation in this file.
+ */
+
+#include <uapi/linux/in.h>
+#include <uapi/linux/in6.h>
+#include <linux/wait.h>
+#include <linux/kref.h>
+#include <linux/lsm_hooks.h>
+#include <linux/capability.h>
+#include <crypto/hash.h>
+#include <crypto/hash_info.h>
+#include <net/af_unix.h>
+
+/* The capability needed to manage TSEM. */
+#define TSEM_CONTROL_CAPABILITY CAP_ML
+
+/*
+ * The number of 'slots' in the structure magazines that are used to
+ * satisfy modeling of security events that are called in atomic context.
+ */
+#define TSEM_ROOT_MAGAZINE_SIZE	96
+#define TSEM_MAGAZINE_SIZE_INTERNAL 16
+#define TSEM_MAGAZINE_SIZE_EXTERNAL 96
+
+/**
+ * enum tsem_event_type - Ordinal value for a security event.
+ * @TSEM_BPRM_SET_CREDS: Ordinal value for bprm_creds_for_exec.
+ * @TSEM_GENERIC_EVENT: Ordinal value for a generically modeled event.
+ * @TSEM_TASK_KILL: Ordinal value for task kill.
+ * @....: Remainder follows with a similar naming format that has
+ *        TSEM_ prep ended to the raw LSM security hook name.
+ * @TSEM_EVENT_CNT: The final ordinal value is used to define the
+ *		    length of the following arrays that are indexed
+ *		    by the ordinal value of the hook:
+ *
+ * This enumeration is used to designate an ordinal value for each
+ * security event, ie. LSM hook, that TSEM is implementing modeling
+ * for.  This value is used to identify the hook that is either having
+ * its event description being exported to an external Trusted Modeling
+ * Agent (TMA) or modeled by the internal TMA implementation.
+ *
+ * The primary use of this enumeration is to conditionalize code paths
+ * based on the security hook being processed and to index the
+ * tsem_names array and the array that defines the action that is to
+ * be taken in response to an event that generates a permissions
+ * violation.
+ */
+enum tsem_event_type {
+	TSEM_BPRM_SET_CREDS = 1,
+	TSEM_GENERIC_EVENT,
+	TSEM_TASK_KILL,
+	TSEM_TASK_SETPGID,
+	TSEM_TASK_GETPGID,
+	TSEM_TASK_GETSID,
+	TSEM_TASK_SETNICE,
+	TSEM_TASK_SETIOPRIO,
+	TSEM_TASK_GETIOPRIO,
+	TSEM_TASK_PRLIMIT,
+	TSEM_TASK_SETRLIMIT,
+	TSEM_TASK_SETSCHEDULER,
+	TSEM_TASK_GETSCHEDULER,
+	TSEM_TASK_PRCTL,
+	TSEM_FILE_OPEN,
+	TSEM_MMAP_FILE,
+	TSEM_FILE_IOCTL,
+	TSEM_FILE_LOCK,
+	TSEM_FILE_FCNTL,
+	TSEM_FILE_RECEIVE,
+	TSEM_UNIX_STREAM_CONNECT,
+	TSEM_UNIX_MAY_SEND,
+	TSEM_SOCKET_CREATE,
+	TSEM_SOCKET_CONNECT,
+	TSEM_SOCKET_BIND,
+	TSEM_SOCKET_ACCEPT,
+	TSEM_SOCKET_LISTEN,
+	TSEM_SOCKET_SOCKETPAIR,
+	TSEM_SOCKET_SENDMSG,
+	TSEM_SOCKET_RECVMSG,
+	TSEM_SOCKET_GETSOCKNAME,
+	TSEM_SOCKET_GETPEERNAME,
+	TSEM_SOCKET_SETSOCKOPT,
+	TSEM_SOCKET_SHUTDOWN,
+	TSEM_PTRACE_TRACEME,
+	TSEM_KERNEL_MODULE_REQUEST,
+	TSEM_KERNEL_LOAD_DATA,
+	TSEM_KERNEL_READ_FILE,
+	TSEM_SB_MOUNT,
+	TSEM_SB_UMOUNT,
+	TSEM_SB_REMOUNT,
+	TSEM_SB_PIVOTROOT,
+	TSEM_SB_STATFS,
+	TSEM_MOVE_MOUNT,
+	TSEM_SHM_ASSOCIATE,
+	TSEM_SHM_SHMCTL,
+	TSEM_SHM_SHMAT,
+	TSEM_SEM_ASSOCIATE,
+	TSEM_SEM_SEMCTL,
+	TSEM_SEM_SEMOP,
+	TSEM_SYSLOG,
+	TSEM_SETTIME,
+	TSEM_QUOTACTL,
+	TSEM_QUOTA_ON,
+	TSEM_MSG_QUEUE_ASSOCIATE,
+	TSEM_MSG_QUEUE_MSGCTL,
+	TSEM_MSG_QUEUE_MSGSND,
+	TSEM_MSG_QUEUE_MSGRCV,
+	TSEM_IPC_PERMISSION,
+	TSEM_KEY_ALLOC,
+	TSEM_KEY_PERMISSION,
+	TSEM_NETLINK_SEND,
+	TSEM_INODE_CREATE,
+	TSEM_INODE_LINK,
+	TSEM_INODE_UNLINK,
+	TSEM_INODE_SYMLINK,
+	TSEM_INODE_MKDIR,
+	TSEM_INODE_RMDIR,
+	TSEM_INODE_MKNOD,
+	TSEM_INODE_RENAME,
+	TSEM_INODE_SETATTR,
+	TSEM_INODE_GETATTR,
+	TSEM_INODE_SETXATTR,
+	TSEM_INODE_GETXATTR,
+	TSEM_INODE_LISTXATTR,
+	TSEM_INODE_REMOVEXATTR,
+	TSEM_INODE_KILLPRIV,
+	TSEM_TUN_DEV_CREATE,
+	TSEM_TUN_DEV_ATTACH_QUEUE,
+	TSEM_TUN_DEV_ATTACH,
+	TSEM_TUN_DEV_OPEN,
+	TSEM_BPF,
+	TSEM_BPF_MAP,
+	TSEM_BPF_PROG,
+	TSEM_EVENT_CNT
+};
+
+/**
+ * enum tsem_action_type - Ordinal value for security responses.
+ * @TSEM_ACTION_LOG: Ordinal value to indicate that a security event
+ *		     that results in a model permissions violation
+ *		     should be logged.
+ * @TSEM_ACTION_EPERM: Ordinal value to indicate that a security event
+ *		       generating a model permissions violation should
+ *		       return -EPERM to the caller.
+ *
+ * This enumeration type is used to designate what type of action is
+ * to be taken when the processing of a security event hook results in
+ * a model violation.  The TSEM_ACTION_LOG and TSEM_ACTION_EPERM
+ * translate into the classical concepts of logging or enforcing
+ * actions used by other mandatory access control architectures.
+ */
+enum tsem_action_type {
+	TSEM_ACTION_LOG = 0,
+	TSEM_ACTION_EPERM,
+	TSEM_ACTION_CNT
+};
+
+/**
+ * enum tsem_control_type - Ordinal values for TSEM control actions.
+ * @TSEM_CONTROL_INTERNAL: This ordinal value is set when the first
+ *			   word of an argument string written to the
+ *			   control file is the word 'internal'.  This
+ *			   designates that the security namespace will
+ *			   be modeled by the internal TMA.
+ * @TSEM_CONTROL_EXTERNAL: This ordinal value is set when the first
+ *			   word of an argument string written to the
+ *			   control file is the word 'external'.  This
+ *			   designates that the security namespace will
+ *			   be model by an external TMA.
+ * @TSEM_CONTROL_ENFORCE: This ordinal value is set when the word
+ *			  'enforce' is written to the control file.
+ *			  This indicates that model is to be placed
+ *			  in 'enforcing' mode and security events that
+ *			  result in model violations will return EPERM.
+ * @TSEM_CONTROL_SEAL: This ordinal value is set when the word 'seal'
+ *		       is written to the control file.  This indicates
+ *		       that the model for security domain will treat
+ *		       all security events that do not conform to the
+ *		       model as 'forensics' events.
+ * @TSEM_CONTROL_TRUSTED: This ordinal value is used when the first
+ *			  word of an argument string written to the
+ *			  control file is the word 'trusted'.  This
+ *			  is interpreted as a directive to set the
+ *			  trust status of the task that executed the
+ *			  security event to be trusted.
+ * @TSEM_CONTROL_UNTRUSTED: This ordinal value is used when the first
+ *			    word of an argument string written to the
+ *			    control file is the word 'untrusted'.
+ *			    This is interpreted as a directive to set
+ *			    the trust status of the task that executed
+ *			    the security event to be untrusted.
+ * @TSEM_CONTROL_MAP_STATE: This ordinal value is used when the first
+ *			    word of an argument string written to the
+ *			    control file is the word 'state'.  The
+ *			    argument to this directive will be an
+ *			    ASCII hexadecimally encoded string of the
+ *			    current model's digest size that will be
+ *			    treated as a security state point for
+ *			    inclusion in the security model for the
+ *			    security domain/namespace.
+ * @TSEM_CONTROL_MAP_PSEUDONYM: This ordinal value is used when the
+ *				first word of an argument string
+ *				written to the control file is the
+ *				word 'pseudonym'.  The argument to
+ *				this directive will be an ASCII
+ *				hexadecimally encoded string of the
+ *				current model's digest size that will
+ *				be treated as a pseudonym directive
+ *				for the security domain/namespace.
+ * TSEM_CONTROL_MAP_BASE: This ordinal value is used when the first
+ *			  word of an argument string written to the
+ *			  control file is the word 'base'.  The
+ *			  argument to this directive will be an ASCII
+ *			  hexadecimally encoded string of the current
+ *			  model's digest size that will be treated as
+ *			  the base value for the computation of the
+ *			  functional values (measurement and state) of
+ *			  the security domain/namespace.
+
+ * This enumeration type is used to designate what type of control
+ * action is to be implemented when arguments are written to the TSEM
+ * control file (/sys/kernel/security/tsem/control).  The ordinal
+ * values govern the processing of the command and the interpretation
+ * of the rest of the command argument string.
+ */
+enum tsem_control_type {
+	TSEM_CONTROL_INTERNAL = 0,
+	TSEM_CONTROL_EXTERNAL,
+	TSEM_CONTROL_ENFORCE,
+	TSEM_CONTROL_SEAL,
+	TSEM_CONTROL_TRUSTED,
+	TSEM_CONTROL_UNTRUSTED,
+	TSEM_CONTROL_MAP_STATE,
+	TSEM_CONTROL_MAP_PSEUDONYM,
+	TSEM_CONTROL_MAP_BASE
+};
+
+/**
+ * enum tsem_ns_reference - Ordinal value for DAC namespace reference.
+ * @TSEM_NS_INITIAL: This ordinal value indicates that the uid/gid
+ *		     values should be interpreted against the initial
+ *		     user namespace.
+ * @TSEM_NS_CURRENT: This ordinal value indicates that the uid/gid
+ *		     values should be interpreted against the user
+ *		     namespace that is in effect for the process being
+ *		     modeled.
+ *
+ * This enumeration type is used to indicate what user namespace
+ * should be referenced when the uid/gid values are interpreted for
+ * the creation of either the COE or CELL identities.  The enumeration
+ * ordinal passed to the tsem_ns_create() function, to configure the
+ * security domain/namespace, is set by the nsref argument to either
+ * the 'internal' or 'external' control commands.
+ */
+enum tsem_ns_reference {
+	TSEM_NS_INITIAL = 1,
+	TSEM_NS_CURRENT
+};
+
+/**
+ * enum tsem_task_trust - Ordinal value describing task trust status.
+ * @TSEM_TASK_TRUSTED: This ordinal value indicates that the task has
+ *		       not executed a security event that has resulted
+ *		       in a security behavior not described by the
+ *		       security model the task is being governed by.
+ * @TSEM_TASK_UNTRUSTED: This ordinal value indicates that the task
+ *		          has requested the execution of a security event
+ *		          that resulted in a security behavior not
+ *		          permitted by the security model the task is
+ *		          being governed by.
+ * @TSEM_TASK_TRUST_PENDING: This ordinal value indicates that the setting
+ *			     of the task trust status is pending a response
+ *		             from an external TMA.
+ *
+ * This enumeration type is used to specify the three different trust
+ * states that a task can be in.  The trust status of a task is
+ * regulated by the trust_status member of struct tsem_task.  A task
+ * carrying the status of TSEM_TASK_TRUSTED means that it has
+ * not requested the execution of any security events that are
+ * inconsistent with the security model that the task is running in.
+ *
+ * If a task requests execution of a security event that is
+ * inconsistent with the security model it is operating in, and the
+ * domain is running in 'sealed' mode, the task trust status is set to
+ * TSEM_TASK_UNTRUSTED.  This value is 'sticky' in that it will be
+ * propagated to any child tasks that are spawned from an untrusted
+ * task.
+ *
+ * In the case of an externally modeled security domain/namespace, the
+ * task trust status cannot be determined until the modeling of the
+ * security event has been completed.  The tsem_export_event()
+ * function sets the trust status TSEM_TASK_TRUST_PENDING and then
+ * places the task into an interruptible sleep state.
+ *
+ * Only two events will cause the task to be removed from sleep state.
+ * Either the task is killed or a control message is written to the
+ * TSEM control file that specifies the trust status of the task.  See
+ * the description of the TSEM_CONTROL_TRUSTED and
+ * TSEM_CONTROL_UNTRUSTED enumeration types.
+ */
+enum tsem_task_trust {
+	TSEM_TASK_TRUSTED = 1,
+	TSEM_TASK_UNTRUSTED = 2,
+	TSEM_TASK_TRUST_PENDING = 4
+};
+
+/**
+ * enum tsem_inode_state - Ordinal value for inode reference state.
+ * @TSEM_INODE_COLLECTING: This ordinal value indicates that the uid/gid
+ *			   values should be interpreted against the initial
+ *			   user namespace.
+ * @TSEM_INODE_COLLECTED: This ordinal value indicates that the uid/gid
+ *			  values should be interpreted against the user
+ *			  namespace that is in effect for the process being
+ *		          modeled.
+ *
+ * This enumeration type is used to specify the status of the inode
+ * that is having a digest value computed on the file that it is
+ * referencing.  The purpose of this enumeration is so that the
+ * recursive call to the TSEM_FILE_OPEN hook, caused by the kernel
+ * opening the file to compute the checksum, can be bypassed.
+ *
+ * The state value of the inode is carried in struct tsem_inode and is
+ * set and interrogated by the add_file_digest() function.  If the
+ * status of the inode is TSEM_INODE_COLLECTED and the iversion of the
+ * inode is the same as the collection time, the cached value for
+ * currently active model digest is returned.
+
+ * If the test for the relevancy of the cached digest value fails the
+ * status of the inode is set to TSEM_INODE_COLLECTING.  The
+ * tsem_file_open() function will check the inode status when it is
+ * invoked by the integrity_kernel_read() function and if it is
+ * set to 'collecting', a successful permissions check is returned so
+ * that the kernel can open the file and compute its digest.
+ */
+enum tsem_inode_state {
+	TSEM_INODE_COLLECTING = 1,
+	TSEM_INODE_COLLECTED
+};
+
+/**
+ * struct tsem_task - TSEM task control structure.
+ * @tma_for_ns: The context identity number of the namespace that
+ *		the task has control over if any.
+ * @trust_status: The enumeration type that specifies the trust state of
+ *		  the process.
+ * @task_id: The hash specific digest that identifies the process.
+ * @task_key: A hash specific digest value that is used to
+ *	      authenticate a task that is running as a trust
+ *	      orchestrator to a task that is under the control of the
+ *	      orchestrator.
+ * @context: A pointer to the tsem_context structure that defines the
+ *	     modeling context that the task is running under.
+ *
+ * This structure is one of the two primary control structures that
+ * are implemented through the LSM blob functionality.  It is
+ * automatically created when the task control structure is allocated
+ * for a new task that is being created.  It's role is to control the
+ * status of the task with respect to its security model.
+ *
+ * The trust_status member of structure determines whether or not the
+ * task is in a condition to be trusted.  It represents whether or not
+ * the task has requested execution of a security event that is
+ * inconsistent with the model that the task is running under.
+ * Reference the tsem_trust_status enumeration type for more
+ * information on this member.  The trust status value is propagated
+ * to any child tasks that are spawned from a task.
+ *
+ * The digest value that the task_id member contains is generated by
+ * the tsem_tsem_bprm_creds_for_exec() function that computes the
+ * task identity based on the COE identity and the CELL identity of
+ * the executable that is being started.  This task_id value is used
+ * in the computation of the security state point values in
+ * combination with the COE and CELL identities for this event.  The
+ * task_id digest creates security state points that are specific to
+ * the executable file that was used to start the task.
+ *
+ * The task_key member holds the authentication key that will be used
+ * to authenticate a process that is requesting the ability to set the
+ * trust status of a process.  This value is generated for the task
+ * structure of the trust orchestrator when a security modeling
+ * namespace is created by the orchestrator.
+ *
+ * As an additional protection, the creation of a namespace causes the
+ * context id of the created namespace to be placed in the task that
+ * will serve as the trust orchestrator for the namespace.  This
+ * context id must match the context id of a process that a trust
+ * control request is being sent to.  Like the authentication key
+ * this value is not propagated on task allocation so only the task
+ * that has nominated the security modeling namespace will have
+ * possession of the necessary credentials to control it.
+ *
+ * The context member of the structure contains a pointer to the
+ * tsem_context structure allocated when a security modeling namespace
+ * is created by the tsem_ns_create() function.  This structure will
+ * contain all of the information needed to define how the task is to
+ * have its security behavior modeled.
+ */
+struct tsem_task {
+	u64 tma_for_ns;
+	enum tsem_task_trust trust_status;
+	u8 task_id[HASH_MAX_DIGESTSIZE];
+	u8 task_key[HASH_MAX_DIGESTSIZE];
+	struct tsem_context *context;
+};
+
+/**
+ * struct tsem_context - TSEM modeling context description.
+ * @kref: Reference count for the context.
+ * @work: Work structure for delayed release of the context.
+ * @id: The index number of the context.
+ * @sealed: Status variable indicating whether or not the
+ *	    modeling context can be modified.
+ * @use_current_ns: Status variable indicating which user namespace
+ *		    should be used for resolution of uid/gid values.
+ * @actions: An array of enum tsem_action_type variables indicating
+ *	     the type of response that should be returned in
+ *	     response to the modeling of a security event that
+ *	     is inconsistent with the model being used for the
+ *	     security context.
+ * @digestname: A pointer to a null-terminated buffer containing the
+ *		name of the digest function that is to be used for
+ *		this security context.
+ * @zero_digest: The digest value for a 'zero-length' digest value.
+ * @tfm: A pointer to the digest transformation structure that is to
+ *	 be used for this context.
+ * @magazine_size: The number of struct tsem_event structures that
+ *		   are held in reserve for security event hooks that
+ *		   are called in atomic context.
+ * @magazine_lock: The spinlock that protects access to the event
+ *		   magazine for the security context.
+ * @magazine_index: The bitmap that is used to track the magazine slots
+ *		    that have been allocated.
+ * @ws: An array of work structures that are used to refill the magazine
+ *	slots.
+ * @magazine: An array of pointers to struct tsem_event structures that
+ *	      are pre-allocated for security hooks called in atomic
+ *	      context.
+ * @model: If the modeling context is implemented with a kernel based
+ *	   trusted model agent this pointer will point to the struct
+ *	   tsem_model structure that maintains the state of the
+ *	   security model.
+ * @external: If the modeling context is implemented with an external
+ *	      modeling agent this pointer will point to the struct
+ *	      tsem_external structure that implements the interface to
+ *	      the external trusted modeling agent.
+
+ * This structure is used to represent the state of a TSEM security
+ * modeling namespace.  A pointer to this structure is stored in the
+ * struct tsem_task structure.
+ *
+ * This structure is allocated by the tsem_ns_create() function in
+ * response to a TSEM control request.  This structure maintains all
+ * of the information that describes the security modeling namespace
+ * that is not specific to the type of namespace, ie. external or
+ * internal that is being implemented.
+
+ * The id member is a 64-bit counter that cannot feasibly be
+ * overflowed and that is incremented for each namespace creation that
+ * is created.  The root modeling namespace has a value of zero so the
+ * TSEM code uses a pattern of testing this value for non-zero status
+ * as an indication of whether or not the task is running in a
+ * subordinate modeling namespace.
+
+ * Each security modeling namespace can have an independent
+ * cryptographic digest function that is used as the compression
+ * function for generating the digest values that are used to model
+ * the security events that occur in a namespace.  A single struct tfm
+ * is allocated for this digest function at the time that the
+ * tsem_context structure is created and is maintained in this
+ * structure for subsequent use during event processing.
+
+ * Each cryptographic digest function has a 'zero message' value that
+ * is the result of the initialization and closure of a hash function
+ * that has no other input.  This zero digest value is computed at the
+ * time of the creation of the array.  This digest value is returned
+ * for files with zero sizes or that have pseudonyms declared for
+ * them.
+ *
+ * The actions array contains a specification of how each security
+ * event should be handled in the event that the model detects a
+ * security event consistent with the model designated for the
+ * namespace.  This array allows the specification of whether the
+ * model should be enforcing or logging.  Currently the specification
+ * is all or nothing for all of the events, with plans to make the
+ * actions individually configurable.
+
+ * Each security event that is processed requires a struct tsem_event
+ * structure that drives either the internal modeling of an event or
+ * its export to an external modeling agent.  Some security event
+ * hooks are called while a task is running in atomic context. Since
+ * memory cannot be allocated while a process is in atomic context, a
+ * magazine of these structures is maintained by this structure for
+ * security events that run in atomic context.  The size of this
+ * magazine is dynamic and is configurable for each security modeling
+ * namespace that is created.
+ *
+ * When a tsem_event structure is allocated for an atomic event a
+ * request for the refill of the slot that is vacated is dispatched to
+ * an asynchronous workqueue.  The ws member of this structure points
+ * to an array of work structures for this refill capability, one for
+ * each slot in the magazine.
+ *
+ * All of this infrastructure is generic for each security modeling
+ * namespace.  How the security modeling is done is governed by the
+ * model and external members of this structure.  These members point
+ * to data structures that either maintain the security model state
+ * for an in kernel trusted modeling agent or handle the export of the
+ * event to an external trusted modeling agent.
+ *
+ * Each task that is created in a non-root security modeling namespace
+ * increments the reference count maintained in the kref member of
+ * this structure in the tsem_task_alloc() function.  The
+ * tsem_task_free() function decrements this reference count.  When
+ * the reference count expires, ie. when the last task using the
+ * modeling namespace exits, an asynchronous workqueue request is
+ * dispatched to dispose of the context.  The work member of this
+ * structure is used to reference that workqueue request.
+ */
+struct tsem_context {
+	struct kref kref;
+	struct work_struct work;
+
+	u64 id;
+	bool sealed;
+	bool use_current_ns;
+
+	enum tsem_action_type actions[TSEM_EVENT_CNT];
+
+	char *digestname;
+	u8 zero_digest[HASH_MAX_DIGESTSIZE];
+	struct crypto_shash *tfm;
+
+	unsigned int magazine_size;
+	spinlock_t magazine_lock;
+	unsigned long *magazine_index;
+	struct tsem_work *ws;
+	struct tsem_event **magazine;
+
+	struct tsem_model *model;
+	struct tsem_external *external;
+};
+
+/**
+ * struct tsem_model - TSEM internal TMA description.
+ * @have_aggregate: Flag variable to indicate whether or not the
+ *		    hardware aggregate value has been injected into
+ *		    the mode.
+ * @base: The base value that is to be used in computing the
+ *	  measurement and state values of the model.
+ * @measurement: The time dependent linear extension state of the
+ *		 model.
+ * @state: The time independent linear extension state of the model.
+ * @point_lock: The spinlock that protects access to the list of
+ *		security state coefficients in the model.
+ * @point_list: A pointer to the list of security state coefficients
+ *		in the model.
+ * @point_end_mutex: The mutex that is used to protect the end of the
+ *		     list of security state coefficients for the
+ *		     model.
+ * @point_end: A pointer to the end of the list of security state
+ *	       coefficients that will be traversed by a call to the
+ *	       control plane.
+ * @trajectory_lock: The spinlock used to protect the list of security
+ *		     event descriptions in the model.
+ * @trajectory_list: A pointer to the list of descriptions of the
+ *		     security events that have been recorded in this
+ *		     model.
+ * @trajectory_end_mutex: The mutex that protects the end of the list
+ *			  of security event descriptions.
+ * @trajectory_end: A pointer to the end of the list of security event
+ *		    descriptions that will be traversed by a call to
+ *		    the control plane.
+ * @forensics_lock: The spinlock used to protect the list of security
+ *		    event descriptions that are considered invalid by
+ *		    the model being enforced.
+ * @forensics_list: A pointer to the list of descriptions of security
+ *		    events that are considered invalid by the security
+ *		    model being enforced.
+ * @forensics_end_mutex: The mutex that protects the end of the list
+ *			 of security event descriptions that are
+ *			 considered invalid by the current model.
+ * @forensics_end: A pointer to the end of the list of security event
+ *		   descriptions, that are considered invalid, that are
+ *		   to be traversed by a call to the control plane.
+ * @pseudonym_mutex: The mutex lock that protects the list of file
+ *		     digest pseudonyms for the current model.
+ * @pseudonum_list: A pointer to the list of file digest pseudonyms
+ *		    that have been declared for the current model.
+ * @magazine_size: The number of struct tsem_event_point structures that
+ *		   are held in reserve for security event hooks that
+ *		   are called in atomic context.
+ * @magazine_lock: The spinlock that protects access to the event
+ *		   magazine for the security context.
+ * @magazine_index: The bitmap that is used to track the magazine slots
+ *		    that have been allocated.
+ * @ws: An array of work structures that are used to refill the magazine
+ *	slots.
+ * @magazine: An array of pointers to struct tsem_event_point structures that
+ *	      are pre-allocated for security hooks called in atomic
+ *	      context.
+ *
+ * If a call to the tsem_ns_create() function specifies that a kernel
+ * based trusted modeling agent is to be used to implement the
+ * security namespace model, a pointer to this structure is placed in
+ * the struct tsem_context structure.  This structure is used to
+ * maintain the state of the kernel based model.
+ *
+ * There are two primary functional values that are maintained by the
+ * model.  The measurement member of this structure represents the
+ * time dependent linear extension sum of the security state
+ * coefficients that have been assigned to security events that have
+ * occurred in the context of the model.
+ *
+ * This classic integrity measurement is subject to scheduling
+ * dependencies and may be invariant from run to run of the model.  It
+ * is of primary use in verifying the order of security events that
+ * have occurred in the model.
+ *
+ * The state member of this structure represents a time independent
+ * linear extension sum of the security state coefficients that have
+ * been generated in the model.  It represents the linear extension
+ * sum of the security state coefficients that have been sorted in
+ * natural (big-endian) form.
+ *
+ * Both of these measurements are dependent on the platform hardware
+ * aggregate value and the base point that has been defined for the
+ * define.
+ *
+ * A non-zero hardware aggregate value is only available if the
+ * platform has a TPM.  The have_aggregate member of this structure is
+ * a flag variable that indicates whether or not the aggregate value
+ * has been injected into the model.
+ *
+ * The base member of this structure contains a model specific
+ * coefficient that is used to perturb each security state coefficient
+ * generated in the model.  This value is designed to serve as a
+ * 'freshness' value for a verifying party to the model.
+ *
+ * There are three primary model lists maintain by this structure:
+ *
+ * * security state points
+ * * security trajectory events
+ * * security forensics events
+ *
+ * Similar members are maintained in this structure to support each of
+ * these lists.
+ *
+ * All three lists are extension only and are protected by a spinlock
+ * that can be held in atomic context.  This spinlock is only held for
+ * the period of time required to extend the list.
+ *
+ * Calls by the control plane to interrogate the lists require the
+ * traversal of the list that is ill-suited for a spinlock.  As a
+ * result each list type has a mutex associated with it that protects
+ * a pointer to the end of the list, an endpoint that is determined at
+ * the start of a call to the control plane.
+ *
+ * The list spinlock is used at the start of the control plane call to
+ * capture the end of the list that is then protected by the mutex.
+ * In essence this is used to transition protection of the list from
+ * the spinlock to the mutex.
+ *
+ * The kernel based modeling agent has support for maintaining a
+ * constant digest value for files, that by function, do not have a
+ * fixed digest value, such as log files.  The pseudonym_list member
+ * of this structure points to the list of these designations.  The
+ * pseudonym_mutex structure protects this list.
+ *
+ * Like the struct tsem_context structure the tsem_model structure
+ * maintains a magazine of structures that are used to service
+ * security events that are called in atomic context.  The magazine
+ * maintained by this structure is a list of struct tsem_event_point
+ * structures that are used to describe the security state
+ * coefficients held by the model.
+ *
+ * The description of struct tsem_context details the implementation
+ * of the magazine which is identical to the implementation for this
+ * structure, with the exception of the type of structures that are
+ * held in reserve.
+ */
+struct tsem_model {
+	bool have_aggregate;
+
+	u8 base[HASH_MAX_DIGESTSIZE];
+	u8 measurement[HASH_MAX_DIGESTSIZE];
+	u8 state[HASH_MAX_DIGESTSIZE];
+
+	spinlock_t point_lock;
+	struct list_head point_list;
+	struct mutex point_end_mutex;
+	unsigned int point_count;
+	struct list_head *point_end;
+
+	spinlock_t trajectory_lock;
+	struct list_head trajectory_list;
+	struct mutex trajectory_end_mutex;
+	struct list_head *trajectory_end;
+
+	spinlock_t forensics_lock;
+	struct list_head forensics_list;
+	struct mutex forensics_end_mutex;
+	struct list_head *forensics_end;
+
+	struct mutex pseudonym_mutex;
+	struct list_head pseudonym_list;
+
+	unsigned int magazine_size;
+	spinlock_t magazine_lock;
+	unsigned long *magazine_index;
+	struct tsem_work *ws;
+	struct tsem_event_point **magazine;
+};
+
+/**
+ * struct tsem_external - TSEM external TMA description.
+ * @export_lock: The spinlock that protects access to the export_list
+ *		 member of this structure.
+ * @export_list: A pointer to the list of events waiting to be
+ *		 exported to the trust orchestrator for the security
+ *		 modeling namespace.  The structure type that is
+ *		 linked by this list is the struct export_event
+ *		 structure that is private to the export.c compilation
+ *		 unit.
+ * @dentry: A pointer to the dentry describing the pseudo-file in the
+ *	    /sys/kernel/security/tsem/ExternalTMA directory that is
+ *	    being used to export security event descriptions to the
+ *	    external trust orchestrator for the security modeling
+ *	    domain described by this structure.
+ * @have_event: A flag variable to indicate that there is work queued
+ *		on the export pseudo-file for the security modeling
+ *		namespace.
+ * @wq: The work queue used to implement polling for the security
+ *	event export file for the security modeling namespace.
+ * @magazine_size: The number of struct export_event structures that
+ *		   are held in reserve for security event hooks that
+ *		   are called in atomic context.
+ * @magazine_lock: The spinlock that protects access to the event
+ *		   magazine for the security modeling domain.
+ * @magazine_index: The bitmap that is used to track the magazine slots
+ *		    that have been allocated.
+ * @ws: An array of work structures that are used to refill the magazine
+ *	slots.
+ * @magazine: An array of pointers to struct export_event structures that
+ *	      are pre-allocated for security hooks called in atomic
+ *	      context.
+ *
+ * If an externally modeled security modeling namespace is created
+ * a structure of this type is allocated for the namespace and placed
+ * in the struct tsem_context structure.
+ *
+ * The primary purpose of this structure is to manage event
+ * descriptions that are being transmitted to the trust orchestrator
+ * associated with the security modeling namespace.  The pseudo-file
+ * will be as follows:
+ *
+ * /sys/kernel/security/tsem/ExternalTMA/N
+ *
+ * Where N is the context id number of the modeling namespace.
+ *
+ * The dentry member of this structure is used to represent the
+ * pseudo-file that is created when the external modeled namespace is
+ * created.
+ *
+ * This list of events waiting to be received by the trust
+ * orchestrator is maintained in the export_list member of this
+ * structure.  Additions or removals from the list hold the spinlock
+ * described by the export_lock member of this structure.
+ *
+ * The wq member of this structure is used to implement a workqueue
+ * to support polling for events on the export control file.  The
+ * have_event flag is set to indicate to the polling call that
+ * security events are available for export.
+ *
+ * When a security event description is exported the calling task is
+ * scheduled away to allow the trust orchestrator to process the
+ * event.  This obviously creates issues for security events that are
+ * called in atomic context.
+ *
+ * Security events in atomic context are exported as an async_event
+ * rather than a simple event.  The trust orchestrator has the option
+ * of killing the workload that deviated from the security model or
+ * signaling a violation of the model.
+ *
+ * To support the export of asynchronous events a magazine, similar to
+ * the event and model structure magazines, is maintained by this
+ * structure for the external modeling namespace.
+ */
+struct tsem_external {
+	spinlock_t export_lock;
+	struct list_head export_list;
+	struct dentry *dentry;
+	bool have_event;
+	wait_queue_head_t wq;
+
+	unsigned int magazine_size;
+	spinlock_t magazine_lock;
+	unsigned long *magazine_index;
+	struct tsem_work *ws;
+	struct export_event **magazine;
+};
+
+/**
+ * struct tsem_work - TSEM magazine refill work structure.
+ * @index: The index number of the slot in the structure magazine that
+ *	   is being refilled.
+ * @u: A union that holds pointers to the structure whose magazine is
+ *     being refilled.
+ * @work: The work structure that manages the workqueue being used to
+ *	  refill the magazine entry.
+ *
+ * As has been previously documented for the struct tsem_context,
+ * struct tsem_model and struct tsem_external structures, there is a
+ * need to maintain a magazine of these structures in order to allow
+ * the processing of security events that are called in atomic
+ * context.  An array of this structure type is embedded in each of
+ * these structures to manage the asynchronous refill of the slot in
+ * the magazine that was used to handle an atomic security event.
+ *
+ * The index member of this structure points to the slot in the
+ * magazine that this work item is referencing.
+ *
+ * The structure that the refill work is being done for is maintained
+ * in the respective structure pointer in the u member of this
+ * structure.
+ *
+ * The work member of this structure is used to reference the
+ * asynchronous work request that is being submitted for the refill.
+ */
+struct tsem_work {
+	unsigned int index;
+	union {
+		struct tsem_context *ctx;
+		struct tsem_model *model;
+		struct tsem_external *ext;
+	} u;
+	struct work_struct work;
+};
+
+/**
+ * struct tsem_COE - TSEM context of execution definition structure.
+ * @uid: The numeric user identity that the COE is running with.
+ * @euid: The effective user identity that the COE is running with.
+ * @suid: The saved user identity possessed by the COE.
+ * @gid: The group identity that the COE is running with.
+ * @egid: The effective group identity that the COE possesses.
+ * @sgid: The saved group identity of the COE.
+ * @fsuid: The filesystem user identity that the COE is running with.
+ * @fsgid: The filesystem group identity that the COE is running with.
+ * @capeff: This union is used to implement access to the effective
+ *	    capability set the COE is running with.  The mask value
+ *	    is used to assign to the structure with the value member
+ *	    used to extract the 64 bit value for export and
+ *	    computation.
+ *
+ * A security state coefficient is computed from two primary entities:
+ * the COE and the CELL identities.  This structure is used to carry
+ * and encapsulate the characteristics of the context of execution
+ * (COE) that will be used to generate the COE identity.
+ *
+ * The numeric values for discretionary access controls, ie. uid, gid,
+ * are determined by which user namespace the security modeling
+ * namespace is configured to reference.  The reference will be either
+ * the initial user namespace or the user namespace that the context
+ * of execution is running in.
+ */
+struct tsem_COE {
+	uid_t uid;
+	uid_t euid;
+	uid_t suid;
+
+	gid_t gid;
+	gid_t egid;
+	gid_t sgid;
+
+	uid_t fsuid;
+	gid_t fsgid;
+
+	union {
+		kernel_cap_t mask;
+		u64 value;
+	} capeff;
+};
+
+/**
+ * struct tsem_COE - TSEM file description.
+ * @uid: The numeric user identity of the file.
+ * @gid: The numeric group identity of the file.
+ * @mode: The discretionary access mode for the file.
+ * @flags: The file control flags.
+ * @name_length: The length of the pathname of the file.
+ * @name: The digest value of the pathname of the file using the
+ *	  hash function defined for the security modeling namespace.
+ * @s_magic: The magic number of the filesystem that the file resides
+ *	     in.
+ * @s_id: The name of the block device supporting the filesystem.
+ * @s_uuid: The uuid of the filesystem that the file resides in.
+ * @digest: The digest value of the contents of the file using the
+ *	    hash function defined for the security modeling namespace.
+ *
+ * This structure and the structures that follow up to the struct
+ * tsem_event structure are used to identify the various entities that
+ * are involved in the definition of the CELL identity for a security
+ * event.
+ *
+ * The tsem_file structure is used to encapsulate the characteristics
+ * of a file that is used as an entity in the CELL definition of an
+ * event.
+ *
+ * Since a pathname can be up to PATH_MAX (4096 bytes) in length the
+ * cryptographic digest value is used rather than the pathname of the
+ * file itself.
+ */
+struct tsem_file {
+	uid_t uid;
+	gid_t gid;
+	umode_t mode;
+	u32 flags;
+
+	u32 name_length;
+	u8 name[HASH_MAX_DIGESTSIZE];
+
+	u32 s_magic;
+	u8 s_id[32];
+	u8 s_uuid[16];
+
+	u8 digest[HASH_MAX_DIGESTSIZE];
+};
+
+/**
+ * struct tsem_COE - TSEM memory mapped file characteristics.
+ * @file: The struct file definition for the file that is being
+ *	  mapped.  This pointer will be null in the case of an
+ *	  anonymous mapping.
+ * @anonymous: A flag variable to indicate whether or not the mapping
+ *	       is file backed or anonymous.
+ * @reqprot: The memory protection flags that are requested by the
+ *	     memory mapping system call.
+ * @prot: The protections that will be applied to the mapping.
+ * @flags: The control flags of the memory mapping call.
+ *
+ * This structure is used to encapsulate the arguments provided to the
+ * tsem_mmap_file security event handler.
+ */
+struct tsem_mmap_file_args {
+	struct file *file;
+	u32 anonymous;
+	u32 reqprot;
+	u32 prot;
+	u32 flags;
+};
+
+/**
+ * struct tsem_socket_create_args - TSEM socket creation arguments.
+ * @family: The family name of the socket whose creation is being
+ *	    requested.
+ * @type: The type of the socket being created.
+ * @protocol: The protocol family of the socket being created.
+ * @kern: A flag variable to indicate whether or not the socket being
+ *	  created is kernel or userspace based.
+ *
+ * This structure is used to encapsulate the arguments provided to the
+ * tsem_socket_create security event handler.
+ */
+struct tsem_socket_create_args {
+	int family;
+	int type;
+	int protocol;
+	int kern;
+};
+
+/**
+ * struct tsem_socket_connection_args - TSEM socket connection arguments.
+ * @tsip: A pointer to the struct tsem_inode structure that describes
+ *	  the TSEM inode characteristics of the inode representing
+ *	  the socket.
+ * @addr: A pointer to the structure describing the socket address
+ *	  that is being connected.
+ * @addr_len: The length of the socket address description structure.
+ * @family: The family number of the socket.
+ *
+ * @protocol: The protocol family of the socket being created.
+ * @kern: A flag variable to indicate whether or not the socket being
+ *	  created is kernel or userspace based.
+ * @u: A union that is used to hold the family specific address
+ *     characteristics of the socket connection.
+ * @u.ipv4: If the connection is IPV4 based this structure will be
+ *	    populated with the IPV4 address information.
+ * @u.ipv6: If the connection is IPV6 based this structure will be
+ *	    populated with the IPV6 address information.
+ * @u.path: If the socket connection is an AF_UNIX based socket
+ *	    address this buffer will contain the pathname of the
+ *	    socket address.
+ * @u.mapping: If the socket represents an address protocol other
+ *	       than IPV4, IPV6 or UNIX domain this buffer will contain
+ *	       the cryptographic value of the socket address
+ *	       information using the hash function that has been
+ *	       specified for the security modeling namespace.
+ *
+ * This structure is used to encapsulate the arguments provided to the
+ * tsem_socket_create security event handler.
+ */
+struct tsem_socket_connect_args {
+	struct tsem_inode *tsip;
+	struct sockaddr *addr;
+	int addr_len;
+	u16 family;
+	union {
+		struct sockaddr_in ipv4;
+		struct sockaddr_in6 ipv6;
+		char path[UNIX_PATH_MAX + 1];
+		u8 mapping[HASH_MAX_DIGESTSIZE];
+	} u;
+};
+
+/**
+ * struct tsem_socket_accept_args - TSEM socket accept parameters.
+ * @family: The socket family identifier for the connection being
+ *	    accepted.
+ * @type: The type of socket connection being accepted.
+ * @port: The port number of the connection being accepted.
+ * @ipv4: The IPV4 address of the connection being accepted if the
+ *	  socket is representing an IPV4 connection
+ * @ipv6: The IPV6 address of the connection being accepted if the
+ *	  socket is representing an IPV6 connection.
+ * @af_unix: The UNIX domain socket address if the socket is
+ *	     representing a UNIX domain connection.
+ * @path: The pathname of the UNIX domain socket.
+ * @mapping: A cryptographic hash of description of the socket
+ *	     connection being accepted if the socket is representing
+ *	     a connection other than an IPV4, IPV6 or UNIX domain
+ *	     socket.
+ *
+ * This structure is used to encapsulate the arguments provided to the
+ * tsem_socket_accept security event handler.
+ */
+struct tsem_socket_accept_args {
+	u16 family;
+	u16 type;
+	__be16 port;
+	union {
+		__be32 ipv4;
+		struct in6_addr ipv6;
+		struct unix_sock *af_unix;
+		char path[UNIX_PATH_MAX + 1];
+		u8 mapping[HASH_MAX_DIGESTSIZE];
+	} u;
+};
+
+/**
+ * struct tsem_task_kill_args - TSEM task kill arguments.
+ * @cross_model: A flag variable used to indicate whether or not the
+ *		 signal is originating from a security modeling
+ *		 namespace other than the namespace of the target process.
+ * @signal: The number of the signal being sent.
+ * @source: The task identifier of the process sending the signal
+ * @target: The task identifier of the target process.
+ *
+ * This structure is used to encapsulate the arguments provided to the
+ * tsem_task_kill security event handler.
+ */
+struct tsem_task_kill_args {
+	u32 cross_model;
+	u32 signal;
+	u8 source[HASH_MAX_DIGESTSIZE];
+	u8 target[HASH_MAX_DIGESTSIZE];
+};
+
+/**
+ * struct tsem_event - TSEM security event description.
+ * @index: The index number of the slot in the structure magazine that
+ *	   is being refilled.
+ * @u: A union that holds pointers to the structure whose magazine is
+ *     being refilled.
+ * @work: The work structure that manages the workqueue being used to
+ *	  refill the magazine entry.
+ * @event: The enumeration type describing the security event that the
+ *	   structure is defining.
+ * @locked: A boolean flag used to indicate whether or not the
+ *	    security event is running in atomic context.
+ * @pid: The process id number, in the global pid namespace, of the
+ *	 task that is requesting approval for a security event.
+ * @pathname: If the event is referencing a file this pointer will
+ *	      point to a null-terminated buffer containing the
+ *	      pathname to the file in the mount namespace that the
+ *	      process is running in.
+ * @comm: A pointer to a null terminated buffer containing the name of
+ *	  the process that is requesting the security event.
+ * @digestsize: The size in bytes of the cryptographic hash function
+ *		that is being used in the namespace in which the event
+ *		is being recorded.
+ * @task_id: The TSEM task identifier of the process that generated the
+ *	     security event described by an instance of this
+ *	     structure.
+ * @mapping: The security state coefficient that the event described
+ *	     by this structure generates.
+ * @COE: The struct tsem_COE structure that describes the Context Of
+ *	 Execution that generated the event described by this
+ *	 structure.
+ * @file: If the security event references a file this structure will
+ *	  contain the struct tsem_file structure that describes the
+ *	  characteristics of the file.
+ * @CELL: The CELL union is used to hold the data structures that
+ *	  characterize the CELL identity of the event.
+ * @CELL.event_type: In the case of a generically modeled event this
+ *		     member will contain the enumeration value
+ *		     identifying the event.
+ * @CELL.mmap_file: The structure describing the characteristics of
+ *		    a mmap_file security event.
+ * @CELL.socket_create: The structure describing the characteristics
+ *			of a socket_create security event.
+ * @CELL.socket_connect: The structure describing the characteristics
+ *			 of a socket_connect security event.
+ * @CELL.socket_accept: The structure describing the characteristics
+ *			of a socket accept security event.
+ * @CELL.task_kill: The structure describing the characteristics of a
+ *		    task_kill security event.
+ *
+ * This structure is the primary data structure for describing
+ * security events that are registered in a security modeling
+ * namespace.  Each unique security coefficient in the namespace will
+ * have one of these structures attached to it.
+ *
+ * This structure encapsulates the following three major sources of
+ * information about the event:
+ *
+ * * A description of the process initiating the event.
+ * * The characteristics that form the COE identity of the event.
+ * * The characteristics that form the CELL identity of the event.
+ *
+ * Since one event description has to ultimately characterize any
+ * security event that can occur the strategy is to use a union that
+ * contains security event specific structures that describe the
+ * characteristics of the event.
+ *
+ * The kref member of this structure is used to signal when the
+ * structure is to be deleted.  For example, in the case of an
+ * externally modeled event, when the export of the event description
+ * is complete.  In the case of an internally modeled namespace the
+ * structure will be released if it represents a security state
+ * coefficient that is already present in the model.
+ *
+ * The work member of this structure is used to support asynchronous
+ * updates to a TPM for the root modeling domain.  Asynchronous
+ * updates are used to improve the performance of modeling and to
+ * handle security events that are running in atomic context and
+ * cannot be scheduled away while the TPM transaction completes.
+ *
+ * The tsem_event_allocate() function is called by a TSEM security
+ * event handler to allocate and populate this structure.  The struct
+ * tsem_event_parameters structure is used to encapsulate all of the
+ * different structure types that are needed to characterize all of
+ * the different security events that occur.
+ *
+ * The tsem_event_allocate() function is called by either the
+ * tsem_map_event() or tsem_map_event_locked() functions.  After
+ * allocating and populating an event description structure the
+ * mapping functions generate a security state coefficient from the
+ * information in this structure.
+ *
+ * The two separate function call points for mapping are to allow the
+ * security event handlers to indicate the context in which the
+ * security event is occurring, ie. sleeping or atomic context.  After
+ * this point the context of the security event is represented by the
+ * locked member of this structure.
+ *
+ * After the event is mapped this structure is either passed to the
+ * internal trusted modeling agent or the contents of this structure
+ * is exported to the trust orchestrator attached to the namespace for
+ * modeling by an external trust modeling agent.
+ */
+struct tsem_event {
+	struct kref kref;
+	struct list_head list;
+	struct work_struct work;
+
+	enum tsem_event_type event;
+	bool locked;
+	pid_t pid;
+	char *pathname;
+	char comm[TASK_COMM_LEN];
+
+	unsigned int digestsize;
+	u8 task_id[HASH_MAX_DIGESTSIZE];
+	u8 mapping[HASH_MAX_DIGESTSIZE];
+
+	struct tsem_COE COE;
+	struct tsem_file file;
+
+	union {
+		u32 event_type;
+		struct tsem_mmap_file_args mmap_file;
+		struct tsem_socket_create_args socket_create;
+		struct tsem_socket_connect_args socket_connect;
+		struct tsem_socket_accept_args socket_accept;
+		struct tsem_task_kill_args task_kill;
+	} CELL;
+};
+
+/**
+ * struct tsem_event_parameters - Security event argument descriptions
+ * @u: A union that encapsulates all of the different structures that
+ *     are used to characterize the argument so the TSEM security
+ *     event handlers.
+ * @u.event_type: This structure member holds the enum tsem_event_type
+ *		  enumeration value of the event whose characteristics
+ *		  are encapsulated in the function.
+ * @u.file: If the security event references a VFS file this member
+ *	    hold a pointer to the description of the file.
+ _file event.
+ * @u.socket_create: This member will point to a structure that
+ *		     describes the characteristics of a socket_create
+ *		     event.
+ * @u.socket_connect: This member will point to a structure that
+ *		      describes the characteristics of a socket_connect
+ *		      event.
+ * @u.socket_accept: This member will point to a structure that
+ *		     describes the characteristics of a socket_accept
+ *		     event.
+ * @u.task_kill: This member will point to a structure that describes
+ *		     the characteristics of a task_kill function.
+ *
+ * The purpose of this structure is to provide a common encapsulation
+ * method for passing the CELL characteristics of a security event
+ * into the tsem_event_init() function.  The characteristics passed in
+ * this event will be used to create and populate the struct
+ * tsem_event structure that will go on to be used to characterize
+ * the event either an internal or external modeling agent.
+ *
+ * The strategy followed is to allocate one of these structures on the
+ * stack for a security event call along with a call specific
+ * characteristics description structure, both of which will no longer
+ * be needed after completion of the call since the requisite
+ * information has been transferred to a struct tsem_event structure.
+ */
+struct tsem_event_parameters {
+	union {
+		u32 event_type;
+		struct file *file;
+		struct tsem_mmap_file_args *mmap_file;
+		struct tsem_socket_create_args *socket_create;
+		struct tsem_socket_connect_args *socket_connect;
+		struct tsem_socket_accept_args *socket_accept;
+		struct tsem_task_kill_args *task_kill;
+	} u;
+};
+
+/**
+ * struct tsem_event_point - TSEM security coefficient characteristics.
+ * @list: The list structure used to link together all of the security
+ *	  state coefficients for a modeling namespace.
+ * @valid: A boolean value use to indicate whether or not the security
+ *	   state point is a valid coefficient in the model.
+ * @count: The number of times this coefficient has been expressed by
+ *	   security model for the namespace.
+ * @point: The security state coefficient for the point created by
+ *	   the cryptographic hash function being used for the modeling
+ *	   namespace.
+ *
+ * This structure is used by internal trusted modeling agents to
+ * represent each unique state point in a security model.  Security
+ * state coefficients are unique within a model so only one struct
+ * tsem_event_point structure will be generated regardless of how many
+ * times the security event that generates the point occurs.  The
+ * count member of this structure represents the total number of
+ * security events that have occurred that have generated the point.
+ *
+ * The valid member of this structure is used to flag whether this
+ * is consistent with the model for the namespace or was generated by
+ * a 'forensic', ie. out of model, event.
+ *
+ * Within each security namespace these structures are linked together
+ * in a list that describes the functional value of the security model
+ * assigned to the namespace.  Entries are only added to this list and
+ * never removed.
+ *
+ * The desired state of a security model is created by using the TSEM
+ * control plane to inject a list of acceptable security state
+ * coefficients into the model.  Sealing a model causes any security
+ * events that produce a coefficient different from those already in
+ * the model to be rejected as an invalid security event and logged as
+ * a forensic event for the model.
+ */
+struct tsem_event_point {
+	struct list_head list;
+	bool valid;
+	u64 count;
+	u8 point[HASH_MAX_DIGESTSIZE];
+};
+
+/**
+ * struct tsem_inode - TSEM inode status structure.
+ * @mutex: The mutex that will protect the list of struct
+ *	   tsem_inode_digest structures that have been created for the
+ *	   inode containing a struct tsem_inode structure.
+ * @list: The list structure that points to the list of struct
+ *	  tsem_inode_structures.
+ * @status: The digest collection state of the inode.  See the
+ *	    discussion of enum tsem_inode_state for what information
+ *	    is conveyed by the value of this structure member.
+
+ * This structure is the second of the two primary control structures
+ * that are implemented through the LSM blob functionality.  It is
+ * automatically created when the inode structure is created for
+ * system resources that are referenced by a struct inode structure.
+ *
+ * This structure has two primary purposes.  The status member is used
+ * to signal that the tsem_file_open() function should return that
+ * permission to access the file is returned when the security hook is
+ * invoked by the integrity_kernel_read() function.  See the
+ * discussion on enum tsem_inode_state to more details.
+ *
+ * The second purpose of this structure is to maintain a list of
+ * digest values that have been computed by the inode that this
+ * structure references.  Maintenance of multiple digest values is
+ * required since there is no concept of a fixed digest function for
+ * TSEM as each modeling namespace can have its own digest function.
+ *
+ * Each digest value in use has a struct tsem_inode_digest structure
+ * allocated for it.  The digest_list member of this structure points
+ * to a list of these structures.
+ *
+ * The mutex implemented in this structure should be held by any
+ * process that is accessing the list.
+ */
+struct tsem_inode {
+	struct mutex mutex;
+	struct list_head digest_list;
+	enum tsem_inode_state status;
+};
+
+/**
+ * struct tsem_inode_digest - Digest specific file checksum.
+ * @list:	The list structure used to link multiple digest values
+ *		for an inode.
+ * @version:	The version number of the inode that generated the digest
+ *		value that is currently represented.
+ * @name:	A pointer to a null-terminated character buffer containing
+ *		the name of the hash function that generated the current
+ *		digest value.
+ * @value:	The digest value of the file.
+ *
+ * A linked list of these structures is maintained for each inode that
+ * is modeled by TSEM and is used to support multiple hash specific
+ * digest values for a file represented by the inode.  The tsem_inode
+ * structure that represents the TSEM security status of the inode
+ * contains the pointer to this list of structures.
+ *
+ * The version member of the structure contains the inode version number
+ * that was in effect when the last digest value of this type was computed.
+ * This version number value is used to detect changes and to trigger an
+ * update of the digest value.
+ *
+ * The name member of structure contains the name of the hash function
+ * that generated the checksum value.  This name is used to locate the
+ * correct structure by comparing its value against the hash function
+ * that is being used for the modeling domain that is accessing the
+ * inode.
+ */
+struct tsem_inode_digest {
+	struct list_head list;
+	char *name;
+	u64 version;
+	u8 value[HASH_MAX_DIGESTSIZE];
+};
+
+/*
+ * The following three variables are the only globally visible
+ * variables used in the TSEM implementation.
+ *
+ * The tsem_blob_sizes variable is used by the LSM infrastructure to
+ * describe the amount of space that will be needed by the struct
+ * tsem_task and struct tsem_inode structures.
+ *
+ * The tsem_names array is defined in the tsem.c file and contains an
+ * array of pointers to the strings that define the names for each of
+ * the TSEM security event handles.  The enum tsem_event_type
+ * enumeration indexes this array.
+ *
+ * The tsem_root_actions array is also indexed by the enum
+ * tsem_event_type enumeration and is used to determine the type of
+ * response that a TSEM security event handler is to return to the
+ * caller, ie. either logging or enforcing.  The contents of this
+ * array is inherited by copying the array into the struct
+ * tsem_context structure for modeling namespaces that are subordinate
+ * to the root model.
+ */
+extern struct lsm_blob_sizes tsem_blob_sizes;
+extern const char * const tsem_names[TSEM_EVENT_CNT];
+extern enum tsem_action_type tsem_root_actions[TSEM_EVENT_CNT];
+
+/*
+ * The following section of the file contains the definitions for the
+ * externally visible functions in each of the TSEM compilation units.
+ */
+extern struct dentry *tsem_fs_create_external(const char *name);
+extern void tsem_fs_show_trajectory(struct seq_file *c, struct tsem_event *ep);
+extern void tsem_fs_show_field(struct seq_file *c, const char *field);
+extern void tsem_fs_show_key(struct seq_file *c, char *term, char *key,
+			     char *fmt, ...);
+extern int tsem_fs_init(void);
+
+extern struct tsem_model *tsem_model_allocate(size_t size);
+extern void tsem_model_free(struct tsem_context *ctx);
+extern int tsem_model_event(struct tsem_event *ep);
+extern int tsem_model_load_point(u8 *point);
+extern int tsem_model_load_pseudonym(u8 *mapping);
+extern int tsem_model_has_pseudonym(struct tsem_inode *tsip,
+				    struct tsem_file *ep);
+extern void tsem_model_load_base(u8 *mapping);
+extern int tsem_model_add_aggregate(void);
+extern void tsem_model_compute_state(void);
+extern void tsem_model_magazine_free(struct tsem_model *model);
+extern int tsem_model_cache_init(struct tsem_model *model, size_t size);
+
+extern void tsem_ns_put(struct tsem_context *ctx);
+extern int tsem_ns_event_key(u8 *task_key, const char *keystr, u8 *key);
+extern int tsem_ns_create(const enum tsem_control_type type,
+			  const char *digest, const enum tsem_ns_reference ns,
+			  const char *key, const unsigned int cache_size);
+
+extern int tsem_export_show(struct seq_file *m, void *v);
+extern int tsem_export_event(struct tsem_event *ep);
+extern int tsem_export_action(enum tsem_event_type event, bool locked);
+extern int tsem_export_aggregate(void);
+extern int tsem_export_magazine_allocate(struct tsem_external *ext,
+					 size_t size);
+extern void tsem_export_magazine_free(struct tsem_external *ext);
+extern int tsem_export_cache_init(void);
+
+extern int tsem_map_task(struct file *file, u8 *mapping);
+struct tsem_event *tsem_map_event(enum tsem_event_type event,
+				  struct tsem_event_parameters *param);
+struct tsem_event *tsem_map_event_locked(enum tsem_event_type event,
+					 struct tsem_event_parameters *param);
+
+extern struct tsem_event *tsem_event_allocate(bool locked);
+extern struct tsem_event *tsem_event_init(enum tsem_event_type event,
+					  struct tsem_event_parameters *params,
+					  bool locked);
+extern void tsem_event_put(struct tsem_event *ep);
+extern void tsem_event_get(struct tsem_event *ep);
+extern int tsem_event_magazine_allocate(struct tsem_context *ctx, size_t size);
+extern void tsem_event_magazine_free(struct tsem_context *ctx);
+extern int tsem_event_cache_init(void);
+
+extern u8 *tsem_trust_aggregate(void);
+extern int tsem_trust_add_event(struct tsem_event *ep);
+
+/*
+ * The remaining inline function declarations follow the design
+ * pattern of the other LSM's and implement functions that return
+ * various TSEM characteristics of tasks, modeling contexts and
+ * inodes.
+ */
+static inline struct tsem_task *tsem_task(struct task_struct *task)
+{
+	return task->security + tsem_blob_sizes.lbs_task;
+}
+
+static inline bool tsem_task_trusted(struct task_struct *task)
+{
+	return tsem_task(task)->trust_status & TSEM_TASK_TRUSTED;
+}
+
+static inline bool tsem_task_untrusted(struct task_struct *task)
+{
+	return tsem_task(task)->trust_status & ~TSEM_TASK_TRUSTED;
+}
+
+static inline struct tsem_context *tsem_context(struct task_struct *task)
+{
+	return tsem_task(task)->context;
+}
+
+static inline struct tsem_model *tsem_model(struct task_struct *task)
+{
+	return tsem_task(task)->context->model;
+}
+
+static inline struct tsem_inode *tsem_inode(struct inode *inode)
+{
+	return inode->i_security + tsem_blob_sizes.lbs_inode;
+}
+
+static inline struct crypto_shash *tsem_digest(void)
+{
+	return tsem_context(current)->tfm;
+}
+
+static inline unsigned int tsem_digestsize(void)
+{
+	return crypto_shash_digestsize(tsem_digest());
+}
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 05/13] Add primary TSEM implementation file.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (3 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 04/13] Add TSEM master header file Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-08-07 21:00   ` Casey Schaufler
  2023-07-10 10:23 ` [PATCH 06/13] Add root domain trust implementation Dr. Greg
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

The tsem.c file is the 'master' file in the TSEM implementation.
It is responsible for initializing the LSM and providing
implementions of the security event hooks implemented by TSEM.

In addition to initializing the LSM, the set_ready() function
implements a secondary initialization that is used to to indicate
that security event modeling can begin.  This is required
secondary to the fact that the cryptographic API's do not become
ready until after the 'fs' phase of system initialization is
complete.

This file also handles the implementation of kernel command-line
parameters that are used to configure the root security modeling
namespace.

The 'tsem_mode' parameter, if set to a value of 1, causes modeling
to be not conducted for the root security modeling namespace.
One use case is to allow development platform to develop security
models without the overhead of full platform modeling.

The 'tsem_digest' parameter is used to set the cryptographic hash
function that is used to generate security state coefficients in
the root model.  TSEM can use any cryptographic hash function
implemented in the kernel, on a namespace by namespace basis.
Subordinate modeling namespaces can select their hash function
as part of the namespace creation process but the 'tsem_digest'
parameter has to be used to set the function for the root
modeling namespace.

The hash function used in the root modeling namespace but be
compiled into the kernel since the function is used before module
loading becomes available.  The TSEM kernel configuration selects
the SHA256 function to be included as the default cryptographic
modeling function.

The 'tsem_cache' variable sets the size of the pre-allocated
structures that are used for security event modeling in the root
modeling namespace.  This cache is used to support the modeling
and export of events that run in atomic context.  The cache size
can be set independently for each subordinate security modeling
on a namespace by namespace basis.

This file also contains the implementation of the tsem_names
array that contains the ASCII text names that are assigned to
each security event handler.  This name is used as one of the
characteristics in the security state points that are generated.
This array is also used to provide symbolic names for the export
of security event descriptions, either through the TSEM control
plane or for export to external trust orchestrators.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/tsem.c | 1987 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1987 insertions(+)
 create mode 100644 security/tsem/tsem.c

diff --git a/security/tsem/tsem.c b/security/tsem/tsem.c
new file mode 100644
index 000000000000..8ec630354240
--- /dev/null
+++ b/security/tsem/tsem.c
@@ -0,0 +1,1987 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * TSEM initialization infrastructure.
+ */
+#define TRAPPED_MSG_LENGTH 128
+
+#define LOCKED true
+#define NOLOCK false
+
+#include <linux/magic.h>
+#include <linux/mman.h>
+#include <linux/binfmts.h>
+#include <linux/bpf.h>
+#include <linux/ipv6.h>
+
+#include "tsem.h"
+
+struct lsm_blob_sizes tsem_blob_sizes __ro_after_init = {
+	.lbs_task = sizeof(struct tsem_task),
+	.lbs_inode = sizeof(struct tsem_inode)
+};
+
+enum tsem_action_type tsem_root_actions[TSEM_EVENT_CNT] = {
+	TSEM_ACTION_EPERM	/* Undefined. */
+};
+
+static struct tsem_model root_model = {
+	.point_lock = __SPIN_LOCK_INITIALIZER(root_model.point_lock),
+	.point_list = LIST_HEAD_INIT(root_model.point_list),
+	.point_end_mutex = __MUTEX_INITIALIZER(root_model.point_end_mutex),
+
+	.trajectory_lock = __SPIN_LOCK_INITIALIZER(root_model.trajectory_lock),
+	.trajectory_list = LIST_HEAD_INIT(root_model.trajectory_list),
+	.trajectory_end_mutex = __MUTEX_INITIALIZER(root_model.trajectory_end_mutex),
+
+	.forensics_lock = __SPIN_LOCK_INITIALIZER(root_model.forensics_lock),
+	.forensics_list = LIST_HEAD_INIT(root_model.forensics_list),
+	.forensics_end_mutex = __MUTEX_INITIALIZER(root_model.forensics_end_mutex),
+
+	.pseudonym_mutex = __MUTEX_INITIALIZER(root_model.pseudonym_mutex),
+	.pseudonym_list = LIST_HEAD_INIT(root_model.pseudonym_list)
+};
+
+static struct tsem_context root_context;
+
+static int tsem_ready __ro_after_init;
+
+static bool tsem_available __ro_after_init;
+
+static unsigned int magazine_size __ro_after_init = TSEM_ROOT_MAGAZINE_SIZE;
+
+static bool no_root_modeling __ro_after_init;
+
+static char *default_hash_function __ro_after_init;
+
+static int __init set_magazine_size(char *magazine_value)
+{
+	if (kstrtouint(magazine_value, 0, &magazine_size))
+		pr_warn("tsem: Failed to parse root cache size.\n");
+
+	if (!magazine_size) {
+		pr_warn("tsem: Forcing non-zero cache size.\n");
+		magazine_size = TSEM_ROOT_MAGAZINE_SIZE;
+	}
+
+	pr_info("tsem: Setting default root cache size to %u.\n",
+		magazine_size);
+	return 1;
+}
+__setup("tsem_cache=", set_magazine_size);
+
+static int __init set_modeling_mode(char *mode_value)
+{
+	unsigned long mode = 0;
+
+	if (kstrtoul(mode_value, 0, &mode)) {
+		pr_warn("tsem: Failed to parse modeling mode.\n");
+		return 1;
+	}
+
+	if (mode == 1)
+		no_root_modeling = true;
+	else
+		pr_warn("tsem: Unknown mode specified.\n");
+	return 1;
+}
+__setup("tsem_mode=", set_modeling_mode);
+
+static int __init set_default_hash_function(char *hash_function)
+{
+
+	default_hash_function = hash_function;
+	return 1;
+}
+__setup("tsem_digest=", set_default_hash_function);
+
+const char * const tsem_names[TSEM_EVENT_CNT] = {
+	"undefined",
+	"bprm_set_creds",
+	"generic_event",
+	"task_kill",
+	"task_setpgid",
+	"task_getpgid",
+	"task_getsid",
+	"task_setnice",
+	"task_setioprio",
+	"task_getioprio",
+	"task_prlimit",
+	"task_setrlimit",
+	"task_setscheduler",
+	"task_getscheduler",
+	"task_prctl",
+	"file_open",
+	"mmap_file",
+	"file_ioctl",
+	"file_lock",
+	"file_fcntl",
+	"file_receive",
+	"unix_stream_connect",
+	"unix_may_send",
+	"socket_create",
+	"socket_connect",
+	"socket_bind",
+	"socket_accept",
+	"socket_listen",
+	"socket_socketpair",
+	"socket_sendmsg",
+	"socket_recvmsg",
+	"socket_getsockname",
+	"socket_getpeername",
+	"socket_setsockopt",
+	"socket_shutdown",
+	"ptrace_traceme",
+	"kernel_module_request",
+	"kernel_load_data",
+	"kernel_read_file",
+	"sb_mount",
+	"sb_umount",
+	"sb_remount",
+	"sb_pivotroot",
+	"sb_statfs",
+	"move_mount",
+	"shm_associate",
+	"shm_shmctl",
+	"shm_shmat",
+	"sem_associate",
+	"sem_semctl",
+	"sem_semop",
+	"syslog",
+	"settime",
+	"quotactl",
+	"quota_on",
+	"msg_queue_associate",
+	"msg_queue_msgctl",
+	"msg_queue_msgsnd",
+	"msg_queue_msgrcv",
+	"ipc_permission",
+	"key_alloc",
+	"key_permission",
+	"netlink_send",
+	"inode_create",
+	"inode_link",
+	"inode_unlink",
+	"inode_symlink",
+	"inode_mkdir",
+	"inode_rmdir",
+	"inode_mknod",
+	"inode_rename",
+	"inode_setattr",
+	"inode_getattr",
+	"inode_setxattr",
+	"inode_getxattr",
+	"inode_listxattr",
+	"inode_removexattr",
+	"inode_killpriv",
+	"tun_dev_create",
+	"tun_dev_attach_queue",
+	"tun_dev_attach",
+	"tun_dev_open",
+	"bpf",
+	"bpf_map",
+	"bpf_prog"
+};
+
+static const int pseudo_filesystems[] = {
+	PROC_SUPER_MAGIC,
+	SYSFS_MAGIC,
+	DEBUGFS_MAGIC,
+	TMPFS_MAGIC,
+	DEVPTS_SUPER_MAGIC,
+	BINFMTFS_MAGIC,
+	SECURITYFS_MAGIC,
+	SELINUX_MAGIC,
+	SMACK_MAGIC,
+	CGROUP_SUPER_MAGIC,
+	CGROUP2_SUPER_MAGIC,
+	NSFS_MAGIC,
+	EFIVARFS_MAGIC
+};
+
+static bool bypass_inode(struct inode *inode)
+{
+	bool retn = true;
+
+	unsigned int lp;
+
+	if (!S_ISREG(inode->i_mode))
+		goto done;
+
+	for (lp = 0; lp < ARRAY_SIZE(pseudo_filesystems); ++lp)
+		if (inode->i_sb->s_magic == pseudo_filesystems[lp])
+			goto done;
+	retn = false;
+
+ done:
+	return retn;
+}
+
+static int event_action(struct tsem_context *ctx, enum tsem_event_type event)
+{
+	int retn = 0;
+
+	if (tsem_task_trusted(current))
+		return retn;
+
+	if (ctx->actions[event] == TSEM_ACTION_EPERM)
+		retn = -EPERM;
+
+	return retn;
+}
+
+static int return_trapped_task(enum tsem_event_type event, char *msg,
+			       bool locked)
+{
+	int retn;
+	struct tsem_context *ctx = tsem_context(current);
+
+	pr_warn("Untrusted %s: comm=%s, pid=%d, parameters='%s'\n",
+		tsem_names[event], current->comm, task_pid_nr(current), msg);
+
+	if (ctx->external) {
+		retn = tsem_export_action(event, locked);
+		if (retn)
+			return retn;
+	}
+
+	return event_action(ctx, event);
+}
+
+static int return_trapped_inode(enum tsem_event_type event,
+				struct inode *inode, char *inode_msg,
+				bool locked)
+{
+	const char *dname;
+	char msg[TRAPPED_MSG_LENGTH];
+	struct dentry *dird;
+
+	dird = d_find_alias(inode);
+	if (dird == NULL)
+		dname = "not available";
+	else
+		dname = dird->d_name.name;
+	scnprintf(msg, sizeof(msg), "parent=%s, %s", dname, inode_msg);
+
+	return return_trapped_task(event, msg, locked);
+}
+
+static int model_event(struct tsem_event *ep)
+{
+	int retn;
+	struct tsem_context *ctx = tsem_context(current);
+
+	if (!ctx->id && no_root_modeling)
+		return 0;
+
+	if (!ctx->external)
+		retn = tsem_model_event(ep);
+	else
+		retn = tsem_export_event(ep);
+
+	if (!retn)
+		retn = event_action(ctx, ep->event);
+	return retn;
+}
+
+static int model_generic_event(enum tsem_event_type event, bool locked)
+{
+	int retn;
+	struct tsem_event *ep;
+	struct tsem_event_parameters params;
+
+	if (!tsem_context(current)->id && no_root_modeling)
+		return 0;
+
+	params.u.event_type = event;
+
+	if (locked)
+		ep = tsem_map_event_locked(TSEM_GENERIC_EVENT, &params);
+	else
+		ep = tsem_map_event(TSEM_GENERIC_EVENT, &params);
+	if (IS_ERR(ep))
+		return PTR_ERR(ep);
+
+	retn = model_event(ep);
+
+	tsem_event_put(ep);
+	return retn;
+}
+
+static int tsem_file_open(struct file *file)
+{
+	int retn = 0;
+	char msg[TRAPPED_MSG_LENGTH];
+	struct inode *inode = file_inode(file);
+	struct tsem_event *ep = NULL;
+	struct tsem_event_parameters params;
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "filename=%s, flags=0x%x",
+			 file->f_path.dentry->d_name.name, file->f_flags);
+		return return_trapped_task(TSEM_FILE_OPEN, msg, NOLOCK);
+	}
+
+	if (bypass_inode(inode))
+		goto done;
+	if (tsem_inode(inode)->status == TSEM_INODE_COLLECTING)
+		goto done;
+
+	params.u.file = file;
+	ep = tsem_map_event(TSEM_FILE_OPEN, &params);
+	if (IS_ERR(ep)) {
+		retn = PTR_ERR(ep);
+		goto done;
+	}
+
+	retn = model_event(ep);
+	tsem_event_put(ep);
+
+ done:
+	return retn;
+}
+
+static int tsem_mmap_file(struct file *file, unsigned long reqprot,
+			  unsigned long prot, unsigned long flags)
+{
+	int retn = 0;
+	const char *p;
+	char msg[TRAPPED_MSG_LENGTH];
+	struct inode *inode = NULL;
+	struct tsem_event *ep = NULL;
+	struct tsem_event_parameters params;
+	struct tsem_mmap_file_args args;
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		p = "anonymous mapping";
+		if (file)
+			p = file->f_path.dentry->d_name.name;
+		scnprintf(msg, sizeof(msg),
+			  "filename=%s, rprot=0x%lx, prot=0x%lx, flags=0x%lx",
+			  p, reqprot, prot, flags);
+		return return_trapped_task(TSEM_MMAP_FILE, msg, NOLOCK);
+	}
+
+	if (!file && !(prot & PROT_EXEC))
+		goto done;
+	if (file) {
+		inode = file_inode(file);
+		if (bypass_inode(inode))
+			goto done;
+	}
+
+	args.file = file;
+	args.anonymous = file == NULL ? 1 : 0;
+	args.reqprot = reqprot;
+	args.prot = prot;
+	args.flags = flags;
+	params.u.mmap_file = &args;
+	ep = tsem_map_event(TSEM_MMAP_FILE, &params);
+	if (IS_ERR(ep)) {
+		retn = PTR_ERR(ep);
+		goto done;
+	}
+
+	retn = model_event(ep);
+	tsem_event_put(ep);
+
+ done:
+	return retn;
+}
+
+static int tsem_file_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s, cmd=%u",
+			  file->f_path.dentry->d_name.name, cmd);
+		return return_trapped_task(TSEM_FILE_IOCTL, msg, NOLOCK);
+	}
+
+	if (bypass_inode(file_inode(file)))
+		return 0;
+
+	return model_generic_event(TSEM_FILE_IOCTL, NOLOCK);
+}
+
+static int tsem_file_lock(struct file *file, unsigned int cmd)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s, cmd=%u",
+			  file->f_path.dentry->d_name.name, cmd);
+		return return_trapped_task(TSEM_FILE_LOCK, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_FILE_LOCK, NOLOCK);
+}
+
+static int tsem_file_fcntl(struct file *file, unsigned int cmd,
+			   unsigned long arg)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s, cmd=%u",
+			  file->f_path.dentry->d_name.name, cmd);
+		return return_trapped_task(TSEM_FILE_FCNTL, msg, NOLOCK);
+	}
+
+	if (bypass_inode(file_inode(file)))
+		return 0;
+
+	return model_generic_event(TSEM_FILE_FCNTL, NOLOCK);
+}
+
+static int tsem_file_receive(struct file *file)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s, flags=%u",
+			  file->f_path.dentry->d_name.name, file->f_flags);
+		return return_trapped_task(TSEM_FILE_RECEIVE, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_FILE_RECEIVE, NOLOCK);
+}
+
+static int tsem_task_alloc(struct task_struct *new, unsigned long flags)
+{
+	struct tsem_task *old_task = tsem_task(current);
+	struct tsem_task *new_task = tsem_task(new);
+
+	new_task->trust_status = old_task->trust_status;
+	new_task->context = old_task->context;
+	memcpy(new_task->task_id, old_task->task_id, HASH_MAX_DIGESTSIZE);
+
+	if (!new_task->context->id)
+		return 0;
+
+	kref_get(&new_task->context->kref);
+	memcpy(new_task->task_key, old_task->task_key, HASH_MAX_DIGESTSIZE);
+	return 0;
+}
+
+static void tsem_task_free(struct task_struct *task)
+{
+	struct tsem_context *ctx = tsem_context(task);
+
+	if (!ctx->id)
+		return;
+	tsem_ns_put(ctx);
+}
+
+static int tsem_task_kill(struct task_struct *target,
+			  struct kernel_siginfo *info, int sig,
+			  const struct cred *cred)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	int retn = 0;
+	struct tsem_event *ep;
+	struct tsem_event_parameters params;
+	struct tsem_task_kill_args args;
+	struct tsem_context *src_ctx = tsem_context(current);
+	struct tsem_context *tgt_ctx = tsem_context(target);
+
+	if (tsem_task_untrusted(current)) {
+		snprintf(msg, sizeof(msg),
+			 "target=%s, pid=%d, signal=%d", target->comm,
+			 task_pid_nr(target), sig);
+		return return_trapped_task(TSEM_TASK_KILL, msg, true);
+	}
+
+	args.cross_model = src_ctx->id != tgt_ctx->id;
+
+	if (SI_FROMKERNEL(info))
+		return retn;
+	if (sig == SIGURG)
+		return retn;
+	if (!capable(TSEM_CONTROL_CAPABILITY) &&
+	    has_capability_noaudit(target, TSEM_CONTROL_CAPABILITY))
+		return -EPERM;
+	if (!capable(TSEM_CONTROL_CAPABILITY) && args.cross_model)
+		return -EPERM;
+
+	args.signal = sig;
+	memcpy(args.target, tsem_task(target)->task_id, tsem_digestsize());
+	params.u.task_kill = &args;
+
+	ep = tsem_map_event_locked(TSEM_TASK_KILL, &params);
+	if (IS_ERR(ep)) {
+		retn = PTR_ERR(ep);
+		goto done;
+	}
+
+	retn = model_event(ep);
+	tsem_event_put(ep);
+
+ done:
+	return retn;
+}
+
+static int tsem_ptrace_traceme(struct task_struct *parent)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "parent=%s", parent->comm);
+		return return_trapped_task(TSEM_PTRACE_TRACEME, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_PTRACE_TRACEME, LOCKED);
+}
+
+static int tsem_task_setpgid(struct task_struct *p, pid_t pgid)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct tsem_context *ctx = tsem_context(current);
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s", p->comm);
+		pr_warn("Untrusted %s: comm=%s, pid=%d, parameters='%s'\n",
+			tsem_names[TSEM_TASK_SETPGID], current->comm,
+			task_pid_nr(current), msg);
+		return event_action(ctx, TSEM_TASK_SETPGID);
+	}
+
+	return model_generic_event(TSEM_TASK_SETPGID, true);
+}
+
+static int tsem_task_getpgid(struct task_struct *p)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s", p->comm);
+		return return_trapped_task(TSEM_TASK_GETPGID, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_TASK_GETPGID, LOCKED);
+}
+
+static int tsem_task_getsid(struct task_struct *p)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s", p->comm);
+		return return_trapped_task(TSEM_TASK_GETSID, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_TASK_GETSID, LOCKED);
+}
+
+static int tsem_task_setnice(struct task_struct *p, int nice)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s, nice=%d",
+			  p->comm, nice);
+		return return_trapped_task(TSEM_TASK_SETNICE, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_TASK_SETNICE, LOCKED);
+}
+
+static int tsem_task_setioprio(struct task_struct *p, int ioprio)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s, ioprio=%d",
+			  p->comm, ioprio);
+		return return_trapped_task(TSEM_TASK_SETIOPRIO, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_TASK_SETIOPRIO, NOLOCK);
+}
+
+static int tsem_task_getioprio(struct task_struct *p)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s", p->comm);
+		return return_trapped_task(TSEM_TASK_GETIOPRIO, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_TASK_GETIOPRIO, NOLOCK);
+}
+
+static int tsem_task_prlimit(const struct cred *cred, const struct cred *tcred,
+			     unsigned int flags)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "uid=%d, gid=%d, euid=%d, egid=%d, flags=%u",
+			  from_kuid(&init_user_ns, tcred->uid),
+			  from_kgid(&init_user_ns, tcred->gid),
+			  from_kuid(&init_user_ns, tcred->euid),
+			  from_kgid(&init_user_ns, tcred->egid), flags);
+		return return_trapped_task(TSEM_TASK_PRLIMIT, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_TASK_PRLIMIT, LOCKED);
+}
+
+static int tsem_task_setrlimit(struct task_struct *p, unsigned int resource,
+			       struct rlimit *new_rlim)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "target=%s, res=%u, cur=%lu, max=%lu",
+			  p->comm, resource, new_rlim->rlim_cur,
+			  new_rlim->rlim_max);
+		return return_trapped_task(TSEM_TASK_SETRLIMIT, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_TASK_SETRLIMIT, LOCKED);
+}
+
+static int tsem_task_setscheduler(struct task_struct *p)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s", p->comm);
+		return return_trapped_task(TSEM_TASK_SETSCHEDULER, msg,
+					   LOCKED);
+	}
+
+	return model_generic_event(TSEM_TASK_SETSCHEDULER, LOCKED);
+}
+
+static int tsem_task_getscheduler(struct task_struct *p)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s", p->comm);
+		return return_trapped_task(TSEM_TASK_GETSCHEDULER, msg,
+					   LOCKED);
+	}
+
+	return model_generic_event(TSEM_TASK_GETSCHEDULER, LOCKED);
+}
+
+static int tsem_task_prctl(int option, unsigned long arg2, unsigned long arg3,
+			   unsigned long arg4, unsigned long arg5)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "option=%d", option);
+		return return_trapped_task(TSEM_TASK_PRCTL, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_TASK_PRCTL, LOCKED);
+}
+
+static int tsem_bprm_creds_for_exec(struct linux_binprm *bprm)
+{
+	struct tsem_task *task = tsem_task(current);
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	return tsem_map_task(bprm->file, task->task_id);
+}
+
+static int tsem_inode_alloc_security(struct inode *inode)
+{
+	struct tsem_inode *tsip = tsem_inode(inode);
+
+	mutex_init(&tsip->mutex);
+	INIT_LIST_HEAD(&tsip->digest_list);
+
+	return 0;
+}
+
+static void tsem_inode_free_security(struct inode *inode)
+{
+	struct tsem_inode_digest *digest, *tmp_digest;
+
+	if (bypass_inode(inode))
+		return;
+
+	list_for_each_entry_safe(digest, tmp_digest,
+				 &tsem_inode(inode)->digest_list, list) {
+		list_del(&digest->list);
+		kfree(digest->name);
+		kfree(digest);
+	}
+}
+
+static int tsem_unix_stream_connect(struct sock *sock, struct sock *other,
+				    struct sock *newsk)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u/%u, ",
+			  sock->sk_family, other->sk_family);
+		return return_trapped_task(TSEM_UNIX_STREAM_CONNECT, msg,
+					   LOCKED);
+	}
+
+	return model_generic_event(TSEM_UNIX_STREAM_CONNECT, LOCKED);
+}
+
+static int tsem_unix_may_send(struct socket *sock, struct socket *other)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *sk = sock->sk;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u, type=%u",
+			  sk->sk_family, sock->type);
+		return return_trapped_task(TSEM_UNIX_MAY_SEND, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_UNIX_MAY_SEND, LOCKED);
+}
+
+static int tsem_socket_create(int family, int type, int protocol, int kern)
+{
+	int retn;
+	char msg[TRAPPED_MSG_LENGTH];
+	struct tsem_event *ep;
+	struct tsem_event_parameters params;
+	struct tsem_socket_create_args args;
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "family=%d, type=%d, protocol=%d, kern=%d", family,
+			  type, protocol, kern);
+		return return_trapped_task(TSEM_SOCKET_CREATE, msg, NOLOCK);
+	}
+
+	args.family = family;
+	args.type = type;
+	args.protocol = protocol;
+	args.kern = kern;
+	params.u.socket_create = &args;
+
+	ep = tsem_map_event(TSEM_SOCKET_CREATE, &params);
+	if (IS_ERR(ep)) {
+		retn = PTR_ERR(ep);
+		goto done;
+	}
+
+	retn = model_event(ep);
+	tsem_event_put(ep);
+
+ done:
+	return retn;
+}
+
+static int tsem_socket_connect(struct socket *sock, struct sockaddr *addr,
+			     int addr_len)
+
+{
+	int retn;
+	char msg[TRAPPED_MSG_LENGTH];
+	struct tsem_event *ep;
+	struct tsem_event_parameters params;
+	struct tsem_socket_connect_args args;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u", addr->sa_family);
+		return return_trapped_task(TSEM_SOCKET_CONNECT, msg, NOLOCK);
+	}
+
+	args.tsip = tsem_inode(SOCK_INODE(sock));
+	args.addr = addr;
+	args.addr_len = addr_len;
+	params.u.socket_connect = &args;
+
+	ep = tsem_map_event(TSEM_SOCKET_CONNECT, &params);
+	if (IS_ERR(ep)) {
+		retn = PTR_ERR(ep);
+		goto done;
+	}
+
+	retn = model_event(ep);
+	tsem_event_put(ep);
+
+ done:
+	return retn;
+
+}
+
+static int tsem_socket_bind(struct socket *sock, struct sockaddr *addr,
+			    int addr_len)
+
+{
+	int retn;
+	char msg[TRAPPED_MSG_LENGTH];
+	struct tsem_event *ep;
+	struct tsem_event_parameters params;
+	struct tsem_socket_connect_args args;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u", addr->sa_family);
+		return return_trapped_task(TSEM_SOCKET_BIND, msg, NOLOCK);
+	}
+
+	args.tsip = tsem_inode(SOCK_INODE(sock));
+	args.addr = addr;
+	args.addr_len = addr_len;
+	params.u.socket_connect = &args;
+
+	ep = tsem_map_event(TSEM_SOCKET_BIND, &params);
+	if (IS_ERR(ep)) {
+		retn = PTR_ERR(ep);
+		goto done;
+	}
+
+	retn = model_event(ep);
+	tsem_event_put(ep);
+
+ done:
+	return retn;
+
+}
+
+static int tsem_socket_accept(struct socket *sock, struct socket *newsock)
+{
+	int retn;
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *sk = sock->sk;
+	const struct in6_addr *ipv6;
+	struct tsem_event *ep;
+	struct tsem_event_parameters params;
+	struct tsem_socket_accept_args args;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u", sk->sk_family);
+		return return_trapped_task(TSEM_SOCKET_ACCEPT, msg, NOLOCK);
+	}
+
+	args.family = sk->sk_family;
+	args.type = sock->type;
+	args.port = sk->sk_num;
+	args.u.ipv4 = sk->sk_rcv_saddr;
+	if (args.family == AF_UNIX)
+		args.u.af_unix = unix_sk(sk);
+	ipv6 = inet6_rcv_saddr(sk);
+	if (ipv6)
+		args.u.ipv6 = *ipv6;
+
+	params.u.socket_accept = &args;
+
+	ep = tsem_map_event(TSEM_SOCKET_ACCEPT, &params);
+	if (IS_ERR(ep)) {
+		retn = PTR_ERR(ep);
+		goto done;
+	}
+
+	retn = model_event(ep);
+	tsem_event_put(ep);
+
+ done:
+	return retn;
+}
+
+static int tsem_socket_listen(struct socket *sock, int backlog)
+
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *sk = sock->sk;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u, type=%u, port=%u",
+			  sk->sk_family, sock->type, sk->sk_num);
+		return return_trapped_task(TSEM_SOCKET_LISTEN, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SOCKET_LISTEN, NOLOCK);
+}
+
+static int tsem_socket_socketpair(struct socket *socka, struct socket *sockb)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *ska = socka->sk, *skb = sockb->sk;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family a=%u, family b=%u",
+			  ska->sk_family, skb->sk_family);
+		return return_trapped_task(TSEM_SOCKET_SOCKETPAIR, msg,
+					   NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SOCKET_SOCKETPAIR, NOLOCK);
+}
+
+static int tsem_socket_sendmsg(struct socket *sock, struct msghdr *msgmsg,
+			       int size)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *sk = sock->sk;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u, size=%d",
+			  sk->sk_family, size);
+		return return_trapped_task(TSEM_SOCKET_SENDMSG, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SOCKET_SENDMSG, NOLOCK);
+}
+
+static int tsem_socket_recvmsg(struct socket *sock, struct msghdr *msgmsg,
+			       int size, int flags)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *sk = sock->sk;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u, size=%d, flags=%d",
+			  sk->sk_family, size, flags);
+		return return_trapped_task(TSEM_SOCKET_RECVMSG, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SOCKET_RECVMSG, NOLOCK);
+}
+
+static int tsem_socket_getsockname(struct socket *sock)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *sk = sock->sk;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u", sk->sk_family);
+		return return_trapped_task(TSEM_SOCKET_GETSOCKNAME, msg,
+					   NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SOCKET_GETSOCKNAME, NOLOCK);
+}
+
+static int tsem_socket_getpeername(struct socket *sock)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *sk = sock->sk;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u", sk->sk_family);
+		return return_trapped_task(TSEM_SOCKET_GETPEERNAME, msg,
+					   NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SOCKET_GETPEERNAME, NOLOCK);
+}
+
+static int tsem_socket_setsockopt(struct socket *sock, int level, int optname)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *sk = sock->sk;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u, level=%d, optname=%d",
+			  sk->sk_family, level, optname);
+		return return_trapped_task(TSEM_SOCKET_SETSOCKOPT, msg,
+					   NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SOCKET_SETSOCKOPT, NOLOCK);
+}
+
+static int tsem_socket_shutdown(struct socket *sock, int how)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct sock *sk = sock->sk;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u, how=%d",
+			  sk->sk_family, how);
+		return return_trapped_task(TSEM_SOCKET_SHUTDOWN, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SOCKET_SHUTDOWN, NOLOCK);
+}
+
+static int tsem_kernel_module_request(char *kmod_name)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "module=%s", kmod_name);
+		return return_trapped_task(TSEM_KERNEL_MODULE_REQUEST, msg,
+					   NOLOCK);
+	}
+
+	return model_generic_event(TSEM_KERNEL_MODULE_REQUEST, NOLOCK);
+}
+
+static int tsem_kernel_load_data(enum kernel_load_data_id id, bool contents)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "id=%d, contents=%d", id,
+			  contents);
+		return return_trapped_task(TSEM_KERNEL_LOAD_DATA, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_KERNEL_LOAD_DATA, NOLOCK);
+}
+
+static int tsem_kernel_read_file(struct file *file,
+				 enum kernel_read_file_id id, bool contents)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "filename=%s, flags=0x%x, id=%d, contents=%d",
+			  file->f_path.dentry->d_name.name, file->f_flags,
+			  id, contents);
+		return return_trapped_task(TSEM_KERNEL_READ_FILE, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_KERNEL_READ_FILE, NOLOCK);
+}
+
+static int tsem_sb_mount(const char *dev_name, const struct path *path,
+			 const char *type, unsigned long flags, void *data)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "device=%s, type=%s, flags=%lu",
+			  dev_name, type, flags);
+		return return_trapped_task(TSEM_SB_MOUNT, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SB_MOUNT, NOLOCK);
+}
+
+static	int tsem_sb_umount(struct vfsmount *mnt, int flags)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "root=%s, flags=%d",
+			  mnt->mnt_root->d_name.name, flags);
+		return return_trapped_task(TSEM_SB_UMOUNT, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SB_UMOUNT, NOLOCK);
+}
+
+static int tsem_sb_remount(struct super_block *sb, void *mnt_opts)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "fstype=%s, type=%s",
+			  sb->s_type->name, sb->s_root->d_name.name);
+		return return_trapped_task(TSEM_SB_REMOUNT, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SB_REMOUNT, NOLOCK);
+}
+
+static int tsem_sb_pivotroot(const struct path *old_path,
+			     const struct path *new_path)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "%s -> %s",
+			  old_path->dentry->d_name.name,
+			  new_path->dentry->d_name.name);
+		return return_trapped_task(TSEM_SB_PIVOTROOT, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SB_PIVOTROOT, NOLOCK);
+}
+
+static int tsem_sb_statfs(struct dentry *dentry)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s", dentry->d_name.name);
+		return return_trapped_task(TSEM_SB_STATFS, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SB_STATFS, NOLOCK);
+}
+
+static int tsem_move_mount(const struct path *from_path,
+			   const struct path *to_path)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "%s -> %s",
+			  from_path->dentry->d_name.name,
+			  to_path->dentry->d_name.name);
+		return return_trapped_task(TSEM_MOVE_MOUNT, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_MOVE_MOUNT, NOLOCK);
+}
+
+static int tsem_shm_associate(struct kern_ipc_perm *perm, int shmflg)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "id=%d, mode=%u, flags=%d",
+			  perm->id, perm->mode, shmflg);
+		return return_trapped_task(TSEM_SHM_ASSOCIATE, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_SHM_ASSOCIATE, LOCKED);
+}
+
+static int tsem_shm_shmctl(struct kern_ipc_perm *perm, int cmd)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "id=%d, mode=%u, cmd=%d",
+			  perm->id, perm->mode, cmd);
+		return return_trapped_task(TSEM_SHM_SHMCTL, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_SHM_SHMCTL, LOCKED);
+}
+
+static int tsem_shm_shmat(struct kern_ipc_perm *perm, char __user *shmaddr,
+			  int shmflg)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "id=%d, mode=%u, flag=%d",
+			  perm->id, perm->mode, shmflg);
+		return return_trapped_task(TSEM_SHM_SHMAT, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_SHM_SHMAT, LOCKED);
+}
+
+static int tsem_sem_associate(struct kern_ipc_perm *perm, int semflg)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "id=%d, mode=%u, flag=%d",
+			  perm->id, perm->mode, semflg);
+		return return_trapped_task(TSEM_SEM_ASSOCIATE, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_SEM_ASSOCIATE, LOCKED);
+}
+
+static int tsem_sem_semctl(struct kern_ipc_perm *perm, int cmd)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "id=%d, mode=%u, cmd=%d",
+			  perm->id, perm->mode, cmd);
+		return return_trapped_task(TSEM_SEM_SEMCTL, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_SEM_SEMCTL, LOCKED);
+}
+
+static int tsem_sem_semop(struct kern_ipc_perm *perm, struct sembuf *sops,
+			  unsigned int nsops, int alter)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "id=%d, mode=%u, nsops=%u, alter=%d", perm->id,
+			  perm->mode, nsops, alter);
+		return return_trapped_task(TSEM_SEM_SEMOP, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_SEM_SEMOP, LOCKED);
+}
+
+static int tsem_syslog(int type)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "type=%d", type);
+		return return_trapped_task(TSEM_SYSLOG, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SYSLOG, NOLOCK);
+}
+
+static int tsem_settime(const struct timespec64 *ts, const struct timezone *tz)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "secs=%lld, nsecs=%ld, mwest=%d, dsttime=%d",
+			  ts->tv_sec, ts->tv_nsec, tz->tz_minuteswest,
+			  tz->tz_dsttime);
+		return return_trapped_task(TSEM_SETTIME, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_SETTIME, NOLOCK);
+}
+
+static int tsem_quotactl(int cmds, int type, int id, struct super_block *sb)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "cmds=%d, type=%d, id=%d, fstype=%s, type=%s", cmds,
+			  type, id, sb->s_type->name, sb->s_root->d_name.name);
+		return return_trapped_task(TSEM_QUOTACTL, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_QUOTACTL, NOLOCK);
+}
+
+static int tsem_quota_on(struct dentry *dentry)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s", dentry->d_name.name);
+		return return_trapped_task(TSEM_QUOTA_ON, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_QUOTA_ON, NOLOCK);
+}
+
+static int tsem_msg_queue_associate(struct kern_ipc_perm *perm, int msqflg)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "id=%d, mode=%u, msqflg=%d", perm->id, perm->mode,
+			  msqflg);
+		return return_trapped_task(TSEM_MSG_QUEUE_ASSOCIATE, msg,
+					   LOCKED);
+	}
+
+	return model_generic_event(TSEM_MSG_QUEUE_ASSOCIATE, LOCKED);
+}
+
+static int tsem_msg_queue_msgsnd(struct kern_ipc_perm *perm,
+				 struct msg_msg *msgmsg, int msqflg)
+
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "id=%d, mode=%u, msqflg=%d", perm->id, perm->mode,
+			  msqflg);
+		return return_trapped_task(TSEM_MSG_QUEUE_MSGSND, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_MSG_QUEUE_MSGSND, LOCKED);
+}
+
+static int tsem_msg_queue_msgctl(struct kern_ipc_perm *perm, int cmd)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "id=%d, mode=%u, cmd=%d", perm->id, perm->mode,
+			  cmd);
+		return return_trapped_task(TSEM_MSG_QUEUE_MSGCTL, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_MSG_QUEUE_MSGCTL, LOCKED);
+}
+
+static int tsem_msg_queue_msgrcv(struct kern_ipc_perm *perm,
+				 struct msg_msg *msgmsg,
+				 struct task_struct *target, long type,
+				 int mode)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "id=%d, mode=%u, target=%s, type=%ld, mode=%d",
+			  perm->id, perm->mode, target->comm, type, mode);
+		return return_trapped_task(TSEM_MSG_QUEUE_MSGRCV, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_MSG_QUEUE_MSGRCV, LOCKED);
+}
+
+static int tsem_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "uid=%d, gid=%d, mode=%u, flag=%u",
+			  from_kuid(&init_user_ns, ipcp->uid),
+			  from_kgid(&init_user_ns, ipcp->gid), ipcp->mode,
+			  flag);
+		return return_trapped_task(TSEM_IPC_PERMISSION, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_IPC_PERMISSION, LOCKED);
+}
+
+#ifdef CONFIG_KEYS
+static int tsem_key_alloc(struct key *key, const struct cred *cred,
+			  unsigned long flags)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "uid=%d, gid=%d, euid=%d, egid=%d, flags=%lu",
+			  from_kuid(&init_user_ns, cred->uid),
+			  from_kgid(&init_user_ns, cred->gid),
+			  from_kuid(&init_user_ns, cred->euid),
+			  from_kgid(&init_user_ns, cred->egid), flags);
+		return return_trapped_task(TSEM_KEY_ALLOC, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_KEY_ALLOC, NOLOCK);
+}
+
+static int tsem_key_permission(key_ref_t key_ref, const struct cred *cred,
+			       unsigned int perm)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "uid=%d, gid=%d, euid=%d, egid=%d, perm=%u",
+			  from_kuid(&init_user_ns, cred->uid),
+			  from_kgid(&init_user_ns, cred->gid),
+			  from_kuid(&init_user_ns, cred->euid),
+			  from_kgid(&init_user_ns, cred->egid), perm);
+		return return_trapped_task(TSEM_KEY_PERMISSION, msg, LOCKED);
+	}
+
+	return model_generic_event(TSEM_KEY_PERMISSION, LOCKED);
+}
+#endif
+
+static int tsem_netlink_send(struct sock *sk, struct sk_buff *skb)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+	struct scm_creds *cred;
+
+	if (tsem_task_untrusted(current)) {
+		cred = NETLINK_CREDS(skb);
+		scnprintf(msg, sizeof(msg),
+			  "uid=%d, gid=%d",
+			  from_kuid(&init_user_ns, cred->uid),
+			  from_kgid(&init_user_ns, cred->gid));
+		return return_trapped_task(TSEM_NETLINK_SEND, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_NETLINK_SEND, NOLOCK);
+}
+
+static int tsem_inode_create(struct inode *dir,
+			     struct dentry *dentry, umode_t mode)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s, mode=%u",
+			  dentry->d_name.name, mode);
+		return return_trapped_inode(TSEM_INODE_CREATE, dir, msg,
+					    NOLOCK);
+	}
+
+	if (bypass_inode(dir))
+		return 0;
+	return model_generic_event(TSEM_INODE_CREATE, NOLOCK);
+}
+
+static int tsem_inode_link(struct dentry *old_dentry, struct inode *dir,
+			   struct dentry *new_dentry)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "old_name=%s, new_name=%s",
+			  old_dentry->d_name.name, new_dentry->d_name.name);
+		return return_trapped_task(TSEM_INODE_LINK, msg, NOLOCK);
+	}
+
+	if (bypass_inode(dir))
+		return 0;
+	return model_generic_event(TSEM_INODE_LINK, NOLOCK);
+}
+
+static int tsem_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s", dentry->d_name.name);
+		return return_trapped_inode(TSEM_INODE_UNLINK, dir, msg,
+					    NOLOCK);
+	}
+
+	if (bypass_inode(dir))
+		return 0;
+	return model_generic_event(TSEM_INODE_UNLINK, NOLOCK);
+}
+
+static int tsem_inode_symlink(struct inode *dir, struct dentry *dentry,
+			      const char *old_name)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s", dentry->d_name.name);
+		return return_trapped_task(TSEM_INODE_SYMLINK, msg, NOLOCK);
+	}
+
+	if (bypass_inode(dir))
+		return 0;
+	return model_generic_event(TSEM_INODE_SYMLINK, NOLOCK);
+}
+
+static int tsem_inode_mkdir(struct inode *dir, struct dentry *dentry,
+			    umode_t mode)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "target=%s, mode=%u",
+			  dentry->d_name.name, mode);
+		return return_trapped_task(TSEM_INODE_MKDIR, msg, NOLOCK);
+	}
+
+	if (bypass_inode(dir))
+		return 0;
+	return model_generic_event(TSEM_INODE_MKDIR, NOLOCK);
+}
+
+static int tsem_inode_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s", dentry->d_name.name);
+		return return_trapped_task(TSEM_INODE_RMDIR, msg, NOLOCK);
+	}
+
+	if (bypass_inode(dir))
+		return 0;
+	return model_generic_event(TSEM_INODE_RMDIR, NOLOCK);
+}
+
+static int tsem_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
+			     struct inode *new_dir, struct dentry *new_dentry)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "old=%s, new=%s",
+			  old_dentry->d_name.name, new_dentry->d_name.name);
+		return return_trapped_task(TSEM_INODE_RENAME, msg, NOLOCK);
+	}
+
+	if (bypass_inode(old_dir))
+		return 0;
+	return model_generic_event(TSEM_INODE_RENAME, NOLOCK);
+}
+
+static int tsem_inode_mknod(struct inode *dir, struct dentry *dentry,
+			    umode_t mode, dev_t dev)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s, mode=%u, dev=%u",
+			  dentry->d_name.name, mode, dev);
+		return return_trapped_task(TSEM_INODE_MKNOD, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_INODE_MKNOD, NOLOCK);
+}
+
+static int tsem_inode_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "name=%s, mode=%u, uid=%d, gid=%d, size=%llu",
+			  dentry->d_name.name, attr->ia_mode,
+			  from_kuid(&init_user_ns, attr->ia_uid),
+			  from_kgid(&init_user_ns, attr->ia_gid),
+			  attr->ia_size);
+		return return_trapped_task(TSEM_INODE_SETATTR, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_INODE_SETATTR, NOLOCK);
+}
+
+static int tsem_inode_getattr(const struct path *path)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (unlikely(!tsem_ready))
+		return 0;
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "name=%s",
+			  path->dentry->d_name.name);
+		return return_trapped_task(TSEM_INODE_GETATTR, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_INODE_GETATTR, NOLOCK);
+}
+
+static int tsem_inode_setxattr(struct mnt_idmap *idmap,
+			       struct dentry *dentry, const char *name,
+			       const void *value, size_t size, int flags)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "fname=%s, name=%s, size=%lu, flags=%d",
+			  dentry->d_name.name, name, size, flags);
+		return return_trapped_task(TSEM_INODE_SETXATTR, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_INODE_SETXATTR, NOLOCK);
+}
+
+static int tsem_inode_getxattr(struct dentry *dentry, const char *name)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg),
+			  "fname=%s, name=%s", dentry->d_name.name, name);
+		return return_trapped_task(TSEM_INODE_GETXATTR, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_INODE_GETXATTR, NOLOCK);
+}
+
+static int tsem_inode_listxattr(struct dentry *dentry)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "fname=%s", dentry->d_name.name);
+		return return_trapped_task(TSEM_INODE_LISTXATTR, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_INODE_LISTXATTR, NOLOCK);
+}
+
+static int tsem_inode_removexattr(struct mnt_idmap *idmap,
+				  struct dentry *dentry, const char *name)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "fname=%s, name=%s",
+			  dentry->d_name.name, name);
+		return return_trapped_task(TSEM_INODE_REMOVEXATTR, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_INODE_REMOVEXATTR, NOLOCK);
+}
+
+static int tsem_inode_killpriv(struct mnt_idmap *idmap, struct dentry *dentry)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "fname=%s", dentry->d_name.name);
+		return return_trapped_task(TSEM_INODE_KILLPRIV, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_INODE_KILLPRIV, NOLOCK);
+}
+
+static int tsem_tun_dev_create(void)
+{
+	if (tsem_task_untrusted(current))
+		return return_trapped_task(TSEM_TUN_DEV_CREATE, "none",
+					   NOLOCK);
+
+	return model_generic_event(TSEM_TUN_DEV_CREATE, NOLOCK);
+}
+
+static int tsem_tun_dev_attach_queue(void *security)
+{
+	if (tsem_task_untrusted(current))
+		return return_trapped_task(TSEM_TUN_DEV_ATTACH_QUEUE, "none",
+					   NOLOCK);
+
+	return model_generic_event(TSEM_TUN_DEV_ATTACH_QUEUE, NOLOCK);
+}
+
+static int tsem_tun_dev_attach(struct sock *sk, void *security)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "family=%u", sk->sk_family);
+		return return_trapped_task(TSEM_TUN_DEV_ATTACH, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_TUN_DEV_ATTACH, NOLOCK);
+}
+
+static int tsem_tun_dev_open(void *security)
+{
+	if (tsem_task_untrusted(current))
+		return return_trapped_task(TSEM_TUN_DEV_OPEN, "none", NOLOCK);
+
+	return model_generic_event(TSEM_TUN_DEV_OPEN, NOLOCK);
+}
+
+#ifdef CONFIG_BPF_SYSCALL
+static int tsem_bpf(int cmd, union bpf_attr *attr, unsigned int size)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "cmd=%d, size=%u", cmd, size);
+		return return_trapped_task(TSEM_BPF, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_BPF, NOLOCK);
+}
+
+static int tsem_bpf_map(struct bpf_map *map, fmode_t fmode)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "type=%d, size=%u", map->map_type,
+			  fmode);
+		return return_trapped_task(TSEM_BPF_MAP, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_BPF_MAP, NOLOCK);
+}
+
+static int tsem_bpf_prog(struct bpf_prog *prog)
+{
+	char msg[TRAPPED_MSG_LENGTH];
+
+	if (tsem_task_untrusted(current)) {
+		scnprintf(msg, sizeof(msg), "type=%d", prog->type);
+		return return_trapped_task(TSEM_BPF_PROG, msg, NOLOCK);
+	}
+
+	return model_generic_event(TSEM_BPF_PROG, NOLOCK);
+}
+#endif
+
+static struct security_hook_list tsem_hooks[] __ro_after_init = {
+	LSM_HOOK_INIT(task_alloc, tsem_task_alloc),
+	LSM_HOOK_INIT(task_free, tsem_task_free),
+	LSM_HOOK_INIT(task_kill, tsem_task_kill),
+	LSM_HOOK_INIT(task_setpgid, tsem_task_setpgid),
+	LSM_HOOK_INIT(task_getpgid, tsem_task_getpgid),
+	LSM_HOOK_INIT(task_getsid, tsem_task_getsid),
+	LSM_HOOK_INIT(task_setnice, tsem_task_setnice),
+	LSM_HOOK_INIT(task_setioprio, tsem_task_setioprio),
+	LSM_HOOK_INIT(task_getioprio, tsem_task_getioprio),
+	LSM_HOOK_INIT(task_prlimit, tsem_task_prlimit),
+	LSM_HOOK_INIT(task_setrlimit, tsem_task_setrlimit),
+	LSM_HOOK_INIT(task_setscheduler, tsem_task_setscheduler),
+	LSM_HOOK_INIT(task_getscheduler, tsem_task_getscheduler),
+	LSM_HOOK_INIT(task_prctl, tsem_task_prctl),
+
+	LSM_HOOK_INIT(ptrace_traceme, tsem_ptrace_traceme),
+
+	LSM_HOOK_INIT(bprm_creds_for_exec, tsem_bprm_creds_for_exec),
+	LSM_HOOK_INIT(inode_alloc_security, tsem_inode_alloc_security),
+	LSM_HOOK_INIT(inode_free_security, tsem_inode_free_security),
+
+	LSM_HOOK_INIT(file_open, tsem_file_open),
+	LSM_HOOK_INIT(mmap_file, tsem_mmap_file),
+	LSM_HOOK_INIT(file_ioctl, tsem_file_ioctl),
+	LSM_HOOK_INIT(file_lock, tsem_file_lock),
+	LSM_HOOK_INIT(file_fcntl, tsem_file_fcntl),
+	LSM_HOOK_INIT(file_receive, tsem_file_receive),
+
+	LSM_HOOK_INIT(unix_stream_connect, tsem_unix_stream_connect),
+	LSM_HOOK_INIT(unix_may_send, tsem_unix_may_send),
+
+	LSM_HOOK_INIT(socket_create, tsem_socket_create),
+	LSM_HOOK_INIT(socket_connect, tsem_socket_connect),
+	LSM_HOOK_INIT(socket_bind, tsem_socket_bind),
+	LSM_HOOK_INIT(socket_accept, tsem_socket_accept),
+	LSM_HOOK_INIT(socket_listen, tsem_socket_listen),
+	LSM_HOOK_INIT(socket_socketpair, tsem_socket_socketpair),
+	LSM_HOOK_INIT(socket_sendmsg, tsem_socket_sendmsg),
+	LSM_HOOK_INIT(socket_recvmsg, tsem_socket_recvmsg),
+	LSM_HOOK_INIT(socket_getsockname, tsem_socket_getsockname),
+	LSM_HOOK_INIT(socket_getpeername, tsem_socket_getpeername),
+	LSM_HOOK_INIT(socket_setsockopt, tsem_socket_setsockopt),
+	LSM_HOOK_INIT(socket_shutdown, tsem_socket_shutdown),
+
+	LSM_HOOK_INIT(kernel_module_request, tsem_kernel_module_request),
+	LSM_HOOK_INIT(kernel_load_data, tsem_kernel_load_data),
+	LSM_HOOK_INIT(kernel_read_file, tsem_kernel_read_file),
+
+	LSM_HOOK_INIT(sb_mount, tsem_sb_mount),
+	LSM_HOOK_INIT(sb_umount, tsem_sb_umount),
+	LSM_HOOK_INIT(sb_remount, tsem_sb_remount),
+	LSM_HOOK_INIT(sb_pivotroot, tsem_sb_pivotroot),
+	LSM_HOOK_INIT(sb_statfs, tsem_sb_statfs),
+	LSM_HOOK_INIT(move_mount, tsem_move_mount),
+
+	LSM_HOOK_INIT(shm_associate, tsem_shm_associate),
+	LSM_HOOK_INIT(shm_shmctl, tsem_shm_shmctl),
+	LSM_HOOK_INIT(shm_shmat, tsem_shm_shmat),
+	LSM_HOOK_INIT(sem_associate, tsem_sem_associate),
+	LSM_HOOK_INIT(sem_semctl, tsem_sem_semctl),
+	LSM_HOOK_INIT(sem_semop, tsem_sem_semop),
+
+	LSM_HOOK_INIT(syslog, tsem_syslog),
+	LSM_HOOK_INIT(settime, tsem_settime),
+
+	LSM_HOOK_INIT(quotactl, tsem_quotactl),
+	LSM_HOOK_INIT(quota_on, tsem_quota_on),
+
+	LSM_HOOK_INIT(msg_queue_associate, tsem_msg_queue_associate),
+	LSM_HOOK_INIT(msg_queue_msgctl, tsem_msg_queue_msgctl),
+	LSM_HOOK_INIT(msg_queue_msgsnd, tsem_msg_queue_msgsnd),
+	LSM_HOOK_INIT(msg_queue_msgrcv, tsem_msg_queue_msgrcv),
+
+	LSM_HOOK_INIT(ipc_permission, tsem_ipc_permission),
+
+#ifdef CONFIG_KEYS
+	LSM_HOOK_INIT(key_alloc, tsem_key_alloc),
+	LSM_HOOK_INIT(key_permission, tsem_key_permission),
+#endif
+
+	LSM_HOOK_INIT(netlink_send, tsem_netlink_send),
+
+	LSM_HOOK_INIT(inode_create, tsem_inode_create),
+	LSM_HOOK_INIT(inode_link, tsem_inode_link),
+	LSM_HOOK_INIT(inode_unlink, tsem_inode_unlink),
+	LSM_HOOK_INIT(inode_symlink, tsem_inode_symlink),
+	LSM_HOOK_INIT(inode_mkdir, tsem_inode_mkdir),
+	LSM_HOOK_INIT(inode_rmdir, tsem_inode_rmdir),
+	LSM_HOOK_INIT(inode_mknod, tsem_inode_mknod),
+	LSM_HOOK_INIT(inode_rename, tsem_inode_rename),
+	LSM_HOOK_INIT(inode_setattr, tsem_inode_setattr),
+	LSM_HOOK_INIT(inode_getattr, tsem_inode_getattr),
+	LSM_HOOK_INIT(inode_setxattr, tsem_inode_setxattr),
+	LSM_HOOK_INIT(inode_getxattr, tsem_inode_getxattr),
+	LSM_HOOK_INIT(inode_listxattr, tsem_inode_listxattr),
+	LSM_HOOK_INIT(inode_removexattr, tsem_inode_removexattr),
+	LSM_HOOK_INIT(inode_killpriv, tsem_inode_killpriv),
+
+	LSM_HOOK_INIT(tun_dev_create, tsem_tun_dev_create),
+	LSM_HOOK_INIT(tun_dev_attach_queue, tsem_tun_dev_attach_queue),
+	LSM_HOOK_INIT(tun_dev_attach, tsem_tun_dev_attach),
+	LSM_HOOK_INIT(tun_dev_open, tsem_tun_dev_open),
+
+#ifdef CONFIG_BPF_SYSCALL
+	LSM_HOOK_INIT(bpf, tsem_bpf),
+	LSM_HOOK_INIT(bpf_map, tsem_bpf_map),
+	LSM_HOOK_INIT(bpf_prog, tsem_bpf_prog)
+#endif
+};
+
+static int configure_root_digest(void)
+{
+	int retn = 0;
+	char *digest = NULL;
+	u8 zero_digest[HASH_MAX_DIGESTSIZE];
+	unsigned int digestsize;
+	struct crypto_shash *tfm;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	if (default_hash_function && crypto_has_shash(default_hash_function,
+						      0, 0)) {
+		digest = default_hash_function;
+		pr_warn("tsem: Using digest %s from command-line.\n", digest);
+	}
+	if (!digest && default_hash_function)
+		pr_warn("tsem: Unknown root digest %s, using sha256.\n",
+			default_hash_function);
+	if (!digest)
+		digest = "sha256";
+
+	tsem_context(current)->digestname = kstrdup(digest, GFP_KERNEL);
+	if (!tsem_context(current)->digestname)
+		return -ENOMEM;
+
+	tfm = crypto_alloc_shash(digest, 0, 0);
+	if (IS_ERR(tfm))
+		return PTR_ERR(tfm);
+
+	shash->tfm = tfm;
+	retn = crypto_shash_digest(shash, NULL, 0, zero_digest);
+	if (retn)
+		goto done;
+
+	tsem_context(current)->tfm = tfm;
+	memcpy(root_context.zero_digest, zero_digest, digestsize);
+
+ done:
+	if (retn) {
+		kfree(tsem_context(current)->digestname);
+		crypto_free_shash(tfm);
+	}
+
+	return retn;
+}
+
+static int __init set_ready(void)
+{
+	int retn;
+
+	if (!tsem_available)
+		return 0;
+
+	retn = configure_root_digest();
+	if (retn)
+		goto done;
+
+	retn = tsem_model_add_aggregate();
+	if (retn)
+		goto done;
+
+	retn = tsem_fs_init();
+	if (retn)
+		goto done;
+
+	tsem_ready = 1;
+	pr_info("tsem: Now ready for modeling.\n");
+
+ done:
+	return retn;
+}
+
+late_initcall(set_ready);
+
+/**
+ * tesm_init() - Register Trusted Security Event Modeling LSM.
+ *
+ * This function is responsible for initializing the TSEM LSM.  It is
+ * invoked at the fs_initcall level.  In addition to configuring the
+ * LSM hooks this function initializes the Trusted Modeling Agent
+ * context including the event actions.  The cache from which
+ * the tsem_event description structures is also initialized.
+ *
+ * Return: If the TSEM LSM is successfully initialized a value of zero
+ *	   is returned.  A non-zero error code is returned if
+ *	   initialization fails.  Currently the only failure mode can
+ *	   come from the initialization of the tsem_event cache.
+ */
+static int __init tsem_init(void)
+{
+	int retn;
+	struct tsem_task *tsk = tsem_task(current);
+	struct tsem_context *ctx = &root_context;
+	struct tsem_model *model = &root_model;
+
+	security_add_hooks(tsem_hooks, ARRAY_SIZE(tsem_hooks), "tsem");
+
+	tsk->context = ctx;
+	kref_init(&ctx->kref);
+	kref_get(&ctx->kref);
+
+	root_context.model = &root_model;
+
+	retn = tsem_event_cache_init();
+	if (retn)
+		return retn;
+	retn = tsem_event_magazine_allocate(ctx, magazine_size);
+	if (retn)
+		goto done;
+
+	memcpy(ctx->actions, tsem_root_actions, sizeof(tsem_root_actions));
+
+	retn = tsem_model_cache_init(model, magazine_size);
+	if (retn)
+		goto done;
+
+	retn = tsem_export_cache_init();
+	if (retn)
+		goto done;
+
+	pr_info("tsem: Initialized %s modeling.\n",
+		no_root_modeling ? "domain only" : "full");
+	tsem_available = true;
+	tsk->trust_status = TSEM_TASK_TRUSTED;
+	retn = 0;
+
+ done:
+	if (retn) {
+		tsem_event_magazine_free(ctx);
+		tsem_model_magazine_free(model);
+	}
+	return retn;
+}
+
+DEFINE_LSM(tsem) = {
+	.name = "tsem",
+	.init = tsem_init,
+	.blobs = &tsem_blob_sizes,
+};
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 06/13] Add root domain trust implementation.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (4 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 05/13] Add primary TSEM implementation file Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-07-10 10:23 ` [PATCH 07/13] Implement TSEM control plane Dr. Greg
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

The trust.c contains the support infrastructure for anchoring the
root modeling domain in a hardware TPM implementation if it is
available.

The security state coefficients are extended, by default, into
Platform Configuration Register (PCR) 11 in order to provide
authentication of the security execution trajectory for the root
domain.  This value was chosen to avoid the use of PCR register
10 that the Integrity Measurement Architecture uses to register
the integrity events that it handles.

This PCR value can be changed through the kernel configuration
process.

This file is also responsible for computing the hardware platform
aggregate measurement.  This is the linear extension sum over PCR
rsegisters 0 through 7.  This file contains an accessor function
for surfacing this value to either the internal or external
Trusted Modeling Agent implementations.

The platform hardware aggregate value is designed to be the first
security state coefficient injected into a model.

Updates to the TPM are through an ordered asynchronous workqueue.
This is needed in order to support the modeling of security event
hooks that are called while a process is in atomic context.

This is also a performance optimization given that TPM
transactions are not highly performant, particularly on discrete
TPM implementations.  Extension of values to PCR's have
historically been done on a relatively infrequent basis, such as
when a file is accessed.  The high rate of security event
processing that can occur in the root modeling namespace
significantly benefits from this optimization.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/trust.c | 220 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 220 insertions(+)
 create mode 100644 security/tsem/trust.c

diff --git a/security/tsem/trust.c b/security/tsem/trust.c
new file mode 100644
index 000000000000..85f7542cf76f
--- /dev/null
+++ b/security/tsem/trust.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * Implements management of a TPM trust root for the in kernel TMA.
+ */
+
+#include <linux/tpm.h>
+
+#include "tsem.h"
+
+static struct workqueue_struct *tpm_update_wq;
+
+static u8 zero_aggregate[HASH_MAX_DIGESTSIZE];
+
+static struct tpm_chip *tpm;
+
+static struct tpm_digest *digests;
+
+struct hardware_aggregate {
+	struct list_head list;
+	char *name;
+	u8 value[HASH_MAX_DIGESTSIZE];
+};
+
+DEFINE_MUTEX(hardware_aggregate_mutex);
+LIST_HEAD(hardware_aggregate_list);
+
+static struct hardware_aggregate *find_aggregate(void)
+{
+	struct hardware_aggregate *aggregate;
+
+	list_for_each_entry(aggregate, &hardware_aggregate_list, list) {
+		if (!strcmp(aggregate->name,
+			    tsem_context(current)->digestname))
+			goto done;
+	}
+	aggregate = NULL;
+
+ done:
+	return aggregate;
+}
+
+static struct hardware_aggregate *add_aggregate(u8 *new_aggregate)
+{
+	struct hardware_aggregate *aggregate;
+
+	aggregate = kzalloc(sizeof(*aggregate), GFP_KERNEL);
+	if (!aggregate)
+		return NULL;
+
+	aggregate->name = kstrdup(tsem_context(current)->digestname,
+				  GFP_KERNEL);
+	if (!aggregate->name) {
+		kfree(aggregate);
+		return NULL;
+	}
+	memcpy(aggregate->value, new_aggregate, tsem_digestsize());
+
+	list_add(&aggregate->list, &hardware_aggregate_list);
+
+	return aggregate;
+}
+
+/**
+ * tsem_trust_aggregate() - Return a pointer to the hardware aggregate.
+ *
+ * This function returns a pointer to the hardware aggregate encoded
+ * with the hash function for the current modeling domain.
+ *
+ * Return: A pointer is returned to the hardware aggregate value that
+ *	   has been cached.
+ */
+u8 *tsem_trust_aggregate(void)
+{
+	u8 aggregate[HASH_MAX_DIGESTSIZE], *retn = zero_aggregate;
+	u16 size;
+	unsigned int lp;
+	struct tpm_digest pcr;
+	struct hardware_aggregate *hw_aggregate;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	if (!tpm)
+		return retn;
+
+	mutex_lock(&hardware_aggregate_mutex);
+
+	hw_aggregate = find_aggregate();
+	if (hw_aggregate) {
+		retn = hw_aggregate->value;
+		goto done;
+	}
+
+	shash->tfm = tsem_digest();
+	if (crypto_shash_init(shash))
+		goto done;
+
+	if (tpm_is_tpm2(tpm))
+		pcr.alg_id = TPM_ALG_SHA256;
+	else
+		pcr.alg_id = TPM_ALG_SHA1;
+	memset(pcr.digest, '\0', TPM_MAX_DIGEST_SIZE);
+
+	for (lp = 0; lp < tpm->nr_allocated_banks; lp++) {
+		if (pcr.alg_id == tpm->allocated_banks[lp].alg_id) {
+			size = tpm->allocated_banks[lp].digest_size;
+			break;
+		}
+	}
+
+	for (lp = 0; lp < 8; ++lp) {
+		if (tpm_pcr_read(tpm, lp, &pcr))
+			goto done;
+		if (crypto_shash_update(shash, pcr.digest, size))
+			goto done;
+	}
+	if (!crypto_shash_final(shash, aggregate)) {
+		hw_aggregate = add_aggregate(aggregate);
+		if (hw_aggregate)
+			retn = hw_aggregate->value;
+	}
+
+ done:
+	mutex_unlock(&hardware_aggregate_mutex);
+
+	if (retn == zero_aggregate)
+		pr_warn("tsem: Error generating platform aggregate\n");
+
+	return retn;
+}
+
+static void tpm_update_worker(struct work_struct *work)
+{
+	int amt, bank, digestsize;
+	struct tsem_event *ep;
+
+	ep = container_of(work, struct tsem_event, work);
+	digestsize = ep->digestsize;
+
+	for (bank = 0; bank < tpm->nr_allocated_banks; bank++) {
+		if (tpm->allocated_banks[bank].digest_size > digestsize) {
+			amt = digestsize;
+			memset(digests[bank].digest, '\0',
+			       tpm->allocated_banks[bank].digest_size);
+		} else
+			amt = tpm->allocated_banks[bank].digest_size;
+		memcpy(digests[bank].digest, ep->mapping, amt);
+	}
+
+	if (tpm_pcr_extend(tpm, CONFIG_SECURITY_TSEM_ROOT_MODEL_PCR,
+			   digests))
+		pr_warn("tsem: Failed TPM update.\n");
+
+	tsem_event_put(ep);
+}
+
+/**
+ * tsem_trust_add_point() - Add a measurement to the trust root.
+ * @ep: A pointer to the security event description whose measurement
+ *	is to be extended into the TPM.
+ *
+ * This function extends the platform configuration register being
+ * used to document the hardware root of trust for internally modeled
+ * domains with a security event coefficient value.
+ *
+ * Return: If the extension fails the error return value from the
+ *	   TPM command is returned, otherwise a value of zero is
+ *	   returned.
+ */
+int tsem_trust_add_event(struct tsem_event *ep)
+{
+	bool retn;
+
+	if (!tpm)
+		return 0;
+
+	tsem_event_get(ep);
+	ep->digestsize = tsem_digestsize();
+
+	INIT_WORK(&ep->work, tpm_update_worker);
+	retn = queue_work(tpm_update_wq, &ep->work);
+
+	return 0;
+}
+
+static int __init trust_init(void)
+{
+	int retn = -EINVAL, lp;
+
+	tpm = tpm_default_chip();
+	if (!tpm)
+		return retn;
+
+	tpm_update_wq = alloc_ordered_workqueue("tsem_tpm", 0);
+	if (IS_ERR(tpm_update_wq)) {
+		retn = PTR_ERR(tpm_update_wq);
+		goto done;
+	}
+
+	digests = kcalloc(tpm->nr_allocated_banks, sizeof(*digests), GFP_NOFS);
+	if (!digests) {
+		tpm = NULL;
+		return retn;
+	}
+	for (lp = 0; lp < tpm->nr_allocated_banks; lp++)
+		digests[lp].alg_id = tpm->allocated_banks[lp].alg_id;
+	retn = 0;
+
+ done:
+	if (retn) {
+		destroy_workqueue(tpm_update_wq);
+		kfree(digests);
+	}
+
+	return retn;
+}
+
+device_initcall_sync(trust_init);
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 07/13] Implement TSEM control plane.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (5 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 06/13] Add root domain trust implementation Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-07-10 10:23 ` [PATCH 08/13] Add namespace implementation Dr. Greg
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

The fs.c file contains the implementation of the TSEM control
plane that is rooted in the following directory in the securityfs
filesystem:

/sys/kernel/security/tsem

The following file documents the interface provided by the
control plane:

Documentation/ABI/testing/tsem

The pseudo-files act on the modeling context of the process that
is reading or writing to the control plane files.  For example,
reading the 'id' pseudo-file, returns the security modeling
namespace identifier that the process is running in.

The 'control' pseudo-file is the only writable file in the plane
and is used to control the TSEM implementation.  The most
important and primary roles are to create namespaces and set the
trust status of a process modeled by an external TMA.

The ExternalTMA directory is used to segregate the pseudo-files
that are created in order to surface security event descriptions
to an external trust orchestrator.  The files in this directory
appear as the numeric value of the modeling domain they were
created for.

The following directory:

/sys/kernel/security/tsem/InternalTMA

Holds directories that are used to surface the characteristics of
internal Trusted Modeling agents.  There is currently only a
single internal TMA implemented and its characteristics are in
the following directory:

/sys/kernel/security/tsem/InternalTMA/model0

This model is used to allow new TMA's to be implemented and to
maintain ABI compatibility if changes are needed in a TMA.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/fs.c | 1336 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1336 insertions(+)
 create mode 100644 security/tsem/fs.c

diff --git a/security/tsem/fs.c b/security/tsem/fs.c
new file mode 100644
index 000000000000..9752aca13afa
--- /dev/null
+++ b/security/tsem/fs.c
@@ -0,0 +1,1336 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * Implements the securityfs based control plane.
+ */
+
+#include <linux/seq_file.h>
+#include <linux/poll.h>
+
+#include "tsem.h"
+
+static struct dentry *tsem_dir;
+static struct dentry *control;
+static struct dentry *id;
+static struct dentry *aggregate;
+static struct dentry *internal_tma;
+static struct dentry *model;
+static struct dentry *forensics;
+static struct dentry *forensics_counts;
+static struct dentry *forensics_coeff;
+static struct dentry *trajectory;
+static struct dentry *trajectory_counts;
+static struct dentry *trajectory_coeff;
+static struct dentry *measurement;
+static struct dentry *state;
+static struct dentry *external_tma;
+
+struct control_commands {
+	char *cmd;
+	enum tsem_control_type type;
+};
+
+static const char * const control_commands[] = {
+	"internal",
+	"external",
+	"enforce",
+	"seal",
+	"trusted",
+	"untrusted",
+	"state",
+	"pseudonym",
+	"base"
+};
+
+enum namespace_argument_type {
+	NS_REF = 0,
+	NS_DIGEST,
+	NS_KEY,
+	NS_CACHE
+};
+
+static const char * const namespace_arguments[] = {
+	"nsref",
+	"digest",
+	"key",
+	"cache"
+};
+
+enum control_argument_type {
+	CONTROL_KEY = 0,
+	CONTROL_PID
+};
+
+static const char * const control_arguments[] = {
+	"key",
+	"pid"
+};
+
+static bool can_access_fs(void)
+{
+	struct tsem_context *ctx = tsem_context(current);
+
+	if (ctx->external)
+		return false;
+	if (capable(TSEM_CONTROL_CAPABILITY))
+		return true;
+	if (ctx->sealed)
+		return false;
+	return true;
+}
+
+static int control_COE(unsigned long cmd, pid_t pid, char *keystr)
+{
+	bool wakeup = false;
+	int retn = -ESRCH;
+	u8 event_key[HASH_MAX_DIGESTSIZE];
+	struct task_struct *COE;
+	struct tsem_task *task;
+	struct tsem_task *tma = tsem_task(current);
+
+	rcu_read_lock();
+	COE = find_task_by_vpid(pid);
+	if (COE != NULL) {
+		task = tsem_task(COE);
+		if (tsem_context(COE)->id != tma->tma_for_ns) {
+			retn = -EINVAL;
+			goto done;
+		}
+
+		retn = tsem_ns_event_key(task->task_key, keystr, event_key);
+		if (retn)
+			goto done;
+
+		if (memcmp(tma->task_key, event_key, tsem_digestsize())) {
+			retn = -EINVAL;
+			goto done;
+		}
+
+		if (cmd == TSEM_CONTROL_UNTRUSTED)
+			task->trust_status = TSEM_TASK_UNTRUSTED;
+		if (cmd == TSEM_CONTROL_TRUSTED) {
+			task->trust_status &= ~TSEM_TASK_TRUST_PENDING;
+			if (tsem_task_trusted(COE))
+				task->trust_status = TSEM_TASK_TRUSTED;
+		}
+		retn = 0;
+		wakeup = true;
+	}
+
+ done:
+	rcu_read_unlock();
+
+	if (retn == -EINVAL)
+		pr_warn("tsem: Invalid process release request.\n");
+
+	if (wakeup)
+		wake_up_process(COE);
+
+	return retn;
+}
+
+static int config_COE(unsigned long cmd, char *arg)
+{
+	char **argv, *argp, *key = NULL;
+	int argc, retn = -EINVAL;
+	unsigned int lp;
+	long pid = 0;
+	enum control_argument_type control_arg;
+
+	if (!*arg)
+		return retn;
+
+	argv = argv_split(GFP_KERNEL, arg, &argc);
+	if (!argv)
+		return -ENOMEM;
+
+	for (lp = 0; lp < argc; ++lp) {
+		argp = strchr(argv[lp], '=');
+		if (!argp)
+			goto done;
+		*argp++ = '\0';
+
+		control_arg = match_string(control_arguments,
+					   ARRAY_SIZE(control_arguments),
+					   argv[lp]);
+		if (control_arg < 0)
+			goto done;
+
+		switch (control_arg) {
+		case CONTROL_KEY:
+			key = argp;
+			if (strlen(key) != tsem_digestsize()*2)
+				goto done;
+			break;
+		case CONTROL_PID:
+			if (kstrtol(argp, 0, &pid))
+				goto done;
+			break;
+		}
+	}
+
+	if (!key || !pid)
+		goto done;
+	retn = control_COE(cmd, pid, key);
+
+ done:
+	argv_free(argv);
+	return retn;
+}
+
+static int config_context(unsigned long cmd, char *bufr)
+{
+	int retn = -EINVAL;
+	unsigned int lp;
+	struct tsem_context *ctx = tsem_context(current);
+
+	if (ctx->sealed)
+		return -EPERM;
+
+	if (cmd == TSEM_CONTROL_SEAL) {
+		ctx->sealed = true;
+		retn = 0;
+	}
+
+	if (cmd == TSEM_CONTROL_ENFORCE) {
+		for (lp = 0; lp < ARRAY_SIZE(tsem_root_actions); ++lp)
+			ctx->actions[lp] = TSEM_ACTION_EPERM;
+		retn = 0;
+	}
+
+	return retn;
+}
+
+static int config_point(enum tsem_control_type type, char *arg)
+{
+	char *argp;
+	int retn = -EINVAL;
+	u8 mapping[HASH_MAX_DIGESTSIZE];
+
+	if (!arg)
+		goto done;
+
+	argp = strchr(arg, '=');
+	if (!argp)
+		goto done;
+	*argp++ = '\0';
+
+	if (strcmp(arg, "value"))
+		goto done;
+
+	if (strlen(argp) != tsem_digestsize()*2)
+		goto done;
+	if (hex2bin(mapping, argp, tsem_digestsize()))
+		goto done;
+
+	if (type == TSEM_CONTROL_MAP_STATE)
+		retn = tsem_model_load_point(mapping);
+	else if (type == TSEM_CONTROL_MAP_PSEUDONYM)
+		retn = tsem_model_load_pseudonym(mapping);
+	else {
+		tsem_model_load_base(mapping);
+		retn = 0;
+	}
+
+ done:
+	return retn;
+}
+
+static int config_namespace(enum tsem_control_type type, const char *arg)
+{
+	char **argv, *argp, *digest = "sha256", *key = NULL;
+	int argc, retn = -EINVAL;
+	unsigned int lp, cache_size = TSEM_MAGAZINE_SIZE_INTERNAL;
+	enum namespace_argument_type ns_arg;
+	enum tsem_ns_reference ns_ref = TSEM_NS_INITIAL;
+
+	if (type == TSEM_CONTROL_EXTERNAL)
+		cache_size = TSEM_MAGAZINE_SIZE_EXTERNAL;
+
+	if (!arg) {
+		if (type == TSEM_CONTROL_EXTERNAL)
+			return retn;
+		return tsem_ns_create(type, digest, ns_ref, key, cache_size);
+	}
+
+	argv = argv_split(GFP_KERNEL, arg, &argc);
+	if (!argv)
+		return -ENOMEM;
+
+	for (lp = 0; lp < argc; ++lp) {
+		argp = strchr(argv[lp], '=');
+		if (!argp)
+			goto done;
+		*argp++ = '\0';
+
+		ns_arg = match_string(namespace_arguments,
+				    ARRAY_SIZE(namespace_arguments), argv[lp]);
+		if (ns_arg < 0)
+			goto done;
+
+		switch (ns_arg) {
+		case NS_REF:
+			if (!strcmp(argp, "current"))
+				ns_ref = TSEM_NS_CURRENT;
+			else if (!strcmp(argp, "initial"))
+				ns_ref = TSEM_NS_INITIAL;
+			else
+				goto done;
+			break;
+		case NS_DIGEST:
+			digest = argp;
+			if (!crypto_has_shash(digest, 0, 0))
+				goto done;
+			break;
+		case NS_KEY:
+			key = argp;
+			if (strlen(key) % 2)
+				goto done;
+			break;
+		case NS_CACHE:
+			if (kstrtouint(argp, 0, &cache_size))
+				goto done;
+			if (!cache_size)
+				goto done;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (type == TSEM_CONTROL_EXTERNAL && !key)
+		goto done;
+
+	retn = tsem_ns_create(type, digest, ns_ref, key, cache_size);
+
+ done:
+	argv_free(argv);
+	return retn;
+}
+
+static void show_event(struct seq_file *c, struct tsem_event *ep)
+{
+	tsem_fs_show_field(c, "event");
+	if (ep->pid)
+		tsem_fs_show_key(c, ",", "pid", "%u", ep->pid);
+	tsem_fs_show_key(c, ",", "process", "%s", ep->comm);
+	tsem_fs_show_key(c, ",", "type", "%s", tsem_names[ep->event]);
+	tsem_fs_show_key(c, "}, ", "task_id", "%*phN", tsem_digestsize(),
+			 ep->task_id);
+
+	tsem_fs_show_field(c, "COE");
+	tsem_fs_show_key(c, ",", "uid", "%u", ep->COE.uid);
+	tsem_fs_show_key(c, ",", "euid", "%u", ep->COE.euid);
+	tsem_fs_show_key(c, ",", "suid", "%u", ep->COE.suid);
+	tsem_fs_show_key(c, ",", "gid", "%u", ep->COE.gid);
+	tsem_fs_show_key(c, ",", "egid", "%u", ep->COE.egid);
+	tsem_fs_show_key(c, ",", "sgid", "%u", ep->COE.sgid);
+	tsem_fs_show_key(c, ",", "fsuid", "%u", ep->COE.fsuid);
+	tsem_fs_show_key(c, ",", "fsgid", "%u", ep->COE.fsgid);
+	tsem_fs_show_key(c, "}, ", "capeff", "0x%llx", ep->COE.capeff.value);
+}
+
+static void show_file(struct seq_file *c, struct tsem_event *ep)
+{
+	if (ep->event == TSEM_FILE_OPEN)
+		tsem_fs_show_field(c, "file_open");
+	else
+		tsem_fs_show_field(c, "file");
+
+	tsem_fs_show_key(c, ",", "flags", "%u", ep->file.flags);
+	tsem_fs_show_key(c, ",", "uid", "%u", ep->file.uid);
+	tsem_fs_show_key(c, ",", "gid", "%u", ep->file.gid);
+	tsem_fs_show_key(c, ",", "mode", "0%o", ep->file.mode);
+	tsem_fs_show_key(c, ",", "path", "%s", ep->pathname);
+	tsem_fs_show_key(c, ",", "s_magic", "0x%0x", ep->file.s_magic);
+	tsem_fs_show_key(c, ",", "s_id", "%s", ep->file.s_id);
+	tsem_fs_show_key(c, ",", "s_uuid", "%*phN", sizeof(ep->file.s_uuid),
+		 ep->file.s_uuid);
+	tsem_fs_show_key(c, "}", "digest", "%*phN", tsem_digestsize(),
+			 ep->file.digest);
+}
+
+static void show_mmap(struct seq_file *c, struct tsem_event *ep)
+{
+	struct tsem_mmap_file_args *args = &ep->CELL.mmap_file;
+
+	show_event(c, ep);
+
+	tsem_fs_show_field(c, tsem_names[ep->event]);
+	tsem_fs_show_key(c, ",", "type", "%u", args->file == NULL);
+	tsem_fs_show_key(c, ",", "reqprot", "%u", args->reqprot);
+	tsem_fs_show_key(c, ",", "prot", "%u", args->prot);
+
+	if (args->file) {
+		tsem_fs_show_key(c, ",", "flags", "%u", args->flags);
+		show_file(c, ep);
+		seq_putc(c, '}');
+	} else
+		tsem_fs_show_key(c, "}", "flags", "%u", args->flags);
+}
+
+static void show_socket_create(struct seq_file *c, struct tsem_event *ep)
+{
+	struct tsem_socket_create_args *args = &ep->CELL.socket_create;
+
+	show_event(c, ep);
+
+	tsem_fs_show_field(c, tsem_names[ep->event]);
+	tsem_fs_show_key(c, ",", "family", "%u", args->family);
+	tsem_fs_show_key(c, ",", "type", "%u", args->type);
+	tsem_fs_show_key(c, ",", "protocol", "%u", args->protocol);
+	tsem_fs_show_key(c, "}", "kern", "%u", args->kern);
+}
+
+static void show_socket(struct seq_file *c, struct tsem_event *ep)
+{
+	struct sockaddr_in *ipv4;
+	struct sockaddr_in6 *ipv6;
+	struct tsem_socket_connect_args *scp = &ep->CELL.socket_connect;
+
+	show_event(c, ep);
+
+	tsem_fs_show_field(c, tsem_names[ep->event]);
+	tsem_fs_show_key(c, ",", "family", "%u", scp->family);
+
+	switch (scp->family) {
+	case AF_INET:
+		ipv4 = (struct sockaddr_in *) &scp->u.ipv4;
+		tsem_fs_show_key(c, ",", "port", "%u", ipv4->sin_port);
+		tsem_fs_show_key(c, "}", "addr", "%u", ipv4->sin_addr.s_addr);
+		break;
+	case AF_INET6:
+		ipv6 = (struct sockaddr_in6 *) &scp->u.ipv6;
+		tsem_fs_show_key(c, ",", "port", "%u", ipv6->sin6_port);
+		tsem_fs_show_key(c, ",", "flow", "%u", ipv6->sin6_flowinfo);
+		tsem_fs_show_key(c, ",", "scope", "%u", ipv6->sin6_scope_id);
+		tsem_fs_show_key(c, "}", "addr", "%*phN",
+			 (int) sizeof(ipv6->sin6_addr.in6_u.u6_addr8),
+			 ipv6->sin6_addr.in6_u.u6_addr8);
+		break;
+	case AF_UNIX:
+		tsem_fs_show_key(c, "}", "addr", "%s", scp->u.path);
+		break;
+	default:
+		tsem_fs_show_key(c, "}", "addr", "%*phN", tsem_digestsize(),
+				 scp->u.mapping);
+		break;
+	}
+}
+
+static void show_socket_accept(struct seq_file *c, struct tsem_event *ep)
+{
+	struct tsem_socket_accept_args *sap = &ep->CELL.socket_accept;
+
+	show_event(c, ep);
+
+	tsem_fs_show_field(c, tsem_names[ep->event]);
+	tsem_fs_show_key(c, ",", "family", "%u", sap->family);
+	tsem_fs_show_key(c, ",", "type", "%u", sap->type);
+	tsem_fs_show_key(c, ",", "port", "%u", sap->port);
+
+	switch (sap->family) {
+	case AF_INET:
+		tsem_fs_show_key(c, "}", "addr", "%u", sap->u.ipv4);
+		break;
+	case AF_INET6:
+		tsem_fs_show_key(c, "}", "addr", "%*phN",
+			 (int) sizeof(sap->u.ipv6.in6_u.u6_addr8),
+			 sap->u.ipv6.in6_u.u6_addr8);
+		break;
+	case AF_UNIX:
+		tsem_fs_show_key(c, "}", "addr", "%s", sap->u.path);
+		break;
+	default:
+		tsem_fs_show_key(c, "}", "addr", "%*phN", tsem_digestsize(),
+				 sap->u.mapping);
+		break;
+	}
+}
+
+static void show_task_kill(struct seq_file *c, struct tsem_event *ep)
+{
+	struct tsem_task_kill_args *args = &ep->CELL.task_kill;
+
+	show_event(c, ep);
+
+	tsem_fs_show_field(c, tsem_names[ep->event]);
+	tsem_fs_show_key(c, ",", "cross", "%u", args->cross_model);
+	tsem_fs_show_key(c, ",", "signal", "%u", args->signal);
+	tsem_fs_show_key(c, "}", "target", "%*phN", tsem_digestsize(),
+			 args->target);
+}
+
+static void show_event_generic(struct seq_file *c, struct tsem_event *ep)
+{
+	show_event(c, ep);
+
+	tsem_fs_show_field(c, tsem_names[ep->event]);
+	tsem_fs_show_key(c, "}", "type", "%s",
+			 tsem_names[ep->CELL.event_type]);
+}
+
+static void *trajectory_start(struct seq_file *c, loff_t *pos)
+{
+	struct list_head *end;
+	struct tsem_model *model = tsem_model(current);
+
+	spin_lock(&model->trajectory_lock);
+	end = model->trajectory_list.prev;
+	spin_unlock(&model->trajectory_lock);
+
+	mutex_lock(&model->trajectory_end_mutex);
+	model->trajectory_end = end;
+
+	return seq_list_start(&model->trajectory_list, *pos);
+}
+
+static void *trajectory_next(struct seq_file *c, void *p, loff_t *pos)
+{
+	struct list_head *next = ((struct list_head *) p)->next;
+	struct tsem_model *model = tsem_model(current);
+
+	if (!model->trajectory_end) {
+		++*pos;
+		return NULL;
+	}
+
+	if (next == model->trajectory_end)
+		model->trajectory_end = NULL;
+
+	return seq_list_next(p, &model->trajectory_list, pos);
+}
+
+static void trajectory_stop(struct seq_file *c, void *pos)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	mutex_unlock(&model->trajectory_end_mutex);
+}
+
+static int trajectory_show(struct seq_file *c, void *trajectory)
+{
+	struct tsem_event *ep;
+
+	ep = list_entry(trajectory, struct tsem_event, list);
+
+	seq_putc(c, '{');
+	tsem_fs_show_trajectory(c, ep);
+	seq_puts(c, "}\n");
+
+	return 0;
+}
+
+static const struct seq_operations trajectory_seqops = {
+	.start = trajectory_start,
+	.next = trajectory_next,
+	.stop = trajectory_stop,
+	.show = trajectory_show
+};
+
+static int trajectory_open(struct inode *inode, struct file *file)
+{
+	if (!can_access_fs())
+		return -EACCES;
+	return seq_open(file, &trajectory_seqops);
+}
+
+static const struct file_operations trajectory_ops = {
+	.open = trajectory_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static void *trajectory_count_start(struct seq_file *c, loff_t *pos)
+{
+	struct list_head *end;
+	struct tsem_model *model = tsem_model(current);
+
+	spin_lock(&model->point_lock);
+	end = model->point_list.prev;
+	spin_unlock(&model->point_lock);
+
+	mutex_lock(&model->point_end_mutex);
+	model->point_end = end;
+
+	return seq_list_start(&model->point_list, *pos);
+}
+
+static void *trajectory_count_next(struct seq_file *c, void *p, loff_t *pos)
+{
+	struct list_head *next = ((struct list_head *) p)->next;
+	struct tsem_model *model = tsem_model(current);
+
+	if (!model->point_end) {
+		++*pos;
+		return NULL;
+	}
+
+	if (next == model->point_end)
+		model->point_end = NULL;
+
+	return seq_list_next(p, &model->point_list, pos);
+}
+
+static void trajectory_count_stop(struct seq_file *c, void *pos)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	mutex_unlock(&model->point_end_mutex);
+}
+
+static int trajectory_count_show(struct seq_file *c, void *point)
+{
+	struct tsem_event_point *pt;
+
+	pt = list_entry(point, struct tsem_event_point, list);
+	if (!pt->valid)
+		return 0;
+
+	seq_printf(c, "%llu\n", pt->count);
+	return 0;
+}
+
+static const struct seq_operations trajectory_count_seqops = {
+	.start = trajectory_count_start,
+	.next = trajectory_count_next,
+	.stop = trajectory_count_stop,
+	.show = trajectory_count_show
+};
+
+static int trajectory_count_open(struct inode *inode, struct file *file)
+{
+	if (!can_access_fs())
+		return -EACCES;
+	return seq_open(file, &trajectory_count_seqops);
+}
+
+static const struct file_operations trajectory_count_ops = {
+	.open = trajectory_count_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static void *trajectory_point_start(struct seq_file *c, loff_t *pos)
+{
+	struct list_head *end;
+	struct tsem_model *model = tsem_model(current);
+
+	spin_lock(&model->point_lock);
+	end = model->point_list.prev;
+	spin_unlock(&model->point_lock);
+
+	mutex_lock(&model->point_end_mutex);
+	model->point_end = end;
+
+	return seq_list_start(&model->point_list, *pos);
+}
+
+static void *trajectory_point_next(struct seq_file *c, void *p, loff_t *pos)
+{
+	struct list_head *next = ((struct list_head *) p)->next;
+	struct tsem_model *model = tsem_model(current);
+
+	if (!model->point_end) {
+		++*pos;
+		return NULL;
+	}
+
+	if (next == model->point_end)
+		model->point_end = NULL;
+
+	return seq_list_next(p, &model->point_list, pos);
+}
+
+static void trajectory_point_stop(struct seq_file *c, void *pos)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	mutex_unlock(&model->point_end_mutex);
+}
+
+static int trajectory_point_show(struct seq_file *c, void *point)
+{
+	struct tsem_event_point *pt;
+
+	pt = list_entry(point, struct tsem_event_point, list);
+	if (!pt->valid)
+		return 0;
+
+	seq_printf(c, "%*phN\n", tsem_digestsize(), pt->point);
+	return 0;
+}
+
+static const struct seq_operations trajectory_point_seqops = {
+	.start = trajectory_point_start,
+	.next = trajectory_point_next,
+	.stop = trajectory_point_stop,
+	.show = trajectory_point_show
+};
+
+static int trajectory_point_open(struct inode *inode, struct file *file)
+{
+	if (!can_access_fs())
+		return -EACCES;
+	return seq_open(file, &trajectory_point_seqops);
+}
+
+static const struct file_operations trajectory_point_ops = {
+	.open = trajectory_point_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static int open_control(struct inode *inode, struct file *filp)
+{
+	if (!capable(TSEM_CONTROL_CAPABILITY))
+		return -EACCES;
+	if (!(filp->f_flags & O_WRONLY))
+		return -EACCES;
+	return 0;
+}
+
+static ssize_t write_control(struct file *file, const char __user *buf,
+			     size_t datalen, loff_t *ppos)
+{
+	char *p, *arg, cmdbufr[128];
+	ssize_t retn = -EINVAL;
+	enum tsem_control_type type;
+
+	if (*ppos != 0)
+		goto done;
+	if (datalen > sizeof(cmdbufr)-1)
+		goto done;
+
+	memset(cmdbufr, '\0', sizeof(cmdbufr));
+	if (copy_from_user(cmdbufr, buf, datalen)) {
+		retn = -EFAULT;
+		goto done;
+	}
+
+	p = strchr(cmdbufr, '\n');
+	if (!p)
+		goto done;
+	*p = '\0';
+
+	arg = strchr(cmdbufr, ' ');
+	if (arg != NULL) {
+		*arg = '\0';
+		++arg;
+	}
+
+	type = match_string(control_commands, ARRAY_SIZE(control_commands),
+			    cmdbufr);
+	if (type < 0)
+		goto done;
+
+	switch (type) {
+	case TSEM_CONTROL_EXTERNAL:
+	case TSEM_CONTROL_INTERNAL:
+		retn = config_namespace(type, arg);
+		break;
+	case TSEM_CONTROL_ENFORCE:
+	case TSEM_CONTROL_SEAL:
+		retn = config_context(type, cmdbufr);
+		break;
+	case TSEM_CONTROL_TRUSTED:
+	case TSEM_CONTROL_UNTRUSTED:
+		retn = config_COE(type, arg);
+		break;
+	case TSEM_CONTROL_MAP_STATE:
+	case TSEM_CONTROL_MAP_PSEUDONYM:
+	case TSEM_CONTROL_MAP_BASE:
+		retn = config_point(type, arg);
+		break;
+	}
+
+done:
+	if (!retn)
+		retn = datalen;
+	return retn;
+}
+
+static int release_control(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static const struct file_operations control_ops = {
+	.open = open_control,
+	.write = write_control,
+	.release = release_control,
+	.llseek = generic_file_llseek,
+};
+
+static void *forensics_start(struct seq_file *c, loff_t *pos)
+{
+	struct list_head *end;
+	struct tsem_model *model = tsem_model(current);
+
+	spin_lock(&model->forensics_lock);
+	end = model->forensics_list.prev;
+	spin_unlock(&model->forensics_lock);
+
+	mutex_lock(&model->forensics_end_mutex);
+	model->forensics_end = end;
+
+	return seq_list_start(&model->forensics_list, *pos);
+}
+
+static void *forensics_next(struct seq_file *c, void *p, loff_t *pos)
+{
+	struct list_head *next = ((struct list_head *) p)->next;
+	struct tsem_model *model = tsem_model(current);
+
+	if (!model->forensics_end) {
+		++*pos;
+		return NULL;
+	}
+
+	if (next == model->forensics_end)
+		model->forensics_end = NULL;
+
+	return seq_list_next(p, &model->forensics_list, pos);
+}
+
+static void forensics_stop(struct seq_file *c, void *pos)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	mutex_unlock(&model->forensics_end_mutex);
+}
+
+static int forensics_show(struct seq_file *c, void *event)
+{
+	struct tsem_event *ep;
+
+	ep = list_entry(event, struct tsem_event, list);
+
+	seq_putc(c, '{');
+	tsem_fs_show_trajectory(c, ep);
+	seq_puts(c, "}\n");
+
+	return 0;
+}
+
+static const struct seq_operations forensics_seqops = {
+	.start = forensics_start,
+	.next = forensics_next,
+	.stop = forensics_stop,
+	.show = forensics_show
+};
+
+static int forensics_open(struct inode *inode, struct file *file)
+{
+	if (!can_access_fs())
+		return -EACCES;
+	return seq_open(file, &forensics_seqops);
+}
+
+static const struct file_operations forensics_ops = {
+	.open = forensics_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static void *forensics_point_start(struct seq_file *c, loff_t *pos)
+{
+	struct list_head *end;
+	struct tsem_model *model = tsem_model(current);
+
+	spin_lock(&model->point_lock);
+	end = model->point_list.prev;
+	spin_unlock(&model->point_lock);
+
+	mutex_lock(&model->point_end_mutex);
+	model->point_end = end;
+
+	return seq_list_start(&model->point_list, *pos);
+}
+
+static void *forensics_point_next(struct seq_file *c, void *p, loff_t *pos)
+{
+	struct list_head *next = ((struct list_head *) p)->next;
+	struct tsem_model *model = tsem_model(current);
+
+	if (!model->point_end) {
+		++*pos;
+		return NULL;
+	}
+
+	if (next == model->point_end)
+		model->point_end = NULL;
+
+	return seq_list_next(p, &model->point_list, pos);
+}
+
+static void forensics_point_stop(struct seq_file *c, void *pos)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	mutex_unlock(&model->point_end_mutex);
+}
+
+static int forensics_point_show(struct seq_file *c, void *point)
+{
+	struct tsem_event_point *pt;
+
+	pt = list_entry(point, struct tsem_event_point, list);
+	if (pt->valid)
+		return 0;
+
+	seq_printf(c, "%*phN\n", tsem_digestsize(), pt->point);
+	return 0;
+}
+
+static const struct seq_operations forensics_point_seqops = {
+	.start = forensics_point_start,
+	.next = forensics_point_next,
+	.stop = forensics_point_stop,
+	.show = forensics_point_show
+};
+
+static int forensics_point_open(struct inode *inode, struct file *file)
+{
+	if (!can_access_fs())
+		return -EACCES;
+	return seq_open(file, &forensics_point_seqops);
+}
+
+static const struct file_operations forensics_point_ops = {
+	.open = forensics_point_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static void *forensics_count_start(struct seq_file *c, loff_t *pos)
+{
+	struct list_head *end;
+	struct tsem_model *model = tsem_model(current);
+
+	spin_lock(&model->point_lock);
+	end = model->point_list.prev;
+	spin_unlock(&model->point_lock);
+
+	mutex_lock(&model->point_end_mutex);
+	model->point_end = end;
+
+	return seq_list_start(&model->point_list, *pos);
+}
+
+static void *forensics_count_next(struct seq_file *c, void *p, loff_t *pos)
+{
+	struct list_head *next = ((struct list_head *) p)->next;
+	struct tsem_model *model = tsem_model(current);
+
+	if (!model->point_end) {
+		++*pos;
+		return NULL;
+	}
+
+	if (next == model->point_end)
+		model->point_end = NULL;
+
+	return seq_list_next(p, &model->point_list, pos);
+}
+
+static void forensics_count_stop(struct seq_file *c, void *pos)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	mutex_unlock(&model->point_end_mutex);
+}
+
+static int forensics_count_show(struct seq_file *c, void *point)
+{
+	struct tsem_event_point *pt;
+
+	pt = list_entry(point, struct tsem_event_point, list);
+	if (pt->valid)
+		return 0;
+
+	seq_printf(c, "%llu\n", pt->count);
+	return 0;
+}
+
+static const struct seq_operations forensics_count_seqops = {
+	.start = forensics_count_start,
+	.next = forensics_count_next,
+	.stop = forensics_count_stop,
+	.show = forensics_count_show
+};
+
+static int forensics_count_open(struct inode *inode, struct file *file)
+{
+	if (!can_access_fs())
+		return -EACCES;
+	return seq_open(file, &forensics_count_seqops);
+}
+
+static const struct file_operations forensics_count_ops = {
+	.open = forensics_count_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static int measurement_show(struct seq_file *c, void *event)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	seq_printf(c, "%*phN\n", tsem_digestsize(), model->measurement);
+	return 0;
+}
+
+static int measurement_open(struct inode *inode, struct file *file)
+{
+	if (!can_access_fs())
+		return -EACCES;
+	return single_open(file, &measurement_show, NULL);
+}
+
+static const struct file_operations measurement_ops = {
+	.open = measurement_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static int id_show(struct seq_file *c, void *event)
+{
+	seq_printf(c, "%llu\n", tsem_context(current)->id);
+	return 0;
+}
+
+static int id_open(struct inode *inode, struct file *file)
+{
+	struct tsem_context *ctx = tsem_context(current);
+
+	if (ctx->sealed)
+		return -EACCES;
+	return single_open(file, &id_show, NULL);
+}
+
+static const struct file_operations id_ops = {
+	.open = id_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static int state_show(struct seq_file *m, void *v)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	tsem_model_compute_state();
+	seq_printf(m, "%*phN\n", tsem_digestsize(), model->state);
+	return 0;
+}
+
+static int state_open(struct inode *inode, struct file *file)
+{
+	if (!can_access_fs())
+		return -EACCES;
+	return single_open(file, &state_show, NULL);
+}
+
+static const struct file_operations state_ops = {
+	.open = state_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static int aggregate_show(struct seq_file *m, void *v)
+{
+	seq_printf(m, "%*phN\n", tsem_digestsize(), tsem_trust_aggregate());
+	return 0;
+}
+
+static int aggregate_open(struct inode *inode, struct file *file)
+{
+	if (!can_access_fs())
+		return -EACCES;
+	return single_open(file, &aggregate_show, NULL);
+}
+
+static const struct file_operations aggregate_ops = {
+	.open = aggregate_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+static __poll_t export_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct tsem_context *ctx = tsem_context(current);
+
+	if (!ctx->external)
+		return -ENOENT;
+
+	poll_wait(file, &ctx->external->wq, wait);
+
+	if (ctx->external->have_event) {
+		ctx->external->have_event = false;
+		return EPOLLIN | EPOLLRDNORM;
+	}
+	return 0;
+}
+
+static int export_open(struct inode *inode, struct file *file)
+{
+	if (!capable(TSEM_CONTROL_CAPABILITY))
+		return -EACCES;
+	return single_open(file, &tsem_export_show, NULL);
+}
+
+static const struct file_operations export_ops = {
+	.open = export_open,
+	.poll = export_poll,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+};
+
+/**
+ * tsem_fs_create_external() - Create an external TMA update file.
+ * @id: A pointer to the ASCII representation of the modeling domain
+ *      that the export file is being created for.
+ *
+ * This function is used to create a pseudo-file that will output security
+ * event descriptions for a namespace.  This routine will create the
+ * following file:
+ *
+ * /sys/kernel/security/tsem/ExternalTMA/N
+ *
+ * Where N is replaced with the security model context identifier.
+ *
+ * Return: If creation of the update file is successful a pointer to the
+ *	   dentry of the file is returned.  If an error was encountered
+ *	   the pointer with an encoded code will be returned.
+ */
+struct dentry *tsem_fs_create_external(const char *name)
+{
+
+	return securityfs_create_file(name, 0400, external_tma, NULL,
+				      &export_ops);
+}
+
+/**
+ * tsem_fs_show_trajectory() - Generate the output of a security event.
+ * @sf: A pointer to the seq_file structure to which output will
+ *      be set.
+ * @ep: A pointer to the event description that is to be output.
+ *
+ * This function is used to generate a record that will be output to
+ * the pseudo-file that outputs the security events for the
+ * domain being modeled.
+ */
+void tsem_fs_show_trajectory(struct seq_file *c, struct tsem_event *ep)
+{
+	switch (ep->event) {
+	case TSEM_FILE_OPEN:
+		show_event(c, ep);
+		show_file(c, ep);
+		break;
+	case TSEM_MMAP_FILE:
+		show_mmap(c, ep);
+		break;
+	case TSEM_SOCKET_CREATE:
+		show_socket_create(c, ep);
+		break;
+	case TSEM_SOCKET_CONNECT:
+	case TSEM_SOCKET_BIND:
+		show_socket(c, ep);
+		break;
+	case TSEM_SOCKET_ACCEPT:
+		show_socket_accept(c, ep);
+		break;
+	case TSEM_TASK_KILL:
+		show_task_kill(c, ep);
+		break;
+	case TSEM_GENERIC_EVENT:
+		show_event_generic(c, ep);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * tesm_fs_show_field() - Output a JSON field description
+ * @sf: A pointer to the seq_file structure that the field description
+ *	is to be written to.
+ * @f:  A pointer to null terminated character buffer containing the
+ *      name of the field to encode
+ *
+ * This function is used to generate a JSON field description that
+ * is used to name a sequence of key/value pairs describing the
+ * characteristcis of the field.
+ */
+void tsem_fs_show_field(struct seq_file *c, const char *field)
+{
+	seq_printf(c, "\"%s\": {", field);
+}
+
+/**
+ * tesm_fs_tsem_fs_show_key() - Output a JSON key/value pair
+ * @sf: A pointer to the seq_file structure that the field description
+ *	is to be written to.
+ * @term: A pointer to a null-terminated character buffer containing
+ *	  the string that is to be used for terminating the key/value
+ *	  pair.
+ * @key: A pointer to the null-terminated character buffer containing
+ *	 the key description.
+ * @fmt: The printf format that is to be used for formatting the
+ *	 value of the key.
+ *
+ * This function is a variadic function that is used to encode a
+ * JSON key/value pair that provides one of characteristics of an
+ * event description field.
+ */
+void tsem_fs_show_key(struct seq_file *c, char *term, char *key,
+		      char *fmt, ...)
+{
+	va_list args;
+
+	seq_printf(c, "\"%s\": \"", key);
+
+	va_start(args, fmt);
+	seq_vprintf(c, fmt, args);
+	va_end(args);
+
+	if (term[0] == ',')
+		seq_printf(c, "\"%s ", term);
+	else
+		seq_printf(c, "\"%s", term);
+}
+
+/**
+ * tesm_fs_init() - Initialize the TSEM control filesystem heirarchy
+ *
+ * This function is called as part of the TSEM LSM initialization
+ * process.  The purpose of this function is to create the TSEM
+ * control plane, based on the securityfs filesystem, by creating the
+ * /sys/kernel/security/tsem directory and populating that directory
+ * with the control plane files and internal TMA model information
+ * files.  The /sys/kernel/security/tsem/ExternalTMA directory is
+ * also created.  This directory will be used to hold the modeling
+ * domain specific files that will emit the security event descriptions
+ * for the domain.
+ *
+ * Return: If filesystem initialization is successful a return code of 0
+ *	   is returned.  A negative return value is returned if an error
+ *	   is encountered.
+ */
+int __init tsem_fs_init(void)
+{
+	int retn = -1;
+
+	tsem_dir = securityfs_create_dir("tsem", NULL);
+	if (tsem_dir == NULL)
+		goto done;
+
+	control = securityfs_create_file("control", 0200, tsem_dir, NULL,
+					 &control_ops);
+	if (IS_ERR(control))
+		goto err;
+
+	id = securityfs_create_file("id", 0400, tsem_dir, NULL, &id_ops);
+	if (IS_ERR(control))
+		goto err;
+
+	aggregate = securityfs_create_file("aggregate", 0400, tsem_dir, NULL,
+					   &aggregate_ops);
+	if (IS_ERR(aggregate))
+		goto err;
+
+	internal_tma = securityfs_create_dir("InternalTMA", tsem_dir);
+	if (IS_ERR(internal_tma))
+		goto err;
+
+	model = securityfs_create_dir("model0", internal_tma);
+	if (IS_ERR(model))
+		goto err;
+
+	forensics = securityfs_create_file("forensics", 0400, model, NULL,
+					   &forensics_ops);
+	if (IS_ERR(forensics))
+		goto err;
+
+	forensics_counts = securityfs_create_file("forensics_counts", 0400,
+						 model, NULL,
+						 &forensics_count_ops);
+	if (IS_ERR(forensics_counts))
+		goto err;
+
+	forensics_coeff = securityfs_create_file("forensics_coefficients",
+						 0400, model, NULL,
+						 &forensics_point_ops);
+	if (IS_ERR(forensics_coeff))
+		goto err;
+
+	trajectory = securityfs_create_file("trajectory", 0400, model, NULL,
+					     &trajectory_ops);
+	if (IS_ERR(trajectory))
+		goto err;
+
+	trajectory_counts = securityfs_create_file("trajectory_counts", 0400,
+						   model, NULL,
+						   &trajectory_count_ops);
+	if (IS_ERR(trajectory_counts))
+		goto err;
+
+	trajectory_coeff = securityfs_create_file("trajectory_coefficients",
+						  0400, model, NULL,
+						  &trajectory_point_ops);
+	if (IS_ERR(trajectory_coeff))
+		goto err;
+
+	measurement = securityfs_create_file("measurement", 0400,
+						  model, NULL,
+						  &measurement_ops);
+	if (IS_ERR(measurement))
+		goto err;
+
+	state = securityfs_create_file("state", 0400, model, NULL,
+					&state_ops);
+	if (IS_ERR(state))
+		goto err;
+
+	external_tma = securityfs_create_dir("ExternalTMA", tsem_dir);
+	if (IS_ERR(external_tma))
+		goto err;
+
+	retn = 0;
+
+ done:
+	return retn;
+
+ err:
+	securityfs_remove(tsem_dir);
+	securityfs_remove(control);
+	securityfs_remove(id);
+	securityfs_remove(aggregate);
+	securityfs_remove(internal_tma);
+	securityfs_remove(model);
+	securityfs_remove(forensics);
+	securityfs_remove(forensics_counts);
+	securityfs_remove(forensics_coeff);
+	securityfs_remove(trajectory);
+	securityfs_remove(trajectory_counts);
+	securityfs_remove(trajectory_coeff);
+	securityfs_remove(measurement);
+	securityfs_remove(state);
+	securityfs_remove(external_tma);
+
+	return retn;
+}
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 08/13] Add namespace implementation.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (6 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 07/13] Implement TSEM control plane Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-07-10 10:23 ` [PATCH 09/13] Add security event description export facility Dr. Greg
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

TSEM implements a security modeling namespace that allows
security models to be implemented that are independent of other
security modeling namespaces.  This allows multiple security
models and modes of modeling (external vs. internal) to be
implemented.  A security modeling namespace is conceptually
similar to other resource namespaces implemented in the kernel

The TSEM control plane is used to cause a process to leave the
root security modeling namespace and institute a new subordinate
modeling namespace.  Additional processes that fork from this
process inherit the the characteristics of the security modeling
namespace.

Each modeling namespace has a unique numeric identifier that is
implemented as an incremented unsigned 64 bit value in order to
preclude overflow.  The id value of 0 is reserved for the root
security modeling namespace.

Each security modeling namespace is designated as either
internally or externally modeled.  An internally modeled namespace
has its security model implemented by a Trusted Modeling Agent
(TMA) implementation that is run in the context of the kernel.

Externally modeled namespaces have a description of the security
event exported to a trust orchestrator running in userspace.
That trust orchestrator has an associated Trusted Modeling Agent
running in a context that implements the root of trust for the
security namespace.

A process that exports a security event description is scheduled
away into an interruptible sleep state.  The trust orchestrator
that created the external modeling namespace is responsible for
using the TSEM control plane to wake the process up and set the
trust status of the process to be trusted or untrusted.  Only
processes that carries the CAP_ML capability can wake up a
process and set its trust status.

An init function is surfaced from this file that is called by the
TSEM initialization function.  This function is responsible for
creating a workqueue that will handle asynchronous release of
resources that were allocated for a modeling domain, including
the release of the pseudo-file that was created for exporting
domain events.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/namespace.c | 347 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 347 insertions(+)
 create mode 100644 security/tsem/namespace.c

diff --git a/security/tsem/namespace.c b/security/tsem/namespace.c
new file mode 100644
index 000000000000..ba2e8f550838
--- /dev/null
+++ b/security/tsem/namespace.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * This file implements TSEM namespaces.
+ */
+
+#include "tsem.h"
+
+static u64 context_id;
+
+struct context_key {
+	struct list_head list;
+	u64 context_id;
+	u8 key[HASH_MAX_DIGESTSIZE];
+};
+
+DEFINE_MUTEX(context_id_mutex);
+LIST_HEAD(context_id_list);
+
+static void remove_task_key(u64 context_id)
+{
+	struct context_key *entry, *tmp_entry;
+
+	list_for_each_entry_safe(entry, tmp_entry, &context_id_list, list) {
+		if (context_id == entry->context_id) {
+			list_del(&entry->list);
+			kfree(entry);
+			break;
+		}
+	}
+}
+
+static int generate_task_key(const char *keystr, u64 context_id,
+			     struct tsem_task *t_ttask,
+			     struct tsem_task *p_ttask)
+{
+	int retn;
+	bool found_key, valid_key = false;
+	unsigned int size = tsem_digestsize();
+	struct context_key *entry;
+
+	while (!valid_key) {
+		get_random_bytes(t_ttask->task_key, size);
+		retn = tsem_ns_event_key(t_ttask->task_key, keystr,
+					 p_ttask->task_key);
+		if (retn)
+			goto done;
+
+		if (list_empty(&context_id_list))
+			break;
+
+		found_key = false;
+		list_for_each_entry(entry, &context_id_list, list) {
+			if (memcmp(entry->key, p_ttask->task_key, size) == 0)
+				found_key = true;
+		}
+		if (!found_key)
+			valid_key = true;
+	}
+
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry) {
+		retn = -ENOMEM;
+		goto done;
+	}
+
+	entry->context_id = context_id;
+	memcpy(entry->key, p_ttask->task_key, size);
+	list_add_tail(&entry->list, &context_id_list);
+	retn = 0;
+
+ done:
+	return retn;
+}
+
+static struct tsem_external *allocate_external(u64 context_id,
+					       const char *keystr)
+{
+	int retn = -ENOMEM;
+	char bufr[20 + 1];
+	struct tsem_external *external;
+	struct tsem_task *t_ttask = tsem_task(current);
+	struct tsem_task *p_ttask = tsem_task(current->real_parent);
+
+	external = kzalloc(sizeof(*external), GFP_KERNEL);
+	if (!external)
+		goto done;
+
+	retn = generate_task_key(keystr, context_id, t_ttask, p_ttask);
+	if (retn)
+		goto done;
+
+	spin_lock_init(&external->export_lock);
+	INIT_LIST_HEAD(&external->export_list);
+
+	init_waitqueue_head(&external->wq);
+
+	scnprintf(bufr, sizeof(bufr), "%llu", context_id);
+	external->dentry = tsem_fs_create_external(bufr);
+	if (IS_ERR(external->dentry)) {
+		retn = PTR_ERR(external->dentry);
+		external->dentry = NULL;
+	} else
+		retn = 0;
+
+ done:
+	if (retn) {
+		memset(t_ttask->task_key, '\0', tsem_digestsize());
+		memset(p_ttask->task_key, '\0', tsem_digestsize());
+		kfree(external);
+		remove_task_key(context_id);
+		external = ERR_PTR(retn);
+	} else
+		p_ttask->tma_for_ns = context_id;
+
+	return external;
+}
+
+static void wq_put(struct work_struct *work)
+{
+	struct tsem_context *ctx;
+
+	ctx = container_of(work, struct tsem_context, work);
+
+	if (ctx->external) {
+		mutex_lock(&context_id_mutex);
+		remove_task_key(ctx->id);
+		mutex_unlock(&context_id_mutex);
+
+		securityfs_remove(ctx->external->dentry);
+		tsem_export_magazine_free(ctx->external);
+		kfree(ctx->external);
+	} else
+		tsem_model_free(ctx);
+
+	crypto_free_shash(ctx->tfm);
+	tsem_event_magazine_free(ctx);
+	kfree(ctx->digestname);
+	kfree(ctx);
+}
+
+static void ns_free(struct kref *kref)
+{
+	struct tsem_context *ctx;
+
+	ctx = container_of(kref, struct tsem_context, kref);
+
+	INIT_WORK(&ctx->work, wq_put);
+	if (!queue_work(system_wq, &ctx->work))
+		WARN_ON_ONCE(1);
+}
+
+/**
+ * tsem_ns_put() - Release a reference to a modeling context.
+ * @ctx: A pointer to the TMA context for which a reference is
+ *	 to be released.
+ *
+ * This function is called to release a reference to a TMA modeling
+ * domain.  The release of the last reference calls the ns_free()
+ * function that schedules the actual work to release the resources
+ * associated with the namespace to a workqueue.
+ */
+void tsem_ns_put(struct tsem_context *ctx)
+{
+	kref_put(&ctx->kref, ns_free);
+}
+
+/**
+ * tsem_ns_event_key() - Generate TMA authentication key.
+ * @task_key: A pointer to the buffer containing the task identification
+ *	      key that was randomly generated for the modeling domain.
+ * @keystr: A pointer to the buffer containing the TMA authentication key
+ *	    in ASCII hexadecimal form.
+ *
+ * This function generates the authentication key that will be used
+ * to validate a call by a TMA to set the trust status of the process.
+ *
+ * Return: This function returns 0 if the key was properly generated
+ *	   or a negative value if a hashing error occurred.
+ */
+int tsem_ns_event_key(u8 *task_key, const char *keystr, u8 *key)
+{
+	bool retn;
+	u8 tma_key[HASH_MAX_DIGESTSIZE];
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	retn = hex2bin(tma_key, keystr, tsem_digestsize());
+	if (retn)
+		return -EINVAL;
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		return retn;
+
+	retn = crypto_shash_update(shash, task_key, tsem_digestsize());
+	if (retn)
+		return retn;
+
+	return crypto_shash_finup(shash, tma_key, tsem_digestsize(), key);
+}
+
+static struct crypto_shash *configure_digest(const char *digest,
+					     char **digestname,
+					     u8 *zero_digest)
+{
+	int retn;
+	struct crypto_shash *tfm;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	*digestname = kstrdup(digest, GFP_KERNEL);
+	if (!*digestname)
+		return ERR_PTR(-ENOMEM);
+
+	tfm = crypto_alloc_shash(digest, 0, 0);
+	if (IS_ERR(tfm))
+		return tfm;
+
+	shash->tfm = tfm;
+	retn = crypto_shash_digest(shash, NULL, 0, zero_digest);
+	if (retn) {
+		crypto_free_shash(tfm);
+		tfm = NULL;
+	}
+
+	return tfm;
+}
+
+/**
+ * tsem_ns_create() - Create a TSEM modeling namespace.
+ * @type:   The type of namespace being created.
+ * @digest: A null terminated character buffer containing the name
+ *	    of the hash function that is to be used for the modeling
+ *	    domain.
+ * @ns:     The enumeration type that specifies whether the security
+ *	    event descriptions should reference the initial user
+ *	    namespace or the current user namespace.
+ * @key:    A pointer to a null-terminated buffer containing the key
+ *	    that will be used to authenticate the TMA's ability to set
+ *	    the trust status of a process.
+ *
+ * This function is used to create either an internally or externally
+ * modeled TSEM namespace.  The type of the namespace to be created
+ * is specified with the tsem_control_type enumeration value.  A
+ * request for an internally model namespace causes a new structure to be
+ * allocated that will hold the description of the security model.
+ * An externally modeled domain will have a control structure allocated
+ * that manages the export of security event descriptions to the
+ * trust orchestrator that is responsible for running the TMA
+ * implementation.
+ *
+ * Return: This function returns 0 if the namespace was created and
+ *	   a negative error value on error.
+ */
+int tsem_ns_create(const enum tsem_control_type type, const char *digest,
+		   const enum tsem_ns_reference ns, const char *key,
+		   unsigned int cache_size)
+{
+	u8 zero_digest[HASH_MAX_DIGESTSIZE];
+	char *use_digest;
+	int retn = -ENOMEM;
+	u64 new_id;
+	struct tsem_task *tsk = tsem_task(current);
+	struct tsem_context *new_ctx;
+	struct tsem_model *model = NULL;
+	struct crypto_shash *tfm;
+
+	tfm = configure_digest(digest, &use_digest, zero_digest);
+	if (IS_ERR(tfm))
+		return PTR_ERR(tfm);
+
+	new_ctx = kzalloc(sizeof(*new_ctx), GFP_KERNEL);
+	if (!new_ctx)
+		return retn;
+
+	mutex_lock(&context_id_mutex);
+	new_id = context_id + 1;
+
+	retn = tsem_event_magazine_allocate(new_ctx, cache_size);
+	if (retn)
+		goto done;
+
+	if (type == TSEM_CONTROL_INTERNAL) {
+		model = tsem_model_allocate(cache_size);
+		if (!model)
+			goto done;
+		new_ctx->model = model;
+	}
+	if (type == TSEM_CONTROL_EXTERNAL) {
+		if (crypto_shash_digestsize(tfm)*2 != strlen(key)) {
+			retn = -EINVAL;
+			goto done;
+		}
+
+		new_ctx->external = allocate_external(new_id, key);
+		if (IS_ERR(new_ctx->external)) {
+			retn = PTR_ERR(new_ctx->external);
+			new_ctx->external = NULL;
+			goto done;
+		}
+
+		retn = tsem_export_magazine_allocate(new_ctx->external,
+						     cache_size);
+		if (retn)
+			goto done;
+	}
+
+	kref_init(&new_ctx->kref);
+
+	new_ctx->id = new_id;
+	new_ctx->tfm = tfm;
+	new_ctx->digestname = use_digest;
+	memcpy(new_ctx->zero_digest, zero_digest,
+	       crypto_shash_digestsize(tfm));
+
+	if (ns == TSEM_NS_CURRENT)
+		new_ctx->use_current_ns = true;
+	memcpy(new_ctx->actions, tsk->context->actions,
+	       sizeof(new_ctx->actions));
+	retn = 0;
+
+ done:
+	if (retn) {
+		remove_task_key(new_id);
+		crypto_free_shash(tfm);
+		tsem_event_magazine_free(new_ctx);
+		kfree(use_digest);
+		if (new_ctx->external)
+			tsem_export_magazine_free(new_ctx->external);
+		kfree(new_ctx->external);
+		kfree(new_ctx);
+		kfree(model);
+	} else {
+		context_id = new_id;
+		tsk->context = new_ctx;
+		if (type == TSEM_CONTROL_EXTERNAL)
+			retn = tsem_export_aggregate();
+		else
+			retn = tsem_model_add_aggregate();
+	}
+
+	mutex_unlock(&context_id_mutex);
+	return retn;
+}
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 09/13] Add security event description export facility.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (7 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 08/13] Add namespace implementation Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-07-10 10:23 ` [PATCH 10/13] Add event description implementation Dr. Greg
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

This file contains functionality for surfacing security modeling
events to an a trust orchestrator that is implementing a Trusted
Modeling Agent for a security modeling namespace.

ASCII descriptions of the events are presented to a userspace
trust orchestrator through the following pseudo-files:

/sys/kernel/security/tsem/ExternalTMA/N

Where N is replaced with security modeling namespace identifier.
This will be an integer value greater than zero.

The following event types are exported:

AGGREGATE_EVENT

EXPORT_EVENT

LOG_EVENT

The AGGREGATE_EVENT is used to inject the hardware platform
aggregate that was computed over TPM Platform Configuration
Registers 0 through 7 at the time the LSM was initialized.  In
TSEM modeling this is the first security state coefficient
committed to a model.

An EXPORT_EVENT is used to surface the description of either an
explicitly or generically modeled security state event for
injection into a security model run by an external orchestrator
and its associated Trusted Modeling Agent (TMA).

A LOG_EVENT is used to export descriptions of security events
that are invoked by untrusted processes.

The modeling and logging by external orchestrators allow the
implementation of out-of-band notifications of security forensics
events that occur.

The /sys/kernel/security/tsem/ExternalTMA/N pseudo-files
implement a pollable interface that the trust orchestrators can
use to wait on events.  After placing the event description into
the device queue the process is placed in an interruptible sleep
state.

After the TMA completes modeling of the event, the trust
orchestrator is responsible for using the TSEM control plane to
set the status of a process to either trusted or untrusted with
release of the process to continue execution.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/export.c | 394 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 394 insertions(+)
 create mode 100644 security/tsem/export.c

diff --git a/security/tsem/export.c b/security/tsem/export.c
new file mode 100644
index 000000000000..d554c2598be7
--- /dev/null
+++ b/security/tsem/export.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * Implements updates to an external modeling engine.
+ */
+
+#include <linux/seq_file.h>
+
+#include "tsem.h"
+
+enum export_type {
+	AGGREGATE_EVENT = 1,
+	EXPORT_EVENT,
+	EXPORT_ASYNC_EVENT,
+	LOG_EVENT
+};
+
+struct action_description {
+	enum export_type type;
+	enum tsem_action_type action;
+	char comm[TASK_COMM_LEN];
+};
+
+struct export_event {
+	struct list_head list;
+	enum export_type type;
+	union {
+		u8 *aggregate[HASH_MAX_DIGESTSIZE];
+		struct tsem_event *ep;
+		struct action_description action;
+	} u;
+};
+
+static const char * const tsem_actions[TSEM_ACTION_CNT] = {
+	"LOG",
+	"DENY"
+};
+
+static struct kmem_cache *export_cachep;
+
+static void refill_export_magazine(struct work_struct *work)
+{
+	struct export_event *exp;
+	struct tsem_external *ext;
+	struct tsem_work *ws;
+
+	ws = container_of(work, struct tsem_work, work);
+	ext = ws->u.ext;
+
+	exp = kmem_cache_zalloc(export_cachep, GFP_KERNEL);
+	if (!exp) {
+		pr_warn("tsem: Cannot refill event magazine.\n");
+		return;
+	}
+
+	spin_lock(&ws->u.ext->magazine_lock);
+	ws->u.ext->magazine[ws->index] = exp;
+	clear_bit(ws->index, ws->u.ext->magazine_index);
+
+	/*
+	 * The following memory barrier is used to cause the magazine
+	 * index to be visible after the refill of the cache slot.
+	 */
+	smp_mb__after_atomic();
+	spin_unlock(&ws->u.ext->magazine_lock);
+}
+
+static struct export_event *allocate_export(bool locked)
+{
+	unsigned int index;
+	struct export_event *exp = NULL;
+	struct tsem_external *ext = tsem_context(current)->external;
+
+	if (!locked)
+		return kmem_cache_zalloc(export_cachep, GFP_KERNEL);
+
+	spin_lock(&ext->magazine_lock);
+	index = find_first_zero_bit(ext->magazine_index, ext->magazine_size);
+	if (index < ext->magazine_size) {
+		exp = ext->magazine[index];
+		ext->ws[index].index = index;
+		ext->ws[index].u.ext = ext;
+		set_bit(index, ext->magazine_index);
+
+		/*
+		 * Similar to the issue noted in the refill_event_magazine()
+		 * function, this barrier is used to cause the consumption
+		 * of the cache entry to become visible.
+
+		 */
+		smp_mb__after_atomic();
+	}
+
+	spin_unlock(&ext->magazine_lock);
+
+	if (exp) {
+		INIT_WORK(&ext->ws[index].work, refill_export_magazine);
+		queue_work(system_wq, &ext->ws[index].work);
+		return exp;
+	}
+
+	pr_warn("tsem: %s in %llu failed export allocation, cache size=%u.\n",
+		current->comm, tsem_context(current)->id, ext->magazine_size);
+	return NULL;
+}
+
+static void trigger_event(struct tsem_context *ctx)
+{
+	ctx->external->have_event = true;
+	wake_up_interruptible(&ctx->external->wq);
+}
+
+int tsem_export_show(struct seq_file *sf, void *v)
+{
+	bool locked = false;
+	struct export_event *exp = NULL;
+	struct tsem_context *ctx = tsem_context(current);
+
+	if (!ctx->id)
+		return -ENODATA;
+
+	spin_lock(&ctx->external->export_lock);
+	if (!list_empty(&ctx->external->export_list)) {
+		exp = list_first_entry(&ctx->external->export_list,
+				       struct export_event, list);
+		list_del(&exp->list);
+	}
+	spin_unlock(&ctx->external->export_lock);
+
+	if (!exp)
+		return -ENODATA;
+
+	seq_putc(sf, '{');
+	tsem_fs_show_field(sf, "export");
+
+	switch (exp->type) {
+	case AGGREGATE_EVENT:
+		tsem_fs_show_key(sf, "}, ", "type", "%s", "aggregate");
+		tsem_fs_show_field(sf, "aggregate");
+		tsem_fs_show_key(sf, "}", "value", "%*phN", tsem_digestsize(),
+				 exp->u.aggregate);
+		break;
+
+	case EXPORT_EVENT:
+		tsem_fs_show_key(sf, "}, ", "type", "%s", "event");
+		tsem_fs_show_trajectory(sf, exp->u.ep);
+		locked = exp->u.ep->locked;
+		tsem_event_put(exp->u.ep);
+		break;
+
+	case EXPORT_ASYNC_EVENT:
+		tsem_fs_show_key(sf, "}, ", "type", "%s", "async_event");
+		tsem_fs_show_trajectory(sf, exp->u.ep);
+		locked = exp->u.ep->locked;
+		tsem_event_put(exp->u.ep);
+		break;
+
+	case LOG_EVENT:
+		tsem_fs_show_key(sf, "}, ", "type", "%s", "log");
+		tsem_fs_show_field(sf, "log");
+		tsem_fs_show_key(sf, ",", "process", "%s", exp->u.action.comm);
+		tsem_fs_show_key(sf, ",", "event", "%s",
+				 tsem_names[exp->u.action.type]);
+		tsem_fs_show_key(sf, "}", "action", "%s",
+				 tsem_actions[exp->u.action.action]);
+		break;
+	}
+	seq_puts(sf, "}\n");
+
+	kmem_cache_free(export_cachep, exp);
+	return 0;
+}
+
+/**
+ * tsem_export_event() - Export a security event description.
+ * @event: The TSEM event type number for which the log event is being
+ *	   generated.
+ *
+ * This function queues for export to an external modeling agent a
+ * security event description.
+ *
+ * Return: This function returns 0 if the export was successful or
+ *	   an error value if it was not.
+ */
+int tsem_export_event(struct tsem_event *ep)
+{
+	int retn = 0;
+	struct tsem_task *task = tsem_task(current);
+	struct tsem_context *ctx = task->context;
+	struct export_event *exp;
+
+	exp = allocate_export(ep->locked);
+	if (!exp) {
+		pr_warn("tsem: domain %llu failed export allocation.\n",
+			ctx->id);
+		return -ENOMEM;
+	}
+
+	exp->type = ep->locked ? EXPORT_ASYNC_EVENT : EXPORT_EVENT;
+	exp->u.ep = ep;
+	tsem_event_get(ep);
+
+	spin_lock(&ctx->external->export_lock);
+	list_add_tail(&exp->list, &ctx->external->export_list);
+	spin_unlock(&ctx->external->export_lock);
+
+	if (ep->locked) {
+		trigger_event(ctx);
+		return 0;
+	}
+
+	task->trust_status |= TSEM_TASK_TRUST_PENDING;
+	trigger_event(ctx);
+
+	while (task->trust_status & TSEM_TASK_TRUST_PENDING) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+		if (signal_pending(current)) {
+			if (sigismember(&current->pending.signal, SIGKILL) ||
+			    sigismember(&current->signal->shared_pending.signal,
+					SIGKILL))
+				task->trust_status = TSEM_TASK_UNTRUSTED;
+		}
+	}
+
+	return retn;
+}
+
+/**
+ * tsem_export_action() - Exports the action taken to a security violation.
+ * @event: The TSEM event type number for which the log event is being
+ *	   generated.
+ * @locked: A boolean flag indicating whether or not the security hook
+ *	    being reported on is called in atomic context.
+ *
+ * This function queues for export a description of an event that
+ * was being disciplined.
+ *
+ * Return: This function returns 0 if the export was successful or
+ *	   an error value if it was not.
+ */
+int tsem_export_action(enum tsem_event_type event, bool locked)
+{
+	struct tsem_context *ctx = tsem_context(current);
+	struct export_event *exp;
+
+	exp = allocate_export(locked);
+	if (!exp) {
+		pr_warn("tsem: domain %llu failed export allocation.\n",
+			ctx->id);
+		return -ENOMEM;
+	}
+
+	exp->type = LOG_EVENT;
+	exp->u.action.type = event;
+	exp->u.action.action = ctx->actions[event];
+	strcpy(exp->u.action.comm, current->comm);
+
+	spin_lock(&ctx->external->export_lock);
+	list_add_tail(&exp->list, &ctx->external->export_list);
+	spin_unlock(&ctx->external->export_lock);
+
+	trigger_event(ctx);
+
+	return 0;
+}
+
+/**
+ * tsem_export_aggregate() - Exports the hardware aggregate value.
+ *
+ * This function exports the hardware aggregate measurement for
+ * the platform on which the TSEM LSM is being run on.
+ *
+ * Return: This function returns a value of 0 if the export was
+ *	   successful or a non-zero return value if the export was
+ *	   not successful.
+ */
+int tsem_export_aggregate(void)
+{
+	struct tsem_context *ctx = tsem_context(current);
+	struct export_event *exp;
+
+	exp = kmem_cache_zalloc(export_cachep, GFP_KERNEL);
+	if (!exp)
+		return -ENOMEM;
+
+	exp->type = AGGREGATE_EVENT;
+	memcpy(exp->u.aggregate, tsem_trust_aggregate(), tsem_digestsize());
+
+	spin_lock(&ctx->external->export_lock);
+	list_add_tail(&exp->list, &ctx->external->export_list);
+	spin_unlock(&ctx->external->export_lock);
+
+	trigger_event(ctx);
+
+	return 0;
+}
+
+/**
+ * tsem export_magazine_allocate() - Allocate a TSEM export magazine.
+ * @ctx: A pointer to the external modeling context that the magazine is
+ *	 to be allocated for.
+ * @size: The number of entries to be created in the magazine.
+
+ * The security event export magazine is an array of export_event
+ * structures that are used to service security hooks that are called
+ * in atomic context.  Each external modeling domain has a magazine
+ * allocated to it and this function allocates and initializes the
+ * memory structures needed to manage that magazine.
+
+ * Return: This function returns a value of zero on success and a negative
+ *	   error code on failure.
+ */
+int tsem_export_magazine_allocate(struct tsem_external *ext, size_t size)
+{
+	unsigned int lp;
+	int retn = -ENOMEM;
+
+	ext->magazine_size = size;
+
+	spin_lock_init(&ext->magazine_lock);
+
+	ext->magazine_index = bitmap_zalloc(ext->magazine_size, GFP_KERNEL);
+	if (!ext->magazine_index)
+		return retn;
+
+	ext->magazine = kcalloc(ext->magazine_size, sizeof(*ext->magazine),
+				GFP_KERNEL);
+	if (!ext->magazine)
+		goto done;
+
+	for (lp = 0; lp < ext->magazine_size; ++lp) {
+		ext->magazine[lp] = kmem_cache_zalloc(export_cachep,
+						      GFP_KERNEL);
+		if (!ext->magazine[lp])
+			goto done;
+	}
+
+	ext->ws = kcalloc(ext->magazine_size, sizeof(*ext->ws), GFP_KERNEL);
+	if (ext->ws)
+		retn = 0;
+
+ done:
+	if (retn)
+		tsem_export_magazine_free(ext);
+
+	return retn;
+}
+
+/**
+ * tsem export_magazine_free() - Releases a TSEM export magazine
+ * @ctx: A pointer to the external modeling context whose magazine is
+ *	 to be released.
+ *
+ * The function is used to free the memory that was allocated by
+ * the tsem_export_magazine_allocate() function for an extenral
+ * modeling context.
+ */
+void tsem_export_magazine_free(struct tsem_external *ext)
+{
+	unsigned int lp;
+
+	for (lp = 0; lp < ext->magazine_size; ++lp)
+		kmem_cache_free(export_cachep, ext->magazine[lp]);
+
+	bitmap_free(ext->magazine_index);
+	kfree(ext->ws);
+	kfree(ext->magazine);
+}
+
+/**
+ * tsem export_cache_init() - Initialize the TSEM export cache.
+ *
+ * This function is called by the TSEM initialization function and sets
+ * up a cache for export structures that are called by security event
+ * descriptions that are generated in atomix context
+ *
+ * Return: This function returns a value of zero on success and a negative
+ *	   error code on failure.
+ */
+int __init tsem_export_cache_init(void)
+{
+
+	export_cachep = kmem_cache_create("tsem_export_cache",
+					 sizeof(struct export_event), 0,
+					 SLAB_PANIC, 0);
+	if (!export_cachep)
+		return -ENOMEM;
+
+	return 0;
+}
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 10/13] Add event description implementation.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (8 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 09/13] Add security event description export facility Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-07-10 10:23 ` [PATCH 11/13] Implement security event mapping Dr. Greg
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

The event.c file implements support for packaging the description
of an event into its Context Of Execution (COE) and CELL
identities for subsequent modeling by an internal Trusted
Modeling Agent (TMA) or export to a an external trust
orchestrator and TMA.

The tsem_event_allocate() function is called by every security
event handler that determines that an event is to be modeled,
either generically or explicitly.  For externally modeled
security modeling namespaces the event description is released
after the export of the event is completed.

For internally modeled domains the event description is retained
in order to support retention and surfacing of the security event
descriptions until the security modeling namespace is terminated.

The event description structures are allocated from a TSEM
event description cache named 'tsem_event_cache'.  This cache is
created by an initialization function exported from this file
that is called as part of the TSEM LSM initialization process.

In the case of a security event that acts on a file, ie. is
called with a 'struct file' pointer, one of the components of the
CELL value is a digest of the contents of the file.  This file
uses the integrity_kernel_read() function supplied by the
integrity infrastructure to compute the file digest value using
the cryptographic hash function that has been selected for use by
the security modeling namespace.

In a manner similar to the Integrity Measurement Architecture the
file digest processing functionality needs to temporarily alter
the file mode characteristics if the file is not readable.  The
characteristics are returned to their normal file after reading
of the digest is complete.

The TSEM LSM uses the LSM 'blob' infrastructure to allocate a
TSEM specific inode structure when an inode is allocated.  The
digest value for the value is stored in this structure in order
to eliminate subsequent re-computation of the digest value if the
file has not changed.

The inode 'iversion' value is used to detect changes to an inode
in order to trigger the re-computation of the digest value if the
file has changed.

One of the subtle issues that needs to be addressed is to handle
re-entrancy of the file_open security event hook that is caused
by the integrity_kernel_read() function opening the file.  The
TSEM specific inode structure contains a member that is used to
indicate whether or not a digest is being computed for a file.
The tsem_file_open() event handler checks for the presence of
this flag and allows permission for the open if this flag is
detected.

For IPV6 and IPV6 sockets relevant socket information is
collected to be used in the CELL computation.

For a UNIX domain socket (AF_UNIX) the digest of the pathname for
the socket is used for the CELL value.

Other socket types are generically modeled by computing the
digest of the address field supplied when the socket was created
or bound.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/event.c | 669 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 669 insertions(+)
 create mode 100644 security/tsem/event.c

diff --git a/security/tsem/event.c b/security/tsem/event.c
new file mode 100644
index 000000000000..2e01702817ca
--- /dev/null
+++ b/security/tsem/event.c
@@ -0,0 +1,669 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * This file manages the data structures used to define a security event.
+ */
+
+#include <linux/iversion.h>
+#include <linux/user_namespace.h>
+
+#include "tsem.h"
+#include "../integrity/integrity.h"
+
+static struct kmem_cache *event_cachep;
+
+static void refill_event_magazine(struct work_struct *work)
+{
+	unsigned int index;
+	struct tsem_event *ep;
+	struct tsem_work *ws;
+
+	ws = container_of(work, struct tsem_work, work);
+
+	ep = kmem_cache_zalloc(event_cachep, GFP_KERNEL);
+	if (!ep) {
+		pr_warn("tsem: Cannot refill event magazine.\n");
+		return;
+	}
+
+	spin_lock(&ws->u.ctx->magazine_lock);
+	ws->u.ctx->magazine[ws->index] = ep;
+	clear_bit(ws->index, ws->u.ctx->magazine_index);
+
+	/*
+	 * The following memory barrier is used to cause the magazine
+	 * index to be visible after the refill of the cache slot.
+	 */
+	smp_mb__after_atomic();
+	spin_unlock(&ws->u.ctx->magazine_lock);
+
+	if (index >= ws->u.ctx->magazine_size) {
+		kmem_cache_free(event_cachep, ep);
+		WARN_ONCE(true, "Refilling event magazine with no slots.\n");
+	}
+}
+
+static void get_COE(struct tsem_COE *COE)
+
+{
+	struct user_namespace *ns;
+
+	if (tsem_context(current)->use_current_ns)
+		ns = current_user_ns();
+	else
+		ns = &init_user_ns;
+
+	COE->uid = from_kuid(ns, current_uid());
+	COE->euid = from_kuid(ns, current_euid());
+	COE->suid = from_kuid(ns, current_suid());
+
+	COE->gid = from_kgid(ns, current_gid());
+	COE->egid = from_kgid(ns, current_egid());
+	COE->sgid = from_kgid(ns, current_sgid());
+
+	COE->fsuid = from_kuid(ns, current_fsuid());
+	COE->fsgid = from_kgid(ns, current_fsgid());
+
+	COE->capeff.mask = current_cred()->cap_effective;
+}
+
+static char *get_path(struct file *file)
+{
+	int retn = 0;
+	const char *pathname = NULL;
+	char *path, *pathbuffer = NULL;
+
+	pathbuffer = __getname();
+	if (pathbuffer) {
+		pathname = d_absolute_path(&file->f_path, pathbuffer,
+					   PATH_MAX);
+		if (IS_ERR(pathname)) {
+			__putname(pathbuffer);
+			pathbuffer = NULL;
+			pathname = NULL;
+		}
+	}
+
+	if (pathname)
+		path = kstrdup(pathname, GFP_KERNEL);
+	else
+		path = kstrdup(file->f_path.dentry->d_name.name, GFP_KERNEL);
+	if (!path)
+		retn = -ENOMEM;
+
+	if (pathbuffer)
+		__putname(pathbuffer);
+	if (retn)
+		path = ERR_PTR(retn);
+	return path;
+}
+
+static int add_file_name(struct tsem_event *ep)
+{
+	int retn;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	ep->file.name_length = strlen(ep->pathname);
+	retn = crypto_shash_finup(shash, ep->pathname, ep->file.name_length,
+				  ep->file.name);
+
+ done:
+	return retn;
+}
+
+static struct tsem_inode_digest *find_digest(struct tsem_inode *tsip)
+{
+	struct tsem_inode_digest *digest;
+
+	list_for_each_entry(digest, &tsip->digest_list, list) {
+		if (!strcmp(digest->name, tsem_context(current)->digestname))
+			return digest;
+	}
+
+	return NULL;
+}
+
+static struct tsem_inode_digest *add_digest(struct tsem_context *ctx,
+					    struct tsem_inode *tsip)
+{
+	struct tsem_inode_digest *digest;
+
+	digest = kzalloc(sizeof(*digest), GFP_KERNEL);
+	if (!digest)
+		return NULL;
+
+	digest->name = kstrdup(tsem_context(current)->digestname, GFP_KERNEL);
+	if (!digest->name)
+		return NULL;
+
+	list_add(&digest->list, &tsip->digest_list);
+
+	return digest;
+}
+
+static struct file *open_event_file(struct file *file, unsigned int *status)
+{
+	int flags;
+	struct file *alt_file;
+
+	if (!(file->f_mode & FMODE_CAN_READ)) {
+		file->f_mode |= FMODE_CAN_READ;
+		*status |= 4;
+	}
+	if (file->f_mode & FMODE_READ)
+		return file;
+
+	flags = file->f_flags & ~(O_WRONLY | O_APPEND | O_TRUNC | O_CREAT |
+				  O_NOCTTY | O_EXCL);
+	flags |= O_RDONLY;
+
+	alt_file = dentry_open(&file->f_path, flags, file->f_cred);
+	if (!IS_ERR(alt_file)) {
+		*status |= 1;
+		return alt_file;
+	}
+
+	file->f_flags |= FMODE_READ;
+	*status |= 2;
+	return file;
+}
+
+static int get_file_digest(struct file *file, struct inode *inode,
+			   loff_t size, u8 *digest)
+{
+	u8 *bufr;
+	int retn = 0, rsize;
+	unsigned int open_status = 0;
+	loff_t posn = 0;
+	struct file *read_file;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	bufr = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!bufr) {
+		retn = -ENOMEM;
+		goto done;
+	}
+
+	if (!likely(file->f_op->read || file->f_op->read_iter)) {
+		retn = -EINVAL;
+		goto done;
+	}
+	read_file = open_event_file(file, &open_status);
+
+	while (posn < size) {
+		rsize = integrity_kernel_read(read_file, posn, bufr, 4096);
+		if (rsize < 0) {
+			retn = rsize;
+			break;
+		}
+		if (rsize == 0)
+			break;
+
+		posn += rsize;
+		retn = crypto_shash_update(shash, bufr, rsize);
+		if (retn)
+			break;
+	}
+
+	kfree(bufr);
+	if (!retn)
+		retn = crypto_shash_final(shash, digest);
+
+ done:
+	if (open_status & 1)
+		fput(read_file);
+	if (open_status & 2)
+		file->f_flags &= ~FMODE_READ;
+	if (open_status & 4)
+		file->f_flags &= ~FMODE_CAN_READ;
+	return retn;
+}
+
+static int add_file_digest(struct file *file, struct tsem_file *tfp)
+{
+	int retn = 0;
+	u8 measurement[HASH_MAX_DIGESTSIZE];
+	loff_t size;
+	struct inode *inode;
+	struct tsem_inode *tsip;
+	struct tsem_inode_digest *digest;
+	struct tsem_context *ctx = tsem_context(current);
+
+	inode = file_inode(file);
+	tsip = tsem_inode(inode);
+
+	mutex_lock(&tsip->mutex);
+	if (!ctx->external) {
+		retn = tsem_model_has_pseudonym(tsip, tfp);
+		if (retn < 0)
+			goto done;
+		if (retn) {
+			memcpy(tfp->digest, ctx->zero_digest,
+			       tsem_digestsize());
+			retn = 0;
+			goto done;
+		}
+	}
+
+	size = i_size_read(inode);
+	if (!size) {
+		memcpy(tfp->digest, ctx->zero_digest, tsem_digestsize());
+		goto done;
+	}
+
+	digest = find_digest(tsip);
+
+	if (digest && inode_eq_iversion(inode, digest->version) &&
+	    tsip->status == TSEM_INODE_COLLECTED) {
+		memcpy(tfp->digest, digest->value, tsem_digestsize());
+		goto done;
+	}
+
+	tsip->status = TSEM_INODE_COLLECTING;
+	retn = get_file_digest(file, inode, size, measurement);
+	if (retn) {
+		tsip->status = 0;
+		goto done;
+	}
+
+	if (!digest) {
+		digest = add_digest(ctx, tsip);
+		if (!digest) {
+			retn = -ENOMEM;
+			goto done;
+		}
+	}
+
+	memcpy(tfp->digest, measurement, tsem_digestsize());
+	memcpy(digest->value, measurement, tsem_digestsize());
+	digest->version = inode_query_iversion(inode);
+	tsip->status = TSEM_INODE_COLLECTED;
+
+ done:
+	mutex_unlock(&tsip->mutex);
+	return retn;
+}
+
+static int get_file_cell(struct file *file, struct tsem_event *ep)
+{
+	int retn = 1;
+	struct inode *inode;
+	struct user_namespace *ns;
+
+	inode = file_inode(file);
+	inode_lock(inode);
+
+	ep->pathname = get_path(file);
+	if (IS_ERR(ep->pathname)) {
+		retn = PTR_ERR(ep->pathname);
+		goto done;
+	}
+
+	retn = add_file_name(ep);
+	if (retn)
+		goto done;
+
+	retn = add_file_digest(file, &ep->file);
+	if (retn)
+		goto done;
+
+	if (tsem_context(current)->use_current_ns)
+		ns = current_user_ns();
+	else
+		ns = &init_user_ns;
+
+	ep->file.flags = file->f_flags;
+
+	ep->file.uid = from_kuid(ns, inode->i_uid);
+	ep->file.gid = from_kgid(ns, inode->i_gid);
+	ep->file.mode = inode->i_mode;
+	ep->file.s_magic = inode->i_sb->s_magic;
+	memcpy(ep->file.s_id, inode->i_sb->s_id, sizeof(ep->file.s_id));
+	memcpy(ep->file.s_uuid, inode->i_sb->s_uuid.b,
+	       sizeof(ep->file.s_uuid));
+
+ done:
+	inode_unlock(inode);
+	return retn;
+}
+
+static int get_socket_accept(struct tsem_event *ep)
+{
+	char *p, path[UNIX_PATH_MAX + 1];
+	int size, retn = 0;
+	struct tsem_socket_accept_args *sap = &ep->CELL.socket_accept;
+
+	if (sap->family == AF_INET || sap->family == AF_INET6)
+		return retn;
+
+	if (sap->family != AF_UNIX) {
+		memcpy(sap->u.mapping, tsem_context(current)->zero_digest,
+		       tsem_digestsize());
+		return retn;
+	}
+
+	memset(path, '\0', sizeof(path));
+	p = sap->u.af_unix->addr->name->sun_path;
+	size = sap->u.af_unix->addr->len -
+		offsetof(struct sockaddr_un, sun_path);
+	strncpy(path, p, size);
+	memcpy(sap->u.path, path, sizeof(sap->u.path));
+
+	return retn;
+}
+
+static int get_socket_connect(struct tsem_socket_connect_args *scp)
+{
+	u8 *p;
+	int retn, size;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	p = (u8 *) scp->addr->sa_data;
+	size = scp->addr_len - offsetof(struct sockaddr, sa_data);
+	retn = crypto_shash_digest(shash, p, size, scp->u.mapping);
+
+ done:
+	return retn;
+}
+
+static int get_socket_cell(struct tsem_event *ep)
+
+{
+	int size, retn = 0;
+	struct tsem_socket_connect_args *scp = &ep->CELL.socket_connect;
+
+	scp->family = scp->addr->sa_family;
+
+	switch (scp->family) {
+	case AF_INET:
+		memcpy(&scp->u.ipv4, scp->addr, sizeof(scp->u.ipv4));
+		break;
+	case AF_INET6:
+		memcpy(&scp->u.ipv6, scp->addr, sizeof(scp->u.ipv6));
+		break;
+	case AF_UNIX:
+		memset(scp->u.path, '\0', sizeof(scp->u.path));
+		size = scp->addr_len - offsetof(struct sockaddr_un, sun_path);
+		strncpy(scp->u.path, scp->addr->sa_data, size);
+		break;
+	default:
+		retn = get_socket_connect(scp);
+		break;
+	}
+
+	return retn;
+}
+
+/**
+ * tsem_event_init() - Initialize a security event description structure.
+ * @event: The security event number for which the structure is being
+ *	   initialized.
+ * @params: A pointer to the aggregation structure used to hold the
+ *	    parameters that describe the function.
+ * @locked: A boolean flag used to indicate if the event to be
+ *	    initialized is running in atomic context.
+ *
+ * This function is responsible for allocating and initializing the
+ * primary tsem_event structure and populating it based on the event type.
+ *
+ * Return: This function returns a pointer to the allocated structure which
+ *	   on failure will have an error return code embedded in it.
+ */
+struct tsem_event *tsem_event_init(enum tsem_event_type event,
+				   struct tsem_event_parameters *params,
+				   bool locked)
+{
+	int retn = 0;
+	struct tsem_event *ep = NULL;
+	struct tsem_task *task = tsem_task(current);
+
+	ep = tsem_event_allocate(locked);
+	if (!ep)
+		return ERR_PTR(-ENOMEM);
+
+	ep->event = event;
+	ep->locked = locked;
+	ep->pid = task_pid_nr(current);
+	memcpy(ep->comm, current->comm, sizeof(ep->comm));
+	memcpy(ep->task_id, task->task_id, tsem_digestsize());
+
+	get_COE(&ep->COE);
+	switch (event) {
+	case TSEM_FILE_OPEN:
+	case TSEM_BPRM_SET_CREDS:
+		retn = get_file_cell(params->u.file, ep);
+		break;
+	case TSEM_MMAP_FILE:
+		ep->CELL.mmap_file = *params->u.mmap_file;
+		if (!ep->CELL.mmap_file.anonymous)
+			retn = get_file_cell(ep->CELL.mmap_file.file, ep);
+		break;
+	case TSEM_SOCKET_CREATE:
+		ep->CELL.socket_create = *params->u.socket_create;
+		break;
+	case TSEM_SOCKET_CONNECT:
+	case TSEM_SOCKET_BIND:
+		ep->CELL.socket_connect = *params->u.socket_connect;
+		retn = get_socket_cell(ep);
+		break;
+	case TSEM_SOCKET_ACCEPT:
+		ep->CELL.socket_accept = *params->u.socket_accept;
+		retn = get_socket_accept(ep);
+		break;
+	case TSEM_TASK_KILL:
+		ep->CELL.task_kill = *params->u.task_kill;
+		break;
+	case TSEM_GENERIC_EVENT:
+		ep->CELL.event_type = params->u.event_type;
+		break;
+	default:
+		WARN_ONCE(true, "Unhandled event type: %d\n", event);
+		break;
+	}
+
+	if (retn) {
+		kmem_cache_free(event_cachep, ep);
+		ep = ERR_PTR(retn);
+	} else
+		kref_init(&ep->kref);
+
+	return ep;
+}
+
+/**
+ * tsem_free_event() - Free a security event description.
+ * @ep: A pointer to the security event description that is to be freed.
+ *
+ * This function is responsible for freeing the resources that were
+ * allocated by the tsem_event_allocate() function.
+ */
+static void tsem_event_free(struct kref *kref)
+{
+	struct tsem_event *ep;
+
+	ep = container_of(kref, struct tsem_event, kref);
+	if (ep)
+		kfree(ep->pathname);
+	kmem_cache_free(event_cachep, ep);
+}
+
+/**
+ * tsem_event_put() - Release a referenceto a TSEM event description.
+ *
+ * This function is called each time the use of a TSEM event description
+ * is dropped.
+ */
+void tsem_event_put(struct tsem_event *ep)
+{
+	kref_put(&ep->kref, tsem_event_free);
+}
+
+/**
+ * tsem_event_get() - Obtain a reference to a TSEM event description.
+ *
+ * This function is called on each invocation of the tsem_task_free
+ * function to release one of the references on the TMA modeling
+ * structure.
+ */
+void tsem_event_get(struct tsem_event *ep)
+{
+	kref_get(&ep->kref);
+}
+
+/**
+ * tsem_event_allocate() - Allocate a TSEM event description structure.
+ * @locked: A boolean flag used to indicate if the allocation is being
+ *	    done in atomic context and must be serviced from the
+ *	    pre-allocated event description structures.
+ *
+ * Return: This function returns a pointer to the allocated structure or
+ *	   a NULL pointer in the event of an allocation failure.
+ */
+struct tsem_event *tsem_event_allocate(bool locked)
+{
+	unsigned int index;
+	struct tsem_event *ep = NULL;
+	struct tsem_context *ctx = tsem_context(current);
+
+	if (!locked)
+		return kmem_cache_zalloc(event_cachep, GFP_KERNEL);
+
+	spin_lock(&ctx->magazine_lock);
+	index = find_first_zero_bit(ctx->magazine_index, ctx->magazine_size);
+	if (index < ctx->magazine_size) {
+		ep = ctx->magazine[index];
+		ctx->ws[index].index = index;
+		ctx->ws[index].u.ctx = ctx;
+		set_bit(index, ctx->magazine_index);
+
+		/*
+		 * Similar to the issue noted in the refill_event_magazine()
+		 * function, this barrier is used to cause the consumption
+		 * of the cache entry to become visible.
+
+		 */
+		smp_mb__after_atomic();
+	}
+
+	spin_unlock(&ctx->magazine_lock);
+
+	if (ep) {
+		INIT_WORK(&ctx->ws[index].work, refill_event_magazine);
+		queue_work(system_wq, &ctx->ws[index].work);
+		return ep;
+	}
+
+	pr_warn("tsem: %s in %llu failed event allocation, cache size=%u.\n",
+		current->comm, tsem_context(current)->id, ctx->magazine_size);
+	return NULL;
+}
+
+/**
+ * tsem event_magazine_allocate() - Allocate a TSEM event magazine.
+ * @ctx: A pointer to the modeling context that the magazine is
+ *	 to be allocated for.
+ * @size: The number of entries to be created in the magazine.
+
+ * The security modeling event magazine is an array of tsem_event
+ * structures that are used to service security hooks that are called
+ * in atomic context.  Each modeling domain/namespace has a magazine
+ * allocated to it and this function allocates and initializes the
+ * memory structures needed to manage that magazine.
+
+ * Return: This function returns a value of zero on success and a negative
+ *	   error code on failure.
+ */
+int tsem_event_magazine_allocate(struct tsem_context *ctx, size_t size)
+{
+	unsigned int lp;
+	int retn = -ENOMEM;
+
+	ctx->magazine_size = size;
+
+	spin_lock_init(&ctx->magazine_lock);
+
+	ctx->magazine_index = bitmap_zalloc(ctx->magazine_size, GFP_KERNEL);
+	if (!ctx->magazine_index)
+		return retn;
+
+	ctx->magazine = kcalloc(ctx->magazine_size, sizeof(*ctx->magazine),
+				GFP_KERNEL);
+	if (!ctx->magazine)
+		goto done;
+
+	for (lp = 0; lp < ctx->magazine_size; ++lp) {
+		ctx->magazine[lp] = kmem_cache_zalloc(event_cachep,
+						      GFP_KERNEL);
+		if (!ctx->magazine[lp])
+			goto done;
+	}
+
+	ctx->ws = kcalloc(ctx->magazine_size, sizeof(*ctx->ws), GFP_KERNEL);
+	if (ctx->ws)
+		retn = 0;
+
+ done:
+	if (retn)
+		tsem_event_magazine_free(ctx);
+
+	return retn;
+}
+
+/**
+ * tsem event_magazine_free() - Releases a TSEM event magazine.
+ * @ctx: A pointer to the modeling context whose magazine is to be
+ *	 released.
+ *
+ * The function is used to free the memory that was allocated by
+ * the tsem_event_magazine_allocate() function for a security
+ * modeling context.
+ */
+void tsem_event_magazine_free(struct tsem_context *ctx)
+{
+	unsigned int lp;
+
+	for (lp = 0; lp < ctx->magazine_size; ++lp)
+		kmem_cache_free(event_cachep, ctx->magazine[lp]);
+
+	bitmap_free(ctx->magazine_index);
+	kfree(ctx->ws);
+	kfree(ctx->magazine);
+}
+
+/**
+ * tsem event_cache_init() - Initialize the TSEM event cache.
+ *
+ * This function is called by the TSEM initialization function and sets
+ * up the cache that will be used to allocate tsem_event structures.
+ *
+ * Return: This function returns a value of zero on success and a negative
+ *	   error code on failure.
+ */
+int __init tsem_event_cache_init(void)
+{
+	event_cachep = kmem_cache_create("tsem_event_cache",
+					 sizeof(struct tsem_event), 0,
+					 SLAB_PANIC, 0);
+	if (!event_cachep)
+		return -ENOMEM;
+
+	return 0;
+}
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 11/13] Implement security event mapping.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (9 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 10/13] Add event description implementation Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-07-10 10:23 ` [PATCH 12/13] Implement an internal Trusted Modeling Agent Dr. Greg
  2023-07-10 10:23 ` [PATCH 13/13] Activate the configuration and build of the TSEM LSM Dr. Greg
  12 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

The map.c file is responsible for implenting the description of a
security event into a security state coefficient.  The following
documentation file provided as a part of the TSEM implementation
contains a description of this mapping process:

Documentation/admin-guide/LSM/tsem.rst

The mapping process takes a security event description, that was
described in the event.c file, and uses that to drive the mapping
process.  The allocation and mapping of the event is unified
through the tsem_map_event() function provided in this file.

The function for a security event state coefficient mapping is as
follows:

Sp = HF(HF(EVENT_ID) || TASK_ID || HF(COE) || HF(CELL))

Where HF is the cryptographic hash function that has been
designated for use by a security modeling namespace.

This function is fully described in the previously noted
documentation file.

The TASK_ID is the security state coefficient for the
bprm_creds_for_exec security event hook.  It is generated by the
tsem_map_task() function that is implemented in this file.

The TASK_ID mapping function uses the same functional expression
as the security state coefficient mapping but substitutes a
TASK_ID that consists of a buffer of null bytes equal in size to
the digest size of the cryptographic hash function being used in
the model.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/map.c | 531 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 531 insertions(+)
 create mode 100644 security/tsem/map.c

diff --git a/security/tsem/map.c b/security/tsem/map.c
new file mode 100644
index 000000000000..45f8ee6eca89
--- /dev/null
+++ b/security/tsem/map.c
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * This file implements mapping of events into security event points.
+ */
+
+#include "tsem.h"
+
+static int get_COE_mapping(struct tsem_event *ep, u8 *mapping)
+{
+	int retn = 0, size;
+	u8 *p;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	p = (u8 *) &ep->COE.uid;
+	size = sizeof(ep->COE.uid);
+	retn = crypto_shash_update(shash, p, size);
+	if (retn)
+		goto done;
+
+	p = (u8 *) &ep->COE.euid;
+	size = sizeof(ep->COE.euid);
+	retn = crypto_shash_update(shash, p, size);
+	if (retn)
+		goto done;
+
+	p = (u8 *) &ep->COE.suid;
+	size = sizeof(ep->COE.suid);
+	retn = crypto_shash_update(shash, p, size);
+	if (retn)
+		goto done;
+
+	p = (u8 *) &ep->COE.gid;
+	size = sizeof(ep->COE.gid);
+	retn = crypto_shash_update(shash, p, size);
+	if (retn)
+		goto done;
+
+	p = (u8 *) &ep->COE.egid;
+	size = sizeof(ep->COE.egid);
+	retn = crypto_shash_update(shash, p, size);
+	if (retn)
+		goto done;
+
+	p = (u8 *) &ep->COE.sgid;
+	size = sizeof(ep->COE.sgid);
+	retn = crypto_shash_update(shash, p, size);
+	if (retn)
+		goto done;
+
+	p = (u8 *) &ep->COE.fsuid;
+	size = sizeof(ep->COE.fsuid);
+	retn = crypto_shash_update(shash, p, size);
+	if (retn)
+		goto done;
+
+	p = (u8 *) &ep->COE.fsgid;
+	size = sizeof(ep->COE.fsgid);
+	retn = crypto_shash_update(shash, p, size);
+	if (retn)
+		goto done;
+
+	p = (u8 *) &ep->COE.capeff;
+	size = sizeof(ep->COE.capeff);
+	retn = crypto_shash_finup(shash, p, size, mapping);
+
+ done:
+	return retn;
+}
+
+static int get_cell_mapping(struct tsem_event *ep, u8 *mapping)
+{
+	int retn = 0, size;
+	u8 *p;
+	struct sockaddr_in *ipv4;
+	struct sockaddr_in6 *ipv6;
+	struct tsem_mmap_file_args *mm_args = &ep->CELL.mmap_file;
+	struct tsem_socket_connect_args *scp = &ep->CELL.socket_connect;
+	struct tsem_socket_accept_args *sap = &ep->CELL.socket_accept;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	if (ep->event == TSEM_MMAP_FILE) {
+		p = (u8 *) &mm_args->reqprot;
+		size = sizeof(mm_args->reqprot);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &mm_args->prot;
+		size = sizeof(mm_args->prot);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &mm_args->flags;
+		size = sizeof(mm_args->flags);
+		if (!mm_args->file) {
+			retn = crypto_shash_finup(shash, p, size, mapping);
+			goto done;
+		}
+
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+	}
+
+	switch (ep->event) {
+	case TSEM_FILE_OPEN:
+	case TSEM_MMAP_FILE:
+	case TSEM_BPRM_SET_CREDS:
+		p = (u8 *) &ep->file.flags;
+		size = sizeof(ep->file.flags);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->file.uid;
+		size = sizeof(ep->file.uid);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->file.gid;
+		size = sizeof(ep->file.gid);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->file.mode;
+		size = sizeof(ep->file.mode);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->file.name_length;
+		size = sizeof(ep->file.name_length);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->file.name;
+		size = tsem_digestsize();
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->file.s_magic;
+		size = sizeof(ep->file.s_magic);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->file.s_id;
+		size = sizeof(ep->file.s_id);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->file.s_uuid;
+		size = sizeof(ep->file.s_uuid);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->file.digest;
+		size = tsem_digestsize();
+		retn = crypto_shash_finup(shash, p, size, mapping);
+		break;
+
+	case TSEM_SOCKET_CREATE:
+		p = (u8 *) &ep->CELL.socket_create.family;
+		size = sizeof(ep->CELL.socket_create.family);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->CELL.socket_create.type;
+		size = sizeof(ep->CELL.socket_create.type);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->CELL.socket_create.protocol;
+		size = sizeof(ep->CELL.socket_create.protocol);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->CELL.socket_create.kern;
+		size = sizeof(ep->CELL.socket_create.kern);
+		retn = crypto_shash_finup(shash, p, size, mapping);
+		if (retn)
+			goto done;
+		break;
+
+	case TSEM_SOCKET_CONNECT:
+	case TSEM_SOCKET_BIND:
+		p = (u8 *) &scp->family;
+		size = sizeof(scp->family);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		switch (scp->family) {
+		case AF_INET:
+			ipv4 = (struct sockaddr_in *) &scp->u.ipv4;
+			p = (u8 *) &ipv4->sin_port;
+			size = sizeof(ipv4->sin_port);
+			retn = crypto_shash_update(shash, p, size);
+			if (retn)
+				goto done;
+
+			p = (u8 *) &ipv4->sin_addr.s_addr;
+			size = sizeof(ipv4->sin_addr.s_addr);
+			retn = crypto_shash_finup(shash, p, size, mapping);
+			break;
+
+		case AF_INET6:
+			ipv6 = (struct sockaddr_in6 *) &scp->u.ipv6;
+			p = (u8 *) &ipv6->sin6_port;
+			size = sizeof(ipv6->sin6_port);
+			retn = crypto_shash_update(shash, p, size);
+			if (retn)
+				goto done;
+
+			p = (u8 *) ipv6->sin6_addr.in6_u.u6_addr8;
+			size = sizeof(ipv6->sin6_addr.in6_u.u6_addr8);
+			retn = crypto_shash_update(shash, p, size);
+			if (retn)
+				goto done;
+
+			p = (u8 *) &ipv6->sin6_flowinfo;
+			size = sizeof(ipv6->sin6_flowinfo);
+			retn = crypto_shash_update(shash, p, size);
+			if (retn)
+				goto done;
+
+			p = (u8 *) &ipv6->sin6_scope_id;
+			size = sizeof(ipv6->sin6_scope_id);
+			retn = crypto_shash_finup(shash, p, size, mapping);
+			if (retn)
+				goto done;
+			break;
+
+		case AF_UNIX:
+			p = scp->u.path;
+			size = strlen(scp->u.path);
+			retn = crypto_shash_finup(shash, p, size, mapping);
+			if (retn)
+				goto done;
+			break;
+
+		default:
+			p = (u8 *) scp->u.mapping;
+			size = tsem_digestsize();
+			retn = crypto_shash_finup(shash, p, size, mapping);
+			if (retn)
+				goto done;
+			break;
+		}
+		break;
+
+	case TSEM_SOCKET_ACCEPT:
+		p = (u8 *) &sap->family;
+		size = sizeof(sap->family);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &sap->type;
+		size = sizeof(sap->type);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &sap->port;
+		size = sizeof(sap->port);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		switch (sap->family) {
+		case AF_INET:
+			p = (u8 *) &sap->u.ipv4;
+			size = sizeof(sap->u.ipv4);
+			retn = crypto_shash_finup(shash, p, size, mapping);
+			if (retn)
+				goto done;
+			break;
+
+		case AF_INET6:
+			p = (u8 *) sap->u.ipv6.in6_u.u6_addr8;
+			size = sizeof(sap->u.ipv6.in6_u.u6_addr8);
+			retn = crypto_shash_finup(shash, p, size, mapping);
+			if (retn)
+				goto done;
+			break;
+
+		case AF_UNIX:
+			p = sap->u.path;
+			size = strlen(sap->u.path);
+			retn = crypto_shash_finup(shash, p, size, mapping);
+			if (retn)
+				goto done;
+			break;
+
+		default:
+			p = sap->u.mapping;
+			size = tsem_digestsize();
+			retn = crypto_shash_finup(shash, p, size, mapping);
+			if (retn)
+				goto done;
+			break;
+		}
+		break;
+
+	case TSEM_TASK_KILL:
+		p = (u8 *) &ep->CELL.task_kill.cross_model;
+		size = sizeof(ep->CELL.task_kill.cross_model);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->CELL.task_kill.signal;
+		size = sizeof(ep->CELL.task_kill.signal);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = (u8 *) &ep->CELL.task_kill.target;
+		size = sizeof(ep->CELL.task_kill.target);
+		retn = crypto_shash_finup(shash, p, size, mapping);
+		if (retn)
+			goto done;
+		break;
+
+	case TSEM_GENERIC_EVENT:
+		p = (u8 *) tsem_names[ep->CELL.event_type];
+		size = strlen(tsem_names[ep->CELL.event_type]);
+		retn = crypto_shash_update(shash, p, size);
+		if (retn)
+			goto done;
+
+		p = tsem_context(current)->zero_digest;
+		size = tsem_digestsize();
+		retn = crypto_shash_finup(shash, p, size, mapping);
+		if (retn)
+			goto done;
+		break;
+
+	default:
+		break;
+	}
+
+ done:
+	return retn;
+}
+
+static int get_event_mapping(int event, u8 *task_id, u8 *COE_id, u8 *cell_id,
+			     u8 *mapping)
+{
+	int retn = 0;
+	u32 event_id = (u32) event;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	retn = crypto_shash_update(shash, tsem_names[event_id],
+				   strlen(tsem_names[event_id]));
+	if (retn)
+		goto done;
+	if (task_id) {
+		retn = crypto_shash_update(shash, task_id, tsem_digestsize());
+		if (retn)
+			goto done;
+	}
+	retn = crypto_shash_update(shash, COE_id, tsem_digestsize());
+	if (retn)
+		goto done;
+	retn = crypto_shash_finup(shash, cell_id, tsem_digestsize(), mapping);
+
+ done:
+	return retn;
+}
+
+static int map_event(enum tsem_event_type event, struct tsem_event *ep,
+		     u8 *task_id, u8 *event_mapping)
+{
+	int retn;
+	u8 COE_mapping[HASH_MAX_DIGESTSIZE];
+	u8 cell_mapping[HASH_MAX_DIGESTSIZE];
+
+	retn = get_COE_mapping(ep, COE_mapping);
+	if (retn)
+		goto done;
+
+	retn = get_cell_mapping(ep, cell_mapping);
+	if (retn)
+		goto done;
+
+	retn = get_event_mapping(event, task_id, COE_mapping, cell_mapping,
+				 event_mapping);
+ done:
+	return retn;
+}
+
+/**
+ * tsem_map_task() - Create the task identity description structure.
+ * @file: A pointer to the file structure defining the executable.
+ * @task_id: Pointer to the buffer that the task id will be copied to.
+ *
+ * This function creates the security event state point that will be used
+ * as the task identifier for the generation of security state points
+ * that are created by the process that task identifier is assigned to.
+ *
+ * Return: This function returns 0 if the mapping was successfully
+ *	   created and an error value otherwise.
+ */
+int tsem_map_task(struct file *file, u8 *task_id)
+{
+	int retn = 0;
+	u8 null_taskid[HASH_MAX_DIGESTSIZE];
+	struct tsem_event *ep;
+	struct tsem_event_parameters params;
+
+	params.u.file = file;
+	ep = tsem_event_init(TSEM_BPRM_SET_CREDS, &params, false);
+	if (IS_ERR(ep)) {
+		retn = PTR_ERR(ep);
+		ep = NULL;
+		goto done;
+	}
+
+	memset(null_taskid, '\0', tsem_digestsize());
+	retn = map_event(TSEM_BPRM_SET_CREDS, ep, null_taskid, task_id);
+	tsem_event_put(ep);
+
+ done:
+	return retn;
+}
+
+/**
+ * tsem_map_event() - Create a security event mapping.
+ * @event: The number of the event to be mapped.
+ * @params: A pointer to the structure containing the event description
+ *	    parameters.
+ *
+ * This function creates a structure to describe a security event
+ * and maps the event into a security state coefficient.
+ *
+ * Return: On success the function returns a pointer to the tsem_event
+ *	   structure that describes the event.  If an error is encountered
+ *	   an error return value is encoded in the pointer.
+ */
+struct tsem_event *tsem_map_event(enum tsem_event_type event,
+				  struct tsem_event_parameters *params)
+{
+	int retn = 0;
+	struct tsem_event *ep;
+	struct tsem_task *task = tsem_task(current);
+
+	ep = tsem_event_init(event, params, false);
+	if (IS_ERR(ep))
+		goto done;
+
+	if (task->context->external)
+		goto done;
+
+	retn = map_event(event, ep, task->task_id, ep->mapping);
+	if (retn) {
+		tsem_event_put(ep);
+		ep = ERR_PTR(retn);
+	}
+
+ done:
+	return ep;
+}
+
+
+/**
+ * tsem_map_event_locked() - Create a security event mapping while atomic.
+ * @event: The number of the event to be mapped.
+ * @params: A pointer to the structure containing the event description
+ *	    parameters.
+ *
+ * This function creates a structure to describe a security event
+ * and maps the event into a security state coefficient.
+ *
+ * Return: On success the function returns a pointer to the tsem_event
+ *	   structure that describes the event.  If an error is encountered
+ *	   an error return value is encoded in the pointer.
+ */
+struct tsem_event *tsem_map_event_locked(enum tsem_event_type event,
+					 struct tsem_event_parameters *params)
+{
+	int retn = 0;
+	struct tsem_event *ep;
+	struct tsem_task *task = tsem_task(current);
+
+	ep = tsem_event_init(event, params, true);
+	if (IS_ERR(ep))
+		goto done;
+
+	if (task->context->external)
+		goto done;
+
+	retn = map_event(event, ep, task->task_id, ep->mapping);
+	if (retn) {
+		tsem_event_put(ep);
+		ep = ERR_PTR(retn);
+	}
+
+ done:
+	return ep;
+}
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 12/13] Implement an internal Trusted Modeling Agent.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (10 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 11/13] Implement security event mapping Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  2023-07-10 10:23 ` [PATCH 13/13] Activate the configuration and build of the TSEM LSM Dr. Greg
  12 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

A Trusted Modeling Agent (TMA) is an implementation of a modeling
algorithm that converts a description of a security event (LSM hook)
into a security state coefficient.  The sum of these coefficients is
considered to be the functional value of the security model
implemented in a security modeling namespace.

The current model implemented is the simple deterministic model
used by the Quixote trust orchestrators.  These orchestrators
represent an initial implementation of the support infrastructure
needed to use the TSEM modeling LSM.  It is anticipated that
other in-kernel modeling implementations will be developed.

The TMA takes the mapping of a security state coefficient, as
generated by the tsem_map_event() function, and determines
whether or not the generated coefficient is a valid coefficient
in the security model being implemented for a security modeling
namespace.  If it is a valid coefficient, the process executing
the security event is designated as being trusted, otherwise the
state of the process is set to be untrusted.

By default the TMA runs in free modeling mode where all security
events are considered valid.  In this mode, the security state
coefficient is registered as a valid coefficient and the
description of the event is added to the security execution
trajectory for the model.

The model implementation can be 'sealed' through the TSEM control
plane, a condition that causes any coefficients not registered in
the model to be considered a 'forensics' event.  The description
of such an event is added to the forensics execution trajectory
for the model.  A forensics event does not result in permission
to the event to be denied unless the model is placed in
'enforcing' mode.

While the current in-kernel TMA is largely deterministic, one
approximation method is provided by this model, which is the
notion of a file digest 'pseudonym'.  A pseudonym can be declared
for an inode by registering the value of the following function
with the model:

Pseudonym = HF(PATH_LENGTH || PATHNAME)

Where HF is the hash function that has been selected for the
security modeling namespace.

If a file pseudonym is detected the file digest value used for
the CELL definition is set to the 'zero message' value of the
cryptographic function being used for the model.  The 'zero
message' value is consistent with what would be produced by a
zero length file.

The pseudonym value is model specific.  A separate modeling
namespace, without a pseudonym definition, will use the actual
computed digest of the file.

The TMA implementation also supports the definition of a 'base'
coefficient that is a nonce equal in length to the cryptographic
hash function being used for the model.  This value is used to
extend the security state coefficient before it is added to the
model.  This allows a verifying partner to specify a nonce that
will allow a verifying partner to confirm the 'freshness' of an
attestation of the function state of the model.

The modeling implementation supports two different functional
values for the model being implemented.  The classic linear
extension sum of all the security state coefficients and a value
referred to as the 'state' of the security model.

The 'state' value is designed to make the measurement value
invariant to scheduling variations that cause the classic trusted
system measurement to be non-deterministic between runs of a
workload.  The state value is computed by sorting the security
event state coefficients in the model in big-endian (natural hash
byte order) format and then computing the extension sum over this
sorted vector of coefficients.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/tsem/model.c | 714 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 714 insertions(+)
 create mode 100644 security/tsem/model.c

diff --git a/security/tsem/model.c b/security/tsem/model.c
new file mode 100644
index 000000000000..ed06485ef50d
--- /dev/null
+++ b/security/tsem/model.c
@@ -0,0 +1,714 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Copyright (C) 2023 Enjellic Systems Development, LLC
+ * Author: Dr. Greg Wettstein <greg@enjellic.com>
+ *
+ * Implements the an kernel modeling agent.
+ */
+
+#include <linux/sort.h>
+
+#include "tsem.h"
+
+struct pseudonym {
+	struct list_head list;
+	u8 mapping[HASH_MAX_DIGESTSIZE];
+};
+
+static struct kmem_cache *point_cachep;
+
+static void refill_point_magazine(struct work_struct *work)
+{
+	struct tsem_event_point *tep;
+	struct tsem_work *ws;
+
+	ws = container_of(work, struct tsem_work, work);
+
+	tep = kmem_cache_zalloc(point_cachep, GFP_KERNEL);
+	if (!tep) {
+		pr_warn("tsem: Cannot refill model point magazine.\n");
+		return;
+	}
+
+	spin_lock(&ws->u.model->magazine_lock);
+	ws->u.model->magazine[ws->index] = tep;
+	clear_bit(ws->index, ws->u.model->magazine_index);
+
+	/*
+	 * The following memory barrier is used to cause the magazine
+	 * index to be visible after the refill of the cache slot.
+	 */
+	smp_mb__after_atomic();
+
+	spin_unlock(&ws->u.model->magazine_lock);
+}
+
+static struct tsem_event_point *alloc_event_point(struct tsem_model *model,
+						  bool locked)
+{
+	unsigned int index;
+	struct tsem_event_point *tep = NULL;
+
+	if (!locked)
+		return kmem_cache_zalloc(point_cachep, GFP_KERNEL);
+
+	spin_lock(&model->magazine_lock);
+	index = find_first_zero_bit(model->magazine_index,
+				    model->magazine_size);
+	if (index < model->magazine_size) {
+		tep = model->magazine[index];
+		model->ws[index].index = index;
+		model->ws[index].u.model = model;
+		set_bit(index, model->magazine_index);
+
+		/*
+		 * Similar to the issue noted in the refill_point_magazine(),
+		 * function, this barrier is used to cause the consumption
+		 * of the cache entry to become visible.
+		 */
+		smp_mb__after_atomic();
+	}
+	spin_unlock(&model->magazine_lock);
+
+	if (tep) {
+		INIT_WORK(&model->ws[index].work, refill_point_magazine);
+		queue_work(system_wq, &model->ws[index].work);
+		return tep;
+	}
+
+	pr_warn("tsem: %s in %llu failed point allocation, cache size=%u.\n",
+		current->comm, tsem_context(current)->id,
+		model->magazine_size);
+	return NULL;
+
+}
+
+static int magazine_allocate(struct tsem_model *model, size_t size)
+{
+	unsigned int lp;
+	int retn = -ENOMEM;
+
+	model->magazine_size = size;
+
+	spin_lock_init(&model->magazine_lock);
+
+	model->magazine_index = bitmap_zalloc(model->magazine_size,
+					      GFP_KERNEL);
+	if (!model->magazine_index)
+		return retn;
+
+	model->magazine = kcalloc(model->magazine_size,
+				  sizeof(*model->magazine), GFP_KERNEL);
+	if (!model->magazine)
+		goto done;
+
+	for (lp = 0; lp < model->magazine_size; ++lp) {
+		model->magazine[lp] = kmem_cache_zalloc(point_cachep,
+							GFP_KERNEL);
+		if (!model->magazine[lp])
+			goto done;
+	}
+
+	model->ws = kcalloc(model->magazine_size, sizeof(*model->ws),
+			    GFP_KERNEL);
+	if (model->ws)
+		retn = 0;
+
+ done:
+	if (retn)
+		tsem_model_magazine_free(model);
+
+	return retn;
+}
+
+static int generate_pseudonym(struct tsem_file *ep, u8 *pseudonym)
+{
+	int retn = 0;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	retn = crypto_shash_update(shash, (u8 *) &ep->name_length,
+				   sizeof(ep->name_length));
+	if (retn)
+		goto done;
+
+	retn = crypto_shash_finup(shash, ep->name, tsem_digestsize(),
+				  pseudonym);
+ done:
+	return retn;
+}
+
+static struct tsem_event_point *have_point(u8 *point)
+{
+	struct tsem_event_point *entry, *retn = NULL;
+	struct tsem_context *ctx = tsem_context(current);
+	struct tsem_model *model = ctx->model;
+
+	spin_lock(&model->point_lock);
+	list_for_each_entry(entry, &model->point_list, list) {
+		if (memcmp(entry->point, point, tsem_digestsize()) == 0) {
+			retn = entry;
+			goto done;
+		}
+	}
+
+ done:
+	spin_unlock(&model->point_lock);
+	return retn;
+}
+
+static struct tsem_event_point *add_event_point(u8 *point, bool valid,
+						bool locked)
+{
+	struct tsem_event_point *entry;
+	struct tsem_model *model = tsem_model(current);
+
+	entry = alloc_event_point(model, locked);
+	if (!entry)
+		return ERR_PTR(-ENOMEM);
+
+	entry->valid = valid;
+	memcpy(entry->point, point, tsem_digestsize());
+
+	spin_lock(&model->point_lock);
+	++model->point_count;
+	list_add_tail(&entry->list, &model->point_list);
+	spin_unlock(&model->point_lock);
+
+	return entry;
+}
+
+static int add_trajectory_point(struct tsem_event *ep)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	ep->pid = 0;
+	tsem_event_get(ep);
+
+	spin_lock(&model->trajectory_lock);
+	list_add_tail(&ep->list, &model->trajectory_list);
+	spin_unlock(&model->trajectory_lock);
+
+	return 0;
+}
+
+static int add_forensic_point(struct tsem_event *ep)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	ep->pid = 0;
+	tsem_event_get(ep);
+
+	spin_lock(&model->forensics_lock);
+	list_add_tail(&ep->list, &model->forensics_list);
+	spin_unlock(&model->forensics_lock);
+
+	return 0;
+}
+
+static int get_host_measurement(u8 *id, u8 *digest)
+{
+	int retn;
+	struct tsem_model *model = tsem_model(current);
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	retn = crypto_shash_update(shash, model->base, tsem_digestsize());
+	if (retn)
+		goto done;
+
+	retn = crypto_shash_finup(shash, id, tsem_digestsize(), digest);
+
+ done:
+	return retn;
+}
+
+static int update_events_measurement(struct tsem_event *ep)
+{
+	int retn;
+	u8 digest[HASH_MAX_DIGESTSIZE];
+	struct tsem_context *ctx = tsem_context(current);
+	struct tsem_model *model = ctx->model;
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	retn = get_host_measurement(ep->mapping, digest);
+	if (retn)
+		goto done;
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	retn = crypto_shash_update(shash, model->measurement,
+				   tsem_digestsize());
+	if (retn)
+		goto done;
+
+	retn = crypto_shash_finup(shash, digest, tsem_digestsize(),
+				  model->measurement);
+	if (retn)
+		goto done;
+
+	if (!tsem_context(current)->id)
+		retn = tsem_trust_add_event(ep);
+
+ done:
+	return retn;
+}
+
+static int state_sort(const void *a, const void *b)
+{
+	unsigned int lp, retn = 0;
+	struct tsem_event_point *ap, *bp;
+
+	ap = *((struct tsem_event_point **) a);
+	bp = *((struct tsem_event_point **) b);
+
+	for (lp = 0; lp < tsem_digestsize(); ++lp) {
+		if (ap->point[lp] == bp->point[lp])
+			continue;
+
+		if (ap->point[lp] < bp->point[lp])
+			retn = -1;
+		else
+			retn = 1;
+		goto done;
+	}
+
+ done:
+	return retn;
+}
+
+/**
+ * tesm_model_compute_state() - Calculate a security model state value.
+ *
+ * The function generates the state value of the current modeling domain.
+ */
+void tsem_model_compute_state(void)
+{
+	u8 state[HASH_MAX_DIGESTSIZE];
+	int retn;
+	unsigned int lp, count, pt_count = 0;
+	struct list_head *end;
+	struct tsem_event_point *end_point, *entry, **points = NULL;
+	struct tsem_model *model = tsem_model(current);
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tsem_digest();
+	retn = crypto_shash_init(shash);
+	if (retn)
+		goto done;
+
+	memset(state, '\0', sizeof(state));
+	retn = crypto_shash_update(shash, state, tsem_digestsize());
+	if (retn)
+		goto done;
+
+	retn = get_host_measurement(tsem_trust_aggregate(), state);
+	if (retn)
+		goto done;
+
+	retn = crypto_shash_finup(shash, state, tsem_digestsize(), state);
+	if (retn)
+		goto done;
+
+	spin_lock(&model->point_lock);
+	end = model->point_list.prev;
+	count = model->point_count;
+	spin_unlock(&model->point_lock);
+
+	points = vmalloc(sizeof(*points) * count);
+	if (!points) {
+		retn = -ENOMEM;
+		goto done;
+	}
+
+	end_point = container_of(end, struct tsem_event_point, list);
+	list_for_each_entry(entry, &model->point_list, list) {
+		points[pt_count++] = entry;
+		if (end_point == entry)
+			break;
+	}
+	sort(points, count, sizeof(*points), state_sort, NULL);
+
+	memcpy(model->state, state, tsem_digestsize());
+	for (lp = 0; lp < pt_count; ++lp) {
+		entry = points[lp];
+
+		if (get_host_measurement(entry->point, state))
+			goto done;
+
+		if (crypto_shash_init(shash))
+			goto done;
+		if (crypto_shash_update(shash, model->state,
+					tsem_digestsize()))
+			goto done;
+		if (crypto_shash_finup(shash, state, tsem_digestsize(),
+				       model->state))
+			goto done;
+	}
+
+ done:
+	if (retn)
+		memset(model->state, '\0', tsem_digestsize());
+
+	vfree(points);
+}
+
+/**
+ * tsem_model_has_pseudonym() - Test for a model pseudonym.
+ * @tsip: A pointer to the TSEM inode security structure.
+ * @ep: A pointer to the TSEM event description structure.
+ *
+ * This function is used to test whether a pseudonym has been
+ * declared for a modeling domain.  It is up to the caller to
+ * populate the event description structure with a suitable
+ * value for the pseudonym digest.
+ *
+ * Return: If an error occurs during the pseudonym probe a negative
+ *	   return value is returned.  A zero return value indicates that
+ *	   a pseudonym was not present.  A value of one indicates that a
+ *	   pseudonym has been defined.
+ */
+int tsem_model_has_pseudonym(struct tsem_inode *tsip, struct tsem_file *ep)
+{
+	int retn = 0;
+	u8 pseudo_mapping[HASH_MAX_DIGESTSIZE];
+	struct tsem_model *model = tsem_model(current);
+	struct pseudonym *entry;
+
+	retn = generate_pseudonym(ep, pseudo_mapping);
+	if (retn)
+		goto done;
+
+	mutex_lock(&model->pseudonym_mutex);
+	list_for_each_entry(entry, &model->pseudonym_list, list) {
+		if (!memcmp(entry->mapping, pseudo_mapping,
+			    tsem_digestsize())) {
+			retn = 1;
+			goto done;
+		}
+	}
+	retn = 0;
+
+ done:
+	mutex_unlock(&model->pseudonym_mutex);
+	return retn;
+}
+
+/**
+ * tesm_model_event() - Inject a security event into a modeling domain.
+ * @ep: A pointer to the event description structure.
+ *
+ * This function is the entry point for the in kernel Trusted Modeling
+ * Agent (TMA).  It takes a description of an event encoded in a
+ * tsem_event structure and generates and updates the security model
+ * description.
+ *
+ * Return: If an error occurs during the injection of an event into a
+ *	   model a negative error value is returned.  A value of zero
+ *	   is returned if the event was successfully modeled.  The
+ *	   security status of the event is returned by encoding the value
+ *	   in the bad_COE member of the tsem_task structure.
+ */
+int tsem_model_event(struct tsem_event *ep)
+{
+	int retn;
+	struct tsem_event_point *point;
+	struct tsem_task *task = tsem_task(current);
+	struct tsem_context *ctx = task->context;
+
+	point = have_point(ep->mapping);
+	if (point) {
+		++point->count;
+		if (!point->valid)
+			task->trust_status = TSEM_TASK_UNTRUSTED;
+		return 0;
+	}
+
+	retn = update_events_measurement(ep);
+	if (retn)
+		goto done;
+
+	retn = -ENOMEM;
+	if (ctx->sealed) {
+		point = add_event_point(ep->mapping, false, ep->locked);
+		if (point) {
+			retn = add_forensic_point(ep);
+			task->trust_status = TSEM_TASK_UNTRUSTED;
+		}
+	} else {
+		point = add_event_point(ep->mapping, true, ep->locked);
+		if (point)
+			retn = add_trajectory_point(ep);
+	}
+
+	if (!retn)
+		++point->count;
+
+ done:
+	return retn;
+}
+
+/**
+ * tesm_model_load_point() - Load a security state event into a model.
+ * @point: A pointer to the array containing the security state
+ *	   point to be added to the model.
+ *
+ * This function takes the binary representation of a security state
+ * point and loads it into the current model domain.
+ *
+ * Return: If an error occurs during the processing of the security state
+ *	   point a negative return value is returned.  A return value of
+ *	   zero indicates the point was successfully loaded into the domain.
+ */
+int tsem_model_load_point(u8 *point)
+{
+	int retn = -ENOMEM;
+	struct tsem_event *ep;
+	struct tsem_context *ctx = tsem_context(current);
+
+	if (have_point(point))
+		return 0;
+
+	if (!add_event_point(point, true, false))
+		return retn;
+
+	if (!ctx->model->have_aggregate) {
+		retn = tsem_model_add_aggregate();
+		if (retn)
+			return retn;
+
+		ctx->model->have_aggregate = true;
+	}
+
+	ep = tsem_event_allocate(false);
+	if (!ep)
+		return retn;
+
+	kref_init(&ep->kref);
+	memcpy(ep->mapping, point, tsem_digestsize());
+	retn = update_events_measurement(ep);
+
+	tsem_event_put(ep);
+	return retn;
+}
+
+/**
+ * tesm_model_load_pseudonym() - Load a pseudonym state point to a model.
+ * @mapping: A pointer to the array containing the pseudonym state
+ *	     point that is to be added to the model.
+ *
+ * This function takes the binary representation of a file pseudonym
+ * and declares the presence of the pseudonym in the modeling domain.
+ *
+ * Return: If an error occurs during the processing of the pseudonym
+ *	   state point a negative return value is returned.  A return
+ *	   value of zero indicates the point was successfully loaded
+ *	   into the model.
+ */
+int tsem_model_load_pseudonym(u8 *mapping)
+{
+	struct pseudonym *psp = NULL;
+	struct tsem_model *model = tsem_model(current);
+
+	psp = kzalloc(sizeof(*psp), GFP_KERNEL);
+	if (!psp)
+		return -ENOMEM;
+	memcpy(psp->mapping, mapping, tsem_digestsize());
+
+	mutex_lock(&model->pseudonym_mutex);
+	list_add_tail(&psp->list, &model->pseudonym_list);
+	mutex_unlock(&model->pseudonym_mutex);
+	return 0;
+}
+
+/**
+ * tesm_model_load_base() - Load a model base point.
+ * @mapping: A pointer to the array containing the base point to be
+ *	     set for the model.
+ *
+ * This function takes the binary representation of a base point and
+ * sets this point as the base point for the model.
+ */
+void tsem_model_load_base(u8 *mapping)
+{
+	struct tsem_model *model = tsem_model(current);
+
+	memcpy(model->base, mapping, tsem_digestsize());
+}
+
+/**
+ * tesm_model_add_aggregate() - Add the hardware aggregate to a model.
+ *
+ * This function adds the hardware aggregate value to an internally
+ * modeled security domain.
+ *
+ * Return: If an error occurs during the injection of the aggregate
+ *	   value into the model a negative error value is returned.
+ *	   A return value of zero indicates the aggregate was
+ *	   successfully added.
+ */
+int tsem_model_add_aggregate(void)
+{
+	int retn = -ENOMEM;
+	struct tsem_event *ep;
+
+	ep = tsem_event_allocate(false);
+	if (!ep)
+		return retn;
+
+	kref_init(&ep->kref);
+	ep->digestsize = tsem_digestsize();
+	memcpy(ep->mapping, tsem_trust_aggregate(), ep->digestsize);
+
+	retn = update_events_measurement(ep);
+	tsem_event_put(ep);
+
+	return retn;
+}
+
+/**
+ * tsem_model_allocate() - Allocates a kernel TMA modeling structure.
+ * @size: The number of slots in the event point magazine for the model.
+ *
+ * This function allocates and initializes a tsem_model structure
+ * that is used to hold modeling information for an in kernel
+ * modeling domain.
+ *
+ * Return: On success a pointer to the model description structure is
+ *	   returned.  If an error occurs an error return value is
+ *	   encoded in the returned pointer.
+ */
+struct tsem_model *tsem_model_allocate(size_t size)
+{
+	struct tsem_model *model = NULL;
+
+	model = kzalloc(sizeof(*model), GFP_KERNEL);
+	if (!model)
+		return NULL;
+
+	spin_lock_init(&model->point_lock);
+	INIT_LIST_HEAD(&model->point_list);
+	mutex_init(&model->point_end_mutex);
+
+	spin_lock_init(&model->trajectory_lock);
+	INIT_LIST_HEAD(&model->trajectory_list);
+	mutex_init(&model->trajectory_end_mutex);
+
+	spin_lock_init(&model->forensics_lock);
+	INIT_LIST_HEAD(&model->forensics_list);
+	mutex_init(&model->forensics_end_mutex);
+
+	mutex_init(&model->pseudonym_mutex);
+	INIT_LIST_HEAD(&model->pseudonym_list);
+
+	if (magazine_allocate(model, size)) {
+		kfree(model);
+		model = NULL;
+	}
+
+	return model;
+}
+
+/**
+ * tsem_model_free() - Frees an a kernel TMA description structure.
+ * @ctx: A pointer to the TMA modeling description structure whose
+ *	 model definition is to be deleted.
+ *
+ * This function is called when the last reference to a kernel
+ * based TMA model description structure is released.
+ */
+void tsem_model_free(struct tsem_context *ctx)
+{
+	struct tsem_event_point *ep, *tmp_ep;
+	struct tsem_event *tentry, *tmp_tentry;
+	struct pseudonym *sentry, *tmp_sentry;
+	struct tsem_model *model = ctx->model;
+
+	list_for_each_entry_safe(ep, tmp_ep, &model->point_list, list) {
+		list_del(&ep->list);
+		kmem_cache_free(point_cachep, ep);
+	}
+
+	list_for_each_entry_safe(sentry, tmp_sentry, &model->pseudonym_list,
+				 list) {
+		list_del(&sentry->list);
+		kfree(sentry);
+	}
+
+	list_for_each_entry_safe(tentry, tmp_tentry, &model->trajectory_list,
+				 list) {
+		list_del(&tentry->list);
+		tsem_event_put(tentry);
+	}
+
+	if (ctx->sealed) {
+		list_for_each_entry_safe(tentry, tmp_tentry,
+					 &model->forensics_list, list) {
+			list_del(&tentry->list);
+			tsem_event_put(tentry);
+		}
+	}
+
+	tsem_model_magazine_free(model);
+	kfree(model);
+}
+
+/**
+ * tsem_model_magazine_free: Free the event point magazine for a model domain.
+ * @model: A pointer to the model whose magazine is to be freed.
+ *
+ * This function releases all of the components of an event point
+ * magazine that has been allocated for a modeling domain.
+ */
+void tsem_model_magazine_free(struct tsem_model *model)
+{
+	unsigned int lp;
+
+	for (lp = 0; lp < model->magazine_size; ++lp)
+		kmem_cache_free(point_cachep, model->magazine[lp]);
+
+	bitmap_free(model->magazine_index);
+	kfree(model->ws);
+	kfree(model->magazine);
+}
+
+/**
+ * tsem model_init() - Initialize the TSEM event point cache.
+ * @model: A pointer to the model that is being initialized.
+ * @size: The number of slots in the event point magazine for the root
+ *	  model.
+ *
+ * This function is called by the primary TSEM initialization function
+ * and sets up the cache that will be used to dispense tsem_event_point
+ * structures for security events that are called in atomic context.
+ *
+ * Return: This function returns a value of zero on success and a negative
+ *	   error code on failure.
+ */
+int __init tsem_model_cache_init(struct tsem_model *model, size_t size)
+{
+	point_cachep = kmem_cache_create("tsem_event_point_cache",
+					 sizeof(struct tsem_event_point), 0,
+					 SLAB_PANIC, 0);
+	if (!point_cachep)
+		return -ENOMEM;
+
+	if (magazine_allocate(model, size)) {
+		kmem_cache_destroy(point_cachep);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 13/13] Activate the configuration and build of the TSEM LSM.
  2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
                   ` (11 preceding siblings ...)
  2023-07-10 10:23 ` [PATCH 12/13] Implement an internal Trusted Modeling Agent Dr. Greg
@ 2023-07-10 10:23 ` Dr. Greg
  12 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-10 10:23 UTC (permalink / raw)
  To: linux-security-module, linux-kernel, corbet

Complete the implementation by integrating the LSM into the
configuration and kernel build infrastructure.

Signed-off-by: Greg Wettstein <greg@enjellic.com>
---
 security/Kconfig       | 11 ++++++-----
 security/Makefile      |  1 +
 security/tsem/Kconfig  | 36 ++++++++++++++++++++++++++++++++++++
 security/tsem/Makefile |  2 ++
 4 files changed, 45 insertions(+), 5 deletions(-)
 create mode 100644 security/tsem/Kconfig
 create mode 100644 security/tsem/Makefile

diff --git a/security/Kconfig b/security/Kconfig
index 97abeb9b9a19..23c25a12c8df 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -202,6 +202,7 @@ source "security/yama/Kconfig"
 source "security/safesetid/Kconfig"
 source "security/lockdown/Kconfig"
 source "security/landlock/Kconfig"
+source "security/tsem/Kconfig"
 
 source "security/integrity/Kconfig"
 
@@ -241,11 +242,11 @@ endchoice
 
 config LSM
 	string "Ordered list of enabled LSMs"
-	default "landlock,lockdown,yama,loadpin,safesetid,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK
-	default "landlock,lockdown,yama,loadpin,safesetid,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR
-	default "landlock,lockdown,yama,loadpin,safesetid,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO
-	default "landlock,lockdown,yama,loadpin,safesetid,bpf" if DEFAULT_SECURITY_DAC
-	default "landlock,lockdown,yama,loadpin,safesetid,selinux,smack,tomoyo,apparmor,bpf"
+	default "tsem,landlock,lockdown,yama,loadpin,safesetid,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK
+	default "tsem,landlock,lockdown,yama,loadpin,safesetid,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR
+	default "tsem,landlock,lockdown,yama,loadpin,safesetid,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO
+	default "tsem,landlock,lockdown,yama,loadpin,safesetid,bpf" if DEFAULT_SECURITY_DAC
+	default "tsem,landlock,lockdown,yama,loadpin,safesetid,selinux,smack,tomoyo,apparmor,bpf"
 	help
 	  A comma-separated list of LSMs, in initialization order.
 	  Any LSMs left off this list, except for those with order
diff --git a/security/Makefile b/security/Makefile
index 18121f8f85cd..11d93885c806 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_SECURITY_LOCKDOWN_LSM)	+= lockdown/
 obj-$(CONFIG_CGROUPS)			+= device_cgroup.o
 obj-$(CONFIG_BPF_LSM)			+= bpf/
 obj-$(CONFIG_SECURITY_LANDLOCK)		+= landlock/
+obj-$(CONFIG_SECURITY_TSEM)		+= tsem/
 
 # Object integrity file lists
 obj-$(CONFIG_INTEGRITY)			+= integrity/
diff --git a/security/tsem/Kconfig b/security/tsem/Kconfig
new file mode 100644
index 000000000000..2e9d54eb3acc
--- /dev/null
+++ b/security/tsem/Kconfig
@@ -0,0 +1,36 @@
+config SECURITY_TSEM
+	bool "Trusted Security Event Modeling"
+	depends on SECURITY
+	depends on NET && INET
+	select SECURITY_NETWORK
+	select SECURITYFS
+	select CRYPTO
+	select CRYPTO_SHA256
+	select CRYPTO_HASH_INFO
+	select TCG_TPM if HAS_IOMEM && !UML
+	select TCG_TIS if TCG_TPM && X86
+	select TCG_CRB if TCG_TPM && ACPI
+	default n
+	help
+	  This option selects support for Trusted Security Event
+	  Modeling (TSEM).  TSEM implements the ability to model
+	  the security state of either the system at large or in a
+	  restricted namespace on the basis of the LSM security
+	  events and attributes that occur in the scope of the model.
+	  The model may be implemented either in the kernel proper
+	  or exported to an external Trusted Modeling Agent (TMA).
+	  If you are unsure how to answer this question, answer N.
+
+config SECURITY_TSEM_ROOT_MODEL_PCR
+	int "TPM PCR index for root domain"
+	depends on SECURITY_TSEM
+	range 8 14
+	default 11
+	help
+	  This configuration variable determines the TPM Platform
+	  Configuration Register (PCR) that the coefficients of
+	  security events for the root modeling domain are extended
+	  into.  The default value is one register above the default
+	  value that IMA uses for its integrity measurements, in order
+	  to avoid a conflict between the two sub-systems.  If unsure,
+	  leave the value at its default value of 11.
diff --git a/security/tsem/Makefile b/security/tsem/Makefile
new file mode 100644
index 000000000000..d43cf2ae2142
--- /dev/null
+++ b/security/tsem/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SECURITY_TSEM) := tsem.o model.o namespace.o map.o event.o fs.o \
+	export.o trust.o
-- 
2.39.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH 01/13] Update MAINTAINERS file.
  2023-07-10 10:23 ` [PATCH 01/13] Update MAINTAINERS file Dr. Greg
@ 2023-07-10 20:00   ` Randy Dunlap
  2023-07-15 22:45     ` Dr. Greg
  0 siblings, 1 reply; 36+ messages in thread
From: Randy Dunlap @ 2023-07-10 20:00 UTC (permalink / raw)
  To: Dr. Greg, linux-security-module, linux-kernel, corbet

Hi,

On 7/10/23 03:23, Dr. Greg wrote:
> Add an entry to the MAINTAINERS file to document the maintainer's
> address and files relevant to the Trusted Security Event Modeling
> system (TSEM).
> 
> Signed-off-by: Greg Wettstein <greg@enjellic.com>
> ---
>  MAINTAINERS | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 35e19594640d..4660c972d5e3 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -19026,6 +19026,14 @@ F:	include/uapi/linux/selinux_netlink.h
>  F:	scripts/selinux/
>  F:	security/selinux/
>  
> +TSEM SECURITY MODULE
> +M:	Greg Wettstein <greg@enjellic.com>
> +S:	Maintained
> +L:	linux-security-module@vger.kernel.org
> +F:	Documentation/admin-guide/LSM/tsem.rst
> +F:	Documentation/ABI/testing/tsemfs
> +F:	security/tsem/
> +

Please insert entries in the MAINTAINERS file in alphabetical order
(as stated in that file).

Thanks.

>  SENSABLE PHANTOM
>  M:	Jiri Slaby <jirislaby@kernel.org>
>  S:	Maintained

-- 
~Randy

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/13] Add TSEM specific documentation.
  2023-07-10 10:23 ` [PATCH 02/13] Add TSEM specific documentation Dr. Greg
@ 2023-07-11  4:37   ` Randy Dunlap
  2023-07-17  0:36     ` Dr. Greg
  2023-08-08 18:48   ` Serge Hallyn
  2024-01-04  4:00   ` [PATCH 2/13] " Paul Moore
  2 siblings, 1 reply; 36+ messages in thread
From: Randy Dunlap @ 2023-07-11  4:37 UTC (permalink / raw)
  To: Dr. Greg, linux-security-module, linux-kernel, corbet

Hi--

On 7/10/23 03:23, Dr. Greg wrote:
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 9e5bab29685f..0e6640a78936 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -6468,6 +6468,24 @@
>  			with CPUID.16h support and partial CPUID.15h support.
>  			Format: <unsigned int>
>  

These 3 entries should be in alphabetical order: tsem_cache, tsem_digest, tsem_mode.

> +	tsem_mode=	[TSEM] Set the mode that the Trusted Security Event
> +			Modeling LSM is to run in.
> +			Format: 1
> +			1 -- Disable root domain modeling.
> +
> +	tsem_cache=	[TSEM] Define the size of the caches used to hold
> +			pointers to structures that will be used to model
> +			security events occurring in the root modeling
> +			namespace that are called in atomic context.
> +			Format: <integer>
> +			Default: 96

What unit?  KB, MB, bytes, pages?

> +
> +	tsem_digest=	[TSEM] Define the cryptographic hash function that
> +			will be used to create security event coefficients
> +			for in the root modeling namespace.

			for in
?

> +			Format: {name of the cryptographic hash function}
> +			Default: sha256

-- 
~Randy

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 01/13] Update MAINTAINERS file.
  2023-07-10 20:00   ` Randy Dunlap
@ 2023-07-15 22:45     ` Dr. Greg
  0 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-07-15 22:45 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: Dr. Greg, linux-security-module, linux-kernel

On Mon, Jul 10, 2023 at 01:00:58PM -0700, Randy Dunlap wrote:

> Hi,

Hi Randy, I hope your are having a good weekend.

> On 7/10/23 03:23, Dr. Greg wrote:
> > Add an entry to the MAINTAINERS file to document the maintainer's
> > address and files relevant to the Trusted Security Event Modeling
> > system (TSEM).
> > 
> > Signed-off-by: Greg Wettstein <greg@enjellic.com>
> > ---
> >  MAINTAINERS | 8 ++++++++
> >  1 file changed, 8 insertions(+)
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 35e19594640d..4660c972d5e3 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -19026,6 +19026,14 @@ F:	include/uapi/linux/selinux_netlink.h
> >  F:	scripts/selinux/
> >  F:	security/selinux/
> >  
> > +TSEM SECURITY MODULE
> > +M:	Greg Wettstein <greg@enjellic.com>
> > +S:	Maintained
> > +L:	linux-security-module@vger.kernel.org
> > +F:	Documentation/admin-guide/LSM/tsem.rst
> > +F:	Documentation/ABI/testing/tsemfs
> > +F:	security/tsem/
> > +

> Please insert entries in the MAINTAINERS file in alphabetical order
> (as stated in that file).

Fixed, my apologies for missing the note in the MAINTAINERS file.

> Thanks.
> -- 
> ~Randy

Have a good remainder of the weekend.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/13] Add TSEM specific documentation.
  2023-07-11  4:37   ` Randy Dunlap
@ 2023-07-17  0:36     ` Dr. Greg
  2023-07-17  1:56       ` Randy Dunlap
  0 siblings, 1 reply; 36+ messages in thread
From: Dr. Greg @ 2023-07-17  0:36 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: linux-security-module, linux-kernel

On Mon, Jul 10, 2023 at 09:37:10PM -0700, Randy Dunlap wrote:

> Hi--

Good morning, I hope the week is starting well for everyone.

> On 7/10/23 03:23, Dr. Greg wrote:
> > diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> > index 9e5bab29685f..0e6640a78936 100644
> > --- a/Documentation/admin-guide/kernel-parameters.txt
> > +++ b/Documentation/admin-guide/kernel-parameters.txt
> > @@ -6468,6 +6468,24 @@
> >  			with CPUID.16h support and partial CPUID.15h support.
> >  			Format: <unsigned int>
> >  

> These 3 entries should be in alphabetical order: tsem_cache,
> tsem_digest, tsem_mode.

Now alphabetized.

> > +	tsem_mode=	[TSEM] Set the mode that the Trusted Security Event
> > +			Modeling LSM is to run in.
> > +			Format: 1
> > +			1 -- Disable root domain modeling.
> > +
> > +	tsem_cache=	[TSEM] Define the size of the caches used to hold
> > +			pointers to structures that will be used to model
> > +			security events occurring in the root modeling
> > +			namespace that are called in atomic context.
> > +			Format: <integer>
> > +			Default: 96

> What unit?  KB, MB, bytes, pages?

Our apologies, we obviously erred in the notion that referring to the
size of a cache of pointers would be understood to mean the number of
pointers.

We updated the documentation as follows:

tsem_cache=	[TSEM] Define the size of the caches used to hold
		pointers to structures that will be used to model
		security events occurring in the root modeling
		namespace that are called in atomic context.  The
		value is the size of the arrays of pointers to the
		pre-allocated structures that will be maintained.
		For example, a value of 16 means each array would
		have 16 entries in it.
		Format: <integer>
		Default: 96

> > +
> > +	tsem_digest=	[TSEM] Define the cryptographic hash function that
> > +			will be used to create security event coefficients
> > +			for in the root modeling namespace.

> 			for in
> ?

That must have been an untoward effect of the single-malt.

The documentation has been updated to read as follows:

tsem_digest=	[TSEM] Define the cryptographic hash function that
		will be used to generate the security event
		coefficients in the root modeling namespace.
		Format: {name of the cryptographic hash function}
		Default: sha256

> > +			Format: {name of the cryptographic hash function}
> > +			Default: sha256
> 
> -- 
> ~Randy

Thank you for the review comments.

Have a good week.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/13] Add TSEM specific documentation.
  2023-07-17  0:36     ` Dr. Greg
@ 2023-07-17  1:56       ` Randy Dunlap
  0 siblings, 0 replies; 36+ messages in thread
From: Randy Dunlap @ 2023-07-17  1:56 UTC (permalink / raw)
  To: Dr. Greg; +Cc: linux-security-module, linux-kernel



On 7/16/23 17:36, Dr. Greg wrote:
> On Mon, Jul 10, 2023 at 09:37:10PM -0700, Randy Dunlap wrote:
> 
>> Hi--
> 
> Good morning, I hope the week is starting well for everyone.
> 
> 
> That must have been an untoward effect of the single-malt.
> 

Mine are more often from double or triple or imperial IPA. :)

> The documentation has been updated to read as follows:
> 

Thanks for the updates. They look good.

-- 
~Randy

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 03/13] Implement CAP_TRUST capability.
  2023-07-10 10:23 ` [PATCH 03/13] Implement CAP_TRUST capability Dr. Greg
@ 2023-08-07 20:21   ` Casey Schaufler
  2023-08-15 10:19     ` Dr. Greg
  0 siblings, 1 reply; 36+ messages in thread
From: Casey Schaufler @ 2023-08-07 20:21 UTC (permalink / raw)
  To: Dr. Greg, linux-security-module, linux-kernel, corbet, Casey Schaufler

On 7/10/2023 3:23 AM, Dr. Greg wrote:
> TSEM was designed to support a Trust Orchestration System (TOS)
> security architecture.  A TOS based system uses the concept of a
> minimum Trusted Computing Base of utilities, referred to as trust
> orchestrators, that maintain workloads in a trusted execution
> state.  The trust orchestrators are thus, from a security
> perspective, the most security privileged processes running on
> the platform.
>
> The CAP_ML (machine modeling) capability is defined as a
> capability that allows a process to alter the modeling and hence
> the trust status of the platform.  In a fully orchestrated system
> only the trust orchestrator carry this capability bit and then
> drop the capability for the execution of the workload.  This is
> designed to prevent a security vulnerability in workloads to be
> leveraged to create an entity that could conduct adversarial
> modifications to the trust status of the platform.
>
> With the introduction of TSEM there are three generic mechanisms
> for implementing security contols, each with its own capability
> bit for management, ie:
>
> DAC - CAP_DAC_ADMIN

There is no CAP_DAC_ADMIN. There are several capabilities related
to changing the DAC state of the system.

>
> MAC - CAP_MAC_ADMIN

Since your system implements a mandatory access control policy
you should be using CAP_MAC_ADMIN.

>
> Security modeling - CAP_ML

First, the name you've chosen makes no sense at all. It isn't descriptive
and fails even as an abbreviation. Second, you aren't doing anything that
wouldn't be covered under CAP_MAC_ADMIN.

>
> Having a separate capability bit for security modeling allows DAC
> and classic label or path based MAC systems to be implemented in
> the context of a security modeling namespace.  Looking forward it
> is not unreasonable to consider the implementation of a modeling
> policy that would verify the status of extended attributes being
> used for label based MAC controls.

It seems reasonable that being trusted with the privilege to change
the modeling policy would imply sufficient trust to change other
security states where allowed. As the Smack maintainer, and having
introduced CAP_MAC_ADMIN, I say that there's insufficient grounds to
introduce a new, single purpose capability.

>
> Signed-off-by: Greg Wettstein <greg@enjellic.com>
> ---
>  include/uapi/linux/capability.h     | 6 +++++-
>  security/selinux/include/classmap.h | 2 +-
>  2 files changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h
> index 3d61a0ae055d..4a17c9774505 100644
> --- a/include/uapi/linux/capability.h
> +++ b/include/uapi/linux/capability.h
> @@ -417,7 +417,11 @@ struct vfs_ns_cap_data {
>  
>  #define CAP_CHECKPOINT_RESTORE	40
>  
> -#define CAP_LAST_CAP         CAP_CHECKPOINT_RESTORE
> +/* Allow modifications to the trust status of the system */
> +
> +#define CAP_ML	41
> +
> +#define CAP_LAST_CAP         CAP_ML
>  
>  #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
>  
> diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
> index a3c380775d41..f367c269bbdb 100644
> --- a/security/selinux/include/classmap.h
> +++ b/security/selinux/include/classmap.h
> @@ -30,7 +30,7 @@
>  		"wake_alarm", "block_suspend", "audit_read", "perfmon", "bpf", \
>  		"checkpoint_restore"
>  
> -#if CAP_LAST_CAP > CAP_CHECKPOINT_RESTORE
> +#if CAP_LAST_CAP > CAP_ML
>  #error New capability defined, please update COMMON_CAP2_PERMS.
>  #endif
>  

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 04/13] Add TSEM master header file.
  2023-07-10 10:23 ` [PATCH 04/13] Add TSEM master header file Dr. Greg
@ 2023-08-07 20:39   ` Casey Schaufler
  2023-08-10  2:57     ` Dr. Greg
  0 siblings, 1 reply; 36+ messages in thread
From: Casey Schaufler @ 2023-08-07 20:39 UTC (permalink / raw)
  To: Dr. Greg, linux-security-module, linux-kernel, corbet, Casey Schaufler

On 7/10/2023 3:23 AM, Dr. Greg wrote:
> TSEM is designed, from a functional perspective, to be contained
> entirely in its own directory.
>
> The tsem.h header file defines the enumeration types, structure
> definitions and externally visiable functions that are referenced
> by all of the compilation units of the TSEM LSM implementation in
> that directory.

Extensive documentation notwithstanding, it's impossible to review
the data structures and constants without the code that goes along
with them.

>
> The structure and enumeration types are extensively documented
> and are the recommended starting point for understanding TSEM
> implementation and functionality.
>
> Signed-off-by: Greg Wettstein <greg@enjellic.com>
> ---
>  security/tsem/tsem.h | 1516 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 1516 insertions(+)
>  create mode 100644 security/tsem/tsem.h
>
> diff --git a/security/tsem/tsem.h b/security/tsem/tsem.h
> new file mode 100644
> index 000000000000..03915f47529b
> --- /dev/null
> +++ b/security/tsem/tsem.h
> @@ -0,0 +1,1516 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +/*
> + * Copyright (C) 2023 Enjellic Systems Development, LLC
> + * Author: Dr. Greg Wettstein <greg@enjellic.com>
> + *
> + * This is the single include file that documents all of the externally
> + * visible types and functions that are used by TSEM.  This file is
> + * currently organized into four major sections in the following order;
> + *
> + * includes used by all compilation units
> + * CPP definitions
> + * enumeration types
> + * structure definitions
> + * function declarations
> + * inline encapsulation functions.
> + *
> + * Include files that are referenced by more than a single compilation
> + * should be included in this file.  Includes that are needed to
> + * satisfy compilation requirements for only a single file should be
> + * included in the file needing that include.
> + *
> + * Understanding the overall implementation and architecture of TSEM
> + * will be facilitated by reviewing the documentation in this file.
> + */
> +
> +#include <uapi/linux/in.h>
> +#include <uapi/linux/in6.h>
> +#include <linux/wait.h>
> +#include <linux/kref.h>
> +#include <linux/lsm_hooks.h>
> +#include <linux/capability.h>
> +#include <crypto/hash.h>
> +#include <crypto/hash_info.h>
> +#include <net/af_unix.h>
> +
> +/* The capability needed to manage TSEM. */
> +#define TSEM_CONTROL_CAPABILITY CAP_ML

Why would you do this? You gave the capability a name that even you
don't want to use.

> +
> +/*
> + * The number of 'slots' in the structure magazines that are used to
> + * satisfy modeling of security events that are called in atomic context.
> + */
> +#define TSEM_ROOT_MAGAZINE_SIZE	96
> +#define TSEM_MAGAZINE_SIZE_INTERNAL 16
> +#define TSEM_MAGAZINE_SIZE_EXTERNAL 96
> +
> +/**
> + * enum tsem_event_type - Ordinal value for a security event.
> + * @TSEM_BPRM_SET_CREDS: Ordinal value for bprm_creds_for_exec.
> + * @TSEM_GENERIC_EVENT: Ordinal value for a generically modeled event.
> + * @TSEM_TASK_KILL: Ordinal value for task kill.
> + * @....: Remainder follows with a similar naming format that has
> + *        TSEM_ prep ended to the raw LSM security hook name.
> + * @TSEM_EVENT_CNT: The final ordinal value is used to define the
> + *		    length of the following arrays that are indexed
> + *		    by the ordinal value of the hook:
> + *
> + * This enumeration is used to designate an ordinal value for each
> + * security event, ie. LSM hook, that TSEM is implementing modeling
> + * for.  This value is used to identify the hook that is either having
> + * its event description being exported to an external Trusted Modeling
> + * Agent (TMA) or modeled by the internal TMA implementation.
> + *
> + * The primary use of this enumeration is to conditionalize code paths
> + * based on the security hook being processed and to index the
> + * tsem_names array and the array that defines the action that is to
> + * be taken in response to an event that generates a permissions
> + * violation.
> + */
> +enum tsem_event_type {
> +	TSEM_BPRM_SET_CREDS = 1,
> +	TSEM_GENERIC_EVENT,
> +	TSEM_TASK_KILL,
> +	TSEM_TASK_SETPGID,
> +	TSEM_TASK_GETPGID,
> +	TSEM_TASK_GETSID,
> +	TSEM_TASK_SETNICE,
> +	TSEM_TASK_SETIOPRIO,
> +	TSEM_TASK_GETIOPRIO,
> +	TSEM_TASK_PRLIMIT,
> +	TSEM_TASK_SETRLIMIT,
> +	TSEM_TASK_SETSCHEDULER,
> +	TSEM_TASK_GETSCHEDULER,
> +	TSEM_TASK_PRCTL,
> +	TSEM_FILE_OPEN,
> +	TSEM_MMAP_FILE,
> +	TSEM_FILE_IOCTL,
> +	TSEM_FILE_LOCK,
> +	TSEM_FILE_FCNTL,
> +	TSEM_FILE_RECEIVE,
> +	TSEM_UNIX_STREAM_CONNECT,
> +	TSEM_UNIX_MAY_SEND,
> +	TSEM_SOCKET_CREATE,
> +	TSEM_SOCKET_CONNECT,
> +	TSEM_SOCKET_BIND,
> +	TSEM_SOCKET_ACCEPT,
> +	TSEM_SOCKET_LISTEN,
> +	TSEM_SOCKET_SOCKETPAIR,
> +	TSEM_SOCKET_SENDMSG,
> +	TSEM_SOCKET_RECVMSG,
> +	TSEM_SOCKET_GETSOCKNAME,
> +	TSEM_SOCKET_GETPEERNAME,
> +	TSEM_SOCKET_SETSOCKOPT,
> +	TSEM_SOCKET_SHUTDOWN,
> +	TSEM_PTRACE_TRACEME,
> +	TSEM_KERNEL_MODULE_REQUEST,
> +	TSEM_KERNEL_LOAD_DATA,
> +	TSEM_KERNEL_READ_FILE,
> +	TSEM_SB_MOUNT,
> +	TSEM_SB_UMOUNT,
> +	TSEM_SB_REMOUNT,
> +	TSEM_SB_PIVOTROOT,
> +	TSEM_SB_STATFS,
> +	TSEM_MOVE_MOUNT,
> +	TSEM_SHM_ASSOCIATE,
> +	TSEM_SHM_SHMCTL,
> +	TSEM_SHM_SHMAT,
> +	TSEM_SEM_ASSOCIATE,
> +	TSEM_SEM_SEMCTL,
> +	TSEM_SEM_SEMOP,
> +	TSEM_SYSLOG,
> +	TSEM_SETTIME,
> +	TSEM_QUOTACTL,
> +	TSEM_QUOTA_ON,
> +	TSEM_MSG_QUEUE_ASSOCIATE,
> +	TSEM_MSG_QUEUE_MSGCTL,
> +	TSEM_MSG_QUEUE_MSGSND,
> +	TSEM_MSG_QUEUE_MSGRCV,
> +	TSEM_IPC_PERMISSION,
> +	TSEM_KEY_ALLOC,
> +	TSEM_KEY_PERMISSION,
> +	TSEM_NETLINK_SEND,
> +	TSEM_INODE_CREATE,
> +	TSEM_INODE_LINK,
> +	TSEM_INODE_UNLINK,
> +	TSEM_INODE_SYMLINK,
> +	TSEM_INODE_MKDIR,
> +	TSEM_INODE_RMDIR,
> +	TSEM_INODE_MKNOD,
> +	TSEM_INODE_RENAME,
> +	TSEM_INODE_SETATTR,
> +	TSEM_INODE_GETATTR,
> +	TSEM_INODE_SETXATTR,
> +	TSEM_INODE_GETXATTR,
> +	TSEM_INODE_LISTXATTR,
> +	TSEM_INODE_REMOVEXATTR,
> +	TSEM_INODE_KILLPRIV,
> +	TSEM_TUN_DEV_CREATE,
> +	TSEM_TUN_DEV_ATTACH_QUEUE,
> +	TSEM_TUN_DEV_ATTACH,
> +	TSEM_TUN_DEV_OPEN,
> +	TSEM_BPF,
> +	TSEM_BPF_MAP,
> +	TSEM_BPF_PROG,
> +	TSEM_EVENT_CNT
> +};
> +
> +/**
> + * enum tsem_action_type - Ordinal value for security responses.
> + * @TSEM_ACTION_LOG: Ordinal value to indicate that a security event
> + *		     that results in a model permissions violation
> + *		     should be logged.
> + * @TSEM_ACTION_EPERM: Ordinal value to indicate that a security event
> + *		       generating a model permissions violation should
> + *		       return -EPERM to the caller.
> + *
> + * This enumeration type is used to designate what type of action is
> + * to be taken when the processing of a security event hook results in
> + * a model violation.  The TSEM_ACTION_LOG and TSEM_ACTION_EPERM
> + * translate into the classical concepts of logging or enforcing
> + * actions used by other mandatory access control architectures.
> + */
> +enum tsem_action_type {
> +	TSEM_ACTION_LOG = 0,
> +	TSEM_ACTION_EPERM,
> +	TSEM_ACTION_CNT
> +};
> +
> +/**
> + * enum tsem_control_type - Ordinal values for TSEM control actions.
> + * @TSEM_CONTROL_INTERNAL: This ordinal value is set when the first
> + *			   word of an argument string written to the
> + *			   control file is the word 'internal'.  This
> + *			   designates that the security namespace will
> + *			   be modeled by the internal TMA.
> + * @TSEM_CONTROL_EXTERNAL: This ordinal value is set when the first
> + *			   word of an argument string written to the
> + *			   control file is the word 'external'.  This
> + *			   designates that the security namespace will
> + *			   be model by an external TMA.
> + * @TSEM_CONTROL_ENFORCE: This ordinal value is set when the word
> + *			  'enforce' is written to the control file.
> + *			  This indicates that model is to be placed
> + *			  in 'enforcing' mode and security events that
> + *			  result in model violations will return EPERM.
> + * @TSEM_CONTROL_SEAL: This ordinal value is set when the word 'seal'
> + *		       is written to the control file.  This indicates
> + *		       that the model for security domain will treat
> + *		       all security events that do not conform to the
> + *		       model as 'forensics' events.
> + * @TSEM_CONTROL_TRUSTED: This ordinal value is used when the first
> + *			  word of an argument string written to the
> + *			  control file is the word 'trusted'.  This
> + *			  is interpreted as a directive to set the
> + *			  trust status of the task that executed the
> + *			  security event to be trusted.
> + * @TSEM_CONTROL_UNTRUSTED: This ordinal value is used when the first
> + *			    word of an argument string written to the
> + *			    control file is the word 'untrusted'.
> + *			    This is interpreted as a directive to set
> + *			    the trust status of the task that executed
> + *			    the security event to be untrusted.
> + * @TSEM_CONTROL_MAP_STATE: This ordinal value is used when the first
> + *			    word of an argument string written to the
> + *			    control file is the word 'state'.  The
> + *			    argument to this directive will be an
> + *			    ASCII hexadecimally encoded string of the
> + *			    current model's digest size that will be
> + *			    treated as a security state point for
> + *			    inclusion in the security model for the
> + *			    security domain/namespace.
> + * @TSEM_CONTROL_MAP_PSEUDONYM: This ordinal value is used when the
> + *				first word of an argument string
> + *				written to the control file is the
> + *				word 'pseudonym'.  The argument to
> + *				this directive will be an ASCII
> + *				hexadecimally encoded string of the
> + *				current model's digest size that will
> + *				be treated as a pseudonym directive
> + *				for the security domain/namespace.
> + * TSEM_CONTROL_MAP_BASE: This ordinal value is used when the first
> + *			  word of an argument string written to the
> + *			  control file is the word 'base'.  The
> + *			  argument to this directive will be an ASCII
> + *			  hexadecimally encoded string of the current
> + *			  model's digest size that will be treated as
> + *			  the base value for the computation of the
> + *			  functional values (measurement and state) of
> + *			  the security domain/namespace.
> +
> + * This enumeration type is used to designate what type of control
> + * action is to be implemented when arguments are written to the TSEM
> + * control file (/sys/kernel/security/tsem/control).  The ordinal
> + * values govern the processing of the command and the interpretation
> + * of the rest of the command argument string.
> + */
> +enum tsem_control_type {
> +	TSEM_CONTROL_INTERNAL = 0,
> +	TSEM_CONTROL_EXTERNAL,
> +	TSEM_CONTROL_ENFORCE,
> +	TSEM_CONTROL_SEAL,
> +	TSEM_CONTROL_TRUSTED,
> +	TSEM_CONTROL_UNTRUSTED,
> +	TSEM_CONTROL_MAP_STATE,
> +	TSEM_CONTROL_MAP_PSEUDONYM,
> +	TSEM_CONTROL_MAP_BASE
> +};
> +
> +/**
> + * enum tsem_ns_reference - Ordinal value for DAC namespace reference.
> + * @TSEM_NS_INITIAL: This ordinal value indicates that the uid/gid
> + *		     values should be interpreted against the initial
> + *		     user namespace.
> + * @TSEM_NS_CURRENT: This ordinal value indicates that the uid/gid
> + *		     values should be interpreted against the user
> + *		     namespace that is in effect for the process being
> + *		     modeled.
> + *
> + * This enumeration type is used to indicate what user namespace
> + * should be referenced when the uid/gid values are interpreted for
> + * the creation of either the COE or CELL identities.  The enumeration
> + * ordinal passed to the tsem_ns_create() function, to configure the
> + * security domain/namespace, is set by the nsref argument to either
> + * the 'internal' or 'external' control commands.
> + */
> +enum tsem_ns_reference {
> +	TSEM_NS_INITIAL = 1,
> +	TSEM_NS_CURRENT
> +};
> +
> +/**
> + * enum tsem_task_trust - Ordinal value describing task trust status.
> + * @TSEM_TASK_TRUSTED: This ordinal value indicates that the task has
> + *		       not executed a security event that has resulted
> + *		       in a security behavior not described by the
> + *		       security model the task is being governed by.
> + * @TSEM_TASK_UNTRUSTED: This ordinal value indicates that the task
> + *		          has requested the execution of a security event
> + *		          that resulted in a security behavior not
> + *		          permitted by the security model the task is
> + *		          being governed by.
> + * @TSEM_TASK_TRUST_PENDING: This ordinal value indicates that the setting
> + *			     of the task trust status is pending a response
> + *		             from an external TMA.
> + *
> + * This enumeration type is used to specify the three different trust
> + * states that a task can be in.  The trust status of a task is
> + * regulated by the trust_status member of struct tsem_task.  A task
> + * carrying the status of TSEM_TASK_TRUSTED means that it has
> + * not requested the execution of any security events that are
> + * inconsistent with the security model that the task is running in.
> + *
> + * If a task requests execution of a security event that is
> + * inconsistent with the security model it is operating in, and the
> + * domain is running in 'sealed' mode, the task trust status is set to
> + * TSEM_TASK_UNTRUSTED.  This value is 'sticky' in that it will be
> + * propagated to any child tasks that are spawned from an untrusted
> + * task.
> + *
> + * In the case of an externally modeled security domain/namespace, the
> + * task trust status cannot be determined until the modeling of the
> + * security event has been completed.  The tsem_export_event()
> + * function sets the trust status TSEM_TASK_TRUST_PENDING and then
> + * places the task into an interruptible sleep state.
> + *
> + * Only two events will cause the task to be removed from sleep state.
> + * Either the task is killed or a control message is written to the
> + * TSEM control file that specifies the trust status of the task.  See
> + * the description of the TSEM_CONTROL_TRUSTED and
> + * TSEM_CONTROL_UNTRUSTED enumeration types.
> + */
> +enum tsem_task_trust {
> +	TSEM_TASK_TRUSTED = 1,
> +	TSEM_TASK_UNTRUSTED = 2,
> +	TSEM_TASK_TRUST_PENDING = 4

What happened to 3?

> +};
> +
> +/**
> + * enum tsem_inode_state - Ordinal value for inode reference state.
> + * @TSEM_INODE_COLLECTING: This ordinal value indicates that the uid/gid
> + *			   values should be interpreted against the initial
> + *			   user namespace.
> + * @TSEM_INODE_COLLECTED: This ordinal value indicates that the uid/gid
> + *			  values should be interpreted against the user
> + *			  namespace that is in effect for the process being
> + *		          modeled.
> + *
> + * This enumeration type is used to specify the status of the inode
> + * that is having a digest value computed on the file that it is
> + * referencing.  The purpose of this enumeration is so that the
> + * recursive call to the TSEM_FILE_OPEN hook, caused by the kernel
> + * opening the file to compute the checksum, can be bypassed.
> + *
> + * The state value of the inode is carried in struct tsem_inode and is
> + * set and interrogated by the add_file_digest() function.  If the
> + * status of the inode is TSEM_INODE_COLLECTED and the iversion of the
> + * inode is the same as the collection time, the cached value for
> + * currently active model digest is returned.
> +
> + * If the test for the relevancy of the cached digest value fails the
> + * status of the inode is set to TSEM_INODE_COLLECTING.  The
> + * tsem_file_open() function will check the inode status when it is
> + * invoked by the integrity_kernel_read() function and if it is
> + * set to 'collecting', a successful permissions check is returned so
> + * that the kernel can open the file and compute its digest.
> + */
> +enum tsem_inode_state {
> +	TSEM_INODE_COLLECTING = 1,
> +	TSEM_INODE_COLLECTED
> +};
> +
> +/**
> + * struct tsem_task - TSEM task control structure.
> + * @tma_for_ns: The context identity number of the namespace that
> + *		the task has control over if any.
> + * @trust_status: The enumeration type that specifies the trust state of
> + *		  the process.
> + * @task_id: The hash specific digest that identifies the process.
> + * @task_key: A hash specific digest value that is used to
> + *	      authenticate a task that is running as a trust
> + *	      orchestrator to a task that is under the control of the
> + *	      orchestrator.
> + * @context: A pointer to the tsem_context structure that defines the
> + *	     modeling context that the task is running under.
> + *
> + * This structure is one of the two primary control structures that
> + * are implemented through the LSM blob functionality.  It is
> + * automatically created when the task control structure is allocated
> + * for a new task that is being created.  It's role is to control the
> + * status of the task with respect to its security model.
> + *
> + * The trust_status member of structure determines whether or not the
> + * task is in a condition to be trusted.  It represents whether or not
> + * the task has requested execution of a security event that is
> + * inconsistent with the model that the task is running under.
> + * Reference the tsem_trust_status enumeration type for more
> + * information on this member.  The trust status value is propagated
> + * to any child tasks that are spawned from a task.
> + *
> + * The digest value that the task_id member contains is generated by
> + * the tsem_tsem_bprm_creds_for_exec() function that computes the
> + * task identity based on the COE identity and the CELL identity of
> + * the executable that is being started.  This task_id value is used
> + * in the computation of the security state point values in
> + * combination with the COE and CELL identities for this event.  The
> + * task_id digest creates security state points that are specific to
> + * the executable file that was used to start the task.
> + *
> + * The task_key member holds the authentication key that will be used
> + * to authenticate a process that is requesting the ability to set the
> + * trust status of a process.  This value is generated for the task
> + * structure of the trust orchestrator when a security modeling
> + * namespace is created by the orchestrator.
> + *
> + * As an additional protection, the creation of a namespace causes the
> + * context id of the created namespace to be placed in the task that
> + * will serve as the trust orchestrator for the namespace.  This
> + * context id must match the context id of a process that a trust
> + * control request is being sent to.  Like the authentication key
> + * this value is not propagated on task allocation so only the task
> + * that has nominated the security modeling namespace will have
> + * possession of the necessary credentials to control it.
> + *
> + * The context member of the structure contains a pointer to the
> + * tsem_context structure allocated when a security modeling namespace
> + * is created by the tsem_ns_create() function.  This structure will
> + * contain all of the information needed to define how the task is to
> + * have its security behavior modeled.
> + */
> +struct tsem_task {
> +	u64 tma_for_ns;
> +	enum tsem_task_trust trust_status;
> +	u8 task_id[HASH_MAX_DIGESTSIZE];
> +	u8 task_key[HASH_MAX_DIGESTSIZE];
> +	struct tsem_context *context;
> +};
> +
> +/**
> + * struct tsem_context - TSEM modeling context description.
> + * @kref: Reference count for the context.
> + * @work: Work structure for delayed release of the context.
> + * @id: The index number of the context.
> + * @sealed: Status variable indicating whether or not the
> + *	    modeling context can be modified.
> + * @use_current_ns: Status variable indicating which user namespace
> + *		    should be used for resolution of uid/gid values.
> + * @actions: An array of enum tsem_action_type variables indicating
> + *	     the type of response that should be returned in
> + *	     response to the modeling of a security event that
> + *	     is inconsistent with the model being used for the
> + *	     security context.
> + * @digestname: A pointer to a null-terminated buffer containing the
> + *		name of the digest function that is to be used for
> + *		this security context.
> + * @zero_digest: The digest value for a 'zero-length' digest value.
> + * @tfm: A pointer to the digest transformation structure that is to
> + *	 be used for this context.
> + * @magazine_size: The number of struct tsem_event structures that
> + *		   are held in reserve for security event hooks that
> + *		   are called in atomic context.
> + * @magazine_lock: The spinlock that protects access to the event
> + *		   magazine for the security context.
> + * @magazine_index: The bitmap that is used to track the magazine slots
> + *		    that have been allocated.
> + * @ws: An array of work structures that are used to refill the magazine
> + *	slots.
> + * @magazine: An array of pointers to struct tsem_event structures that
> + *	      are pre-allocated for security hooks called in atomic
> + *	      context.
> + * @model: If the modeling context is implemented with a kernel based
> + *	   trusted model agent this pointer will point to the struct
> + *	   tsem_model structure that maintains the state of the
> + *	   security model.
> + * @external: If the modeling context is implemented with an external
> + *	      modeling agent this pointer will point to the struct
> + *	      tsem_external structure that implements the interface to
> + *	      the external trusted modeling agent.
> +
> + * This structure is used to represent the state of a TSEM security
> + * modeling namespace.  A pointer to this structure is stored in the
> + * struct tsem_task structure.
> + *
> + * This structure is allocated by the tsem_ns_create() function in
> + * response to a TSEM control request.  This structure maintains all
> + * of the information that describes the security modeling namespace
> + * that is not specific to the type of namespace, ie. external or
> + * internal that is being implemented.
> +
> + * The id member is a 64-bit counter that cannot feasibly be
> + * overflowed and that is incremented for each namespace creation that
> + * is created.  The root modeling namespace has a value of zero so the
> + * TSEM code uses a pattern of testing this value for non-zero status
> + * as an indication of whether or not the task is running in a
> + * subordinate modeling namespace.
> +
> + * Each security modeling namespace can have an independent
> + * cryptographic digest function that is used as the compression
> + * function for generating the digest values that are used to model
> + * the security events that occur in a namespace.  A single struct tfm
> + * is allocated for this digest function at the time that the
> + * tsem_context structure is created and is maintained in this
> + * structure for subsequent use during event processing.
> +
> + * Each cryptographic digest function has a 'zero message' value that
> + * is the result of the initialization and closure of a hash function
> + * that has no other input.  This zero digest value is computed at the
> + * time of the creation of the array.  This digest value is returned
> + * for files with zero sizes or that have pseudonyms declared for
> + * them.
> + *
> + * The actions array contains a specification of how each security
> + * event should be handled in the event that the model detects a
> + * security event consistent with the model designated for the
> + * namespace.  This array allows the specification of whether the
> + * model should be enforcing or logging.  Currently the specification
> + * is all or nothing for all of the events, with plans to make the
> + * actions individually configurable.
> +
> + * Each security event that is processed requires a struct tsem_event
> + * structure that drives either the internal modeling of an event or
> + * its export to an external modeling agent.  Some security event
> + * hooks are called while a task is running in atomic context. Since
> + * memory cannot be allocated while a process is in atomic context, a
> + * magazine of these structures is maintained by this structure for
> + * security events that run in atomic context.  The size of this
> + * magazine is dynamic and is configurable for each security modeling
> + * namespace that is created.
> + *
> + * When a tsem_event structure is allocated for an atomic event a
> + * request for the refill of the slot that is vacated is dispatched to
> + * an asynchronous workqueue.  The ws member of this structure points
> + * to an array of work structures for this refill capability, one for
> + * each slot in the magazine.
> + *
> + * All of this infrastructure is generic for each security modeling
> + * namespace.  How the security modeling is done is governed by the
> + * model and external members of this structure.  These members point
> + * to data structures that either maintain the security model state
> + * for an in kernel trusted modeling agent or handle the export of the
> + * event to an external trusted modeling agent.
> + *
> + * Each task that is created in a non-root security modeling namespace
> + * increments the reference count maintained in the kref member of
> + * this structure in the tsem_task_alloc() function.  The
> + * tsem_task_free() function decrements this reference count.  When
> + * the reference count expires, ie. when the last task using the
> + * modeling namespace exits, an asynchronous workqueue request is
> + * dispatched to dispose of the context.  The work member of this
> + * structure is used to reference that workqueue request.
> + */
> +struct tsem_context {
> +	struct kref kref;
> +	struct work_struct work;
> +
> +	u64 id;
> +	bool sealed;
> +	bool use_current_ns;
> +
> +	enum tsem_action_type actions[TSEM_EVENT_CNT];
> +
> +	char *digestname;
> +	u8 zero_digest[HASH_MAX_DIGESTSIZE];
> +	struct crypto_shash *tfm;
> +
> +	unsigned int magazine_size;
> +	spinlock_t magazine_lock;
> +	unsigned long *magazine_index;
> +	struct tsem_work *ws;
> +	struct tsem_event **magazine;
> +
> +	struct tsem_model *model;
> +	struct tsem_external *external;
> +};

Odd use of whitespace in the structure definition.

> +
> +/**
> + * struct tsem_model - TSEM internal TMA description.
> + * @have_aggregate: Flag variable to indicate whether or not the
> + *		    hardware aggregate value has been injected into
> + *		    the mode.
> + * @base: The base value that is to be used in computing the
> + *	  measurement and state values of the model.
> + * @measurement: The time dependent linear extension state of the
> + *		 model.
> + * @state: The time independent linear extension state of the model.
> + * @point_lock: The spinlock that protects access to the list of
> + *		security state coefficients in the model.
> + * @point_list: A pointer to the list of security state coefficients
> + *		in the model.
> + * @point_end_mutex: The mutex that is used to protect the end of the
> + *		     list of security state coefficients for the
> + *		     model.
> + * @point_end: A pointer to the end of the list of security state
> + *	       coefficients that will be traversed by a call to the
> + *	       control plane.
> + * @trajectory_lock: The spinlock used to protect the list of security
> + *		     event descriptions in the model.
> + * @trajectory_list: A pointer to the list of descriptions of the
> + *		     security events that have been recorded in this
> + *		     model.
> + * @trajectory_end_mutex: The mutex that protects the end of the list
> + *			  of security event descriptions.
> + * @trajectory_end: A pointer to the end of the list of security event
> + *		    descriptions that will be traversed by a call to
> + *		    the control plane.
> + * @forensics_lock: The spinlock used to protect the list of security
> + *		    event descriptions that are considered invalid by
> + *		    the model being enforced.
> + * @forensics_list: A pointer to the list of descriptions of security
> + *		    events that are considered invalid by the security
> + *		    model being enforced.
> + * @forensics_end_mutex: The mutex that protects the end of the list
> + *			 of security event descriptions that are
> + *			 considered invalid by the current model.
> + * @forensics_end: A pointer to the end of the list of security event
> + *		   descriptions, that are considered invalid, that are
> + *		   to be traversed by a call to the control plane.
> + * @pseudonym_mutex: The mutex lock that protects the list of file
> + *		     digest pseudonyms for the current model.
> + * @pseudonum_list: A pointer to the list of file digest pseudonyms
> + *		    that have been declared for the current model.
> + * @magazine_size: The number of struct tsem_event_point structures that
> + *		   are held in reserve for security event hooks that
> + *		   are called in atomic context.
> + * @magazine_lock: The spinlock that protects access to the event
> + *		   magazine for the security context.
> + * @magazine_index: The bitmap that is used to track the magazine slots
> + *		    that have been allocated.
> + * @ws: An array of work structures that are used to refill the magazine
> + *	slots.
> + * @magazine: An array of pointers to struct tsem_event_point structures that
> + *	      are pre-allocated for security hooks called in atomic
> + *	      context.
> + *
> + * If a call to the tsem_ns_create() function specifies that a kernel
> + * based trusted modeling agent is to be used to implement the
> + * security namespace model, a pointer to this structure is placed in
> + * the struct tsem_context structure.  This structure is used to
> + * maintain the state of the kernel based model.
> + *
> + * There are two primary functional values that are maintained by the
> + * model.  The measurement member of this structure represents the
> + * time dependent linear extension sum of the security state
> + * coefficients that have been assigned to security events that have
> + * occurred in the context of the model.
> + *
> + * This classic integrity measurement is subject to scheduling
> + * dependencies and may be invariant from run to run of the model.  It
> + * is of primary use in verifying the order of security events that
> + * have occurred in the model.
> + *
> + * The state member of this structure represents a time independent
> + * linear extension sum of the security state coefficients that have
> + * been generated in the model.  It represents the linear extension
> + * sum of the security state coefficients that have been sorted in
> + * natural (big-endian) form.
> + *
> + * Both of these measurements are dependent on the platform hardware
> + * aggregate value and the base point that has been defined for the
> + * define.
> + *
> + * A non-zero hardware aggregate value is only available if the
> + * platform has a TPM.  The have_aggregate member of this structure is
> + * a flag variable that indicates whether or not the aggregate value
> + * has been injected into the model.
> + *
> + * The base member of this structure contains a model specific
> + * coefficient that is used to perturb each security state coefficient
> + * generated in the model.  This value is designed to serve as a
> + * 'freshness' value for a verifying party to the model.
> + *
> + * There are three primary model lists maintain by this structure:
> + *
> + * * security state points
> + * * security trajectory events
> + * * security forensics events
> + *
> + * Similar members are maintained in this structure to support each of
> + * these lists.
> + *
> + * All three lists are extension only and are protected by a spinlock
> + * that can be held in atomic context.  This spinlock is only held for
> + * the period of time required to extend the list.
> + *
> + * Calls by the control plane to interrogate the lists require the
> + * traversal of the list that is ill-suited for a spinlock.  As a
> + * result each list type has a mutex associated with it that protects
> + * a pointer to the end of the list, an endpoint that is determined at
> + * the start of a call to the control plane.
> + *
> + * The list spinlock is used at the start of the control plane call to
> + * capture the end of the list that is then protected by the mutex.
> + * In essence this is used to transition protection of the list from
> + * the spinlock to the mutex.
> + *
> + * The kernel based modeling agent has support for maintaining a
> + * constant digest value for files, that by function, do not have a
> + * fixed digest value, such as log files.  The pseudonym_list member
> + * of this structure points to the list of these designations.  The
> + * pseudonym_mutex structure protects this list.
> + *
> + * Like the struct tsem_context structure the tsem_model structure
> + * maintains a magazine of structures that are used to service
> + * security events that are called in atomic context.  The magazine
> + * maintained by this structure is a list of struct tsem_event_point
> + * structures that are used to describe the security state
> + * coefficients held by the model.
> + *
> + * The description of struct tsem_context details the implementation
> + * of the magazine which is identical to the implementation for this
> + * structure, with the exception of the type of structures that are
> + * held in reserve.
> + */
> +struct tsem_model {
> +	bool have_aggregate;
> +
> +	u8 base[HASH_MAX_DIGESTSIZE];
> +	u8 measurement[HASH_MAX_DIGESTSIZE];
> +	u8 state[HASH_MAX_DIGESTSIZE];
> +
> +	spinlock_t point_lock;
> +	struct list_head point_list;
> +	struct mutex point_end_mutex;
> +	unsigned int point_count;
> +	struct list_head *point_end;
> +
> +	spinlock_t trajectory_lock;
> +	struct list_head trajectory_list;
> +	struct mutex trajectory_end_mutex;
> +	struct list_head *trajectory_end;
> +
> +	spinlock_t forensics_lock;
> +	struct list_head forensics_list;
> +	struct mutex forensics_end_mutex;
> +	struct list_head *forensics_end;
> +
> +	struct mutex pseudonym_mutex;
> +	struct list_head pseudonym_list;
> +
> +	unsigned int magazine_size;
> +	spinlock_t magazine_lock;
> +	unsigned long *magazine_index;
> +	struct tsem_work *ws;
> +	struct tsem_event_point **magazine;
> +};
> +
> +/**
> + * struct tsem_external - TSEM external TMA description.
> + * @export_lock: The spinlock that protects access to the export_list
> + *		 member of this structure.
> + * @export_list: A pointer to the list of events waiting to be
> + *		 exported to the trust orchestrator for the security
> + *		 modeling namespace.  The structure type that is
> + *		 linked by this list is the struct export_event
> + *		 structure that is private to the export.c compilation
> + *		 unit.
> + * @dentry: A pointer to the dentry describing the pseudo-file in the
> + *	    /sys/kernel/security/tsem/ExternalTMA directory that is
> + *	    being used to export security event descriptions to the
> + *	    external trust orchestrator for the security modeling
> + *	    domain described by this structure.
> + * @have_event: A flag variable to indicate that there is work queued
> + *		on the export pseudo-file for the security modeling
> + *		namespace.
> + * @wq: The work queue used to implement polling for the security
> + *	event export file for the security modeling namespace.
> + * @magazine_size: The number of struct export_event structures that
> + *		   are held in reserve for security event hooks that
> + *		   are called in atomic context.
> + * @magazine_lock: The spinlock that protects access to the event
> + *		   magazine for the security modeling domain.
> + * @magazine_index: The bitmap that is used to track the magazine slots
> + *		    that have been allocated.
> + * @ws: An array of work structures that are used to refill the magazine
> + *	slots.
> + * @magazine: An array of pointers to struct export_event structures that
> + *	      are pre-allocated for security hooks called in atomic
> + *	      context.
> + *
> + * If an externally modeled security modeling namespace is created
> + * a structure of this type is allocated for the namespace and placed
> + * in the struct tsem_context structure.
> + *
> + * The primary purpose of this structure is to manage event
> + * descriptions that are being transmitted to the trust orchestrator
> + * associated with the security modeling namespace.  The pseudo-file
> + * will be as follows:
> + *
> + * /sys/kernel/security/tsem/ExternalTMA/N
> + *
> + * Where N is the context id number of the modeling namespace.
> + *
> + * The dentry member of this structure is used to represent the
> + * pseudo-file that is created when the external modeled namespace is
> + * created.
> + *
> + * This list of events waiting to be received by the trust
> + * orchestrator is maintained in the export_list member of this
> + * structure.  Additions or removals from the list hold the spinlock
> + * described by the export_lock member of this structure.
> + *
> + * The wq member of this structure is used to implement a workqueue
> + * to support polling for events on the export control file.  The
> + * have_event flag is set to indicate to the polling call that
> + * security events are available for export.
> + *
> + * When a security event description is exported the calling task is
> + * scheduled away to allow the trust orchestrator to process the
> + * event.  This obviously creates issues for security events that are
> + * called in atomic context.
> + *
> + * Security events in atomic context are exported as an async_event
> + * rather than a simple event.  The trust orchestrator has the option
> + * of killing the workload that deviated from the security model or
> + * signaling a violation of the model.
> + *
> + * To support the export of asynchronous events a magazine, similar to
> + * the event and model structure magazines, is maintained by this
> + * structure for the external modeling namespace.
> + */
> +struct tsem_external {
> +	spinlock_t export_lock;
> +	struct list_head export_list;
> +	struct dentry *dentry;
> +	bool have_event;
> +	wait_queue_head_t wq;
> +
> +	unsigned int magazine_size;
> +	spinlock_t magazine_lock;
> +	unsigned long *magazine_index;
> +	struct tsem_work *ws;
> +	struct export_event **magazine;
> +};
> +
> +/**
> + * struct tsem_work - TSEM magazine refill work structure.
> + * @index: The index number of the slot in the structure magazine that
> + *	   is being refilled.
> + * @u: A union that holds pointers to the structure whose magazine is
> + *     being refilled.
> + * @work: The work structure that manages the workqueue being used to
> + *	  refill the magazine entry.
> + *
> + * As has been previously documented for the struct tsem_context,
> + * struct tsem_model and struct tsem_external structures, there is a
> + * need to maintain a magazine of these structures in order to allow
> + * the processing of security events that are called in atomic
> + * context.  An array of this structure type is embedded in each of
> + * these structures to manage the asynchronous refill of the slot in
> + * the magazine that was used to handle an atomic security event.
> + *
> + * The index member of this structure points to the slot in the
> + * magazine that this work item is referencing.
> + *
> + * The structure that the refill work is being done for is maintained
> + * in the respective structure pointer in the u member of this
> + * structure.
> + *
> + * The work member of this structure is used to reference the
> + * asynchronous work request that is being submitted for the refill.
> + */
> +struct tsem_work {
> +	unsigned int index;
> +	union {
> +		struct tsem_context *ctx;
> +		struct tsem_model *model;
> +		struct tsem_external *ext;
> +	} u;
> +	struct work_struct work;
> +};
> +
> +/**
> + * struct tsem_COE - TSEM context of execution definition structure.
> + * @uid: The numeric user identity that the COE is running with.
> + * @euid: The effective user identity that the COE is running with.
> + * @suid: The saved user identity possessed by the COE.
> + * @gid: The group identity that the COE is running with.
> + * @egid: The effective group identity that the COE possesses.
> + * @sgid: The saved group identity of the COE.
> + * @fsuid: The filesystem user identity that the COE is running with.
> + * @fsgid: The filesystem group identity that the COE is running with.
> + * @capeff: This union is used to implement access to the effective
> + *	    capability set the COE is running with.  The mask value
> + *	    is used to assign to the structure with the value member
> + *	    used to extract the 64 bit value for export and
> + *	    computation.
> + *
> + * A security state coefficient is computed from two primary entities:
> + * the COE and the CELL identities.  This structure is used to carry
> + * and encapsulate the characteristics of the context of execution
> + * (COE) that will be used to generate the COE identity.
> + *
> + * The numeric values for discretionary access controls, ie. uid, gid,
> + * are determined by which user namespace the security modeling
> + * namespace is configured to reference.  The reference will be either
> + * the initial user namespace or the user namespace that the context
> + * of execution is running in.
> + */
> +struct tsem_COE {
> +	uid_t uid;
> +	uid_t euid;
> +	uid_t suid;
> +
> +	gid_t gid;
> +	gid_t egid;
> +	gid_t sgid;
> +
> +	uid_t fsuid;
> +	gid_t fsgid;
> +
> +	union {
> +		kernel_cap_t mask;
> +		u64 value;
> +	} capeff;
> +};
> +
> +/**
> + * struct tsem_COE - TSEM file description.
> + * @uid: The numeric user identity of the file.
> + * @gid: The numeric group identity of the file.
> + * @mode: The discretionary access mode for the file.
> + * @flags: The file control flags.
> + * @name_length: The length of the pathname of the file.
> + * @name: The digest value of the pathname of the file using the
> + *	  hash function defined for the security modeling namespace.
> + * @s_magic: The magic number of the filesystem that the file resides
> + *	     in.
> + * @s_id: The name of the block device supporting the filesystem.
> + * @s_uuid: The uuid of the filesystem that the file resides in.
> + * @digest: The digest value of the contents of the file using the
> + *	    hash function defined for the security modeling namespace.
> + *
> + * This structure and the structures that follow up to the struct
> + * tsem_event structure are used to identify the various entities that
> + * are involved in the definition of the CELL identity for a security
> + * event.
> + *
> + * The tsem_file structure is used to encapsulate the characteristics
> + * of a file that is used as an entity in the CELL definition of an
> + * event.
> + *
> + * Since a pathname can be up to PATH_MAX (4096 bytes) in length the
> + * cryptographic digest value is used rather than the pathname of the
> + * file itself.
> + */
> +struct tsem_file {
> +	uid_t uid;
> +	gid_t gid;
> +	umode_t mode;
> +	u32 flags;
> +
> +	u32 name_length;
> +	u8 name[HASH_MAX_DIGESTSIZE];
> +
> +	u32 s_magic;
> +	u8 s_id[32];
> +	u8 s_uuid[16];
> +
> +	u8 digest[HASH_MAX_DIGESTSIZE];
> +};
> +
> +/**
> + * struct tsem_COE - TSEM memory mapped file characteristics.
> + * @file: The struct file definition for the file that is being
> + *	  mapped.  This pointer will be null in the case of an
> + *	  anonymous mapping.
> + * @anonymous: A flag variable to indicate whether or not the mapping
> + *	       is file backed or anonymous.
> + * @reqprot: The memory protection flags that are requested by the
> + *	     memory mapping system call.
> + * @prot: The protections that will be applied to the mapping.
> + * @flags: The control flags of the memory mapping call.
> + *
> + * This structure is used to encapsulate the arguments provided to the
> + * tsem_mmap_file security event handler.
> + */
> +struct tsem_mmap_file_args {
> +	struct file *file;
> +	u32 anonymous;
> +	u32 reqprot;
> +	u32 prot;
> +	u32 flags;
> +};
> +
> +/**
> + * struct tsem_socket_create_args - TSEM socket creation arguments.
> + * @family: The family name of the socket whose creation is being
> + *	    requested.
> + * @type: The type of the socket being created.
> + * @protocol: The protocol family of the socket being created.
> + * @kern: A flag variable to indicate whether or not the socket being
> + *	  created is kernel or userspace based.
> + *
> + * This structure is used to encapsulate the arguments provided to the
> + * tsem_socket_create security event handler.
> + */
> +struct tsem_socket_create_args {
> +	int family;
> +	int type;
> +	int protocol;
> +	int kern;
> +};
> +
> +/**
> + * struct tsem_socket_connection_args - TSEM socket connection arguments.
> + * @tsip: A pointer to the struct tsem_inode structure that describes
> + *	  the TSEM inode characteristics of the inode representing
> + *	  the socket.
> + * @addr: A pointer to the structure describing the socket address
> + *	  that is being connected.
> + * @addr_len: The length of the socket address description structure.
> + * @family: The family number of the socket.
> + *
> + * @protocol: The protocol family of the socket being created.
> + * @kern: A flag variable to indicate whether or not the socket being
> + *	  created is kernel or userspace based.
> + * @u: A union that is used to hold the family specific address
> + *     characteristics of the socket connection.
> + * @u.ipv4: If the connection is IPV4 based this structure will be
> + *	    populated with the IPV4 address information.
> + * @u.ipv6: If the connection is IPV6 based this structure will be
> + *	    populated with the IPV6 address information.
> + * @u.path: If the socket connection is an AF_UNIX based socket
> + *	    address this buffer will contain the pathname of the
> + *	    socket address.
> + * @u.mapping: If the socket represents an address protocol other
> + *	       than IPV4, IPV6 or UNIX domain this buffer will contain
> + *	       the cryptographic value of the socket address
> + *	       information using the hash function that has been
> + *	       specified for the security modeling namespace.
> + *
> + * This structure is used to encapsulate the arguments provided to the
> + * tsem_socket_create security event handler.
> + */
> +struct tsem_socket_connect_args {
> +	struct tsem_inode *tsip;
> +	struct sockaddr *addr;
> +	int addr_len;
> +	u16 family;
> +	union {
> +		struct sockaddr_in ipv4;
> +		struct sockaddr_in6 ipv6;
> +		char path[UNIX_PATH_MAX + 1];
> +		u8 mapping[HASH_MAX_DIGESTSIZE];
> +	} u;
> +};
> +
> +/**
> + * struct tsem_socket_accept_args - TSEM socket accept parameters.
> + * @family: The socket family identifier for the connection being
> + *	    accepted.
> + * @type: The type of socket connection being accepted.
> + * @port: The port number of the connection being accepted.
> + * @ipv4: The IPV4 address of the connection being accepted if the
> + *	  socket is representing an IPV4 connection
> + * @ipv6: The IPV6 address of the connection being accepted if the
> + *	  socket is representing an IPV6 connection.
> + * @af_unix: The UNIX domain socket address if the socket is
> + *	     representing a UNIX domain connection.
> + * @path: The pathname of the UNIX domain socket.
> + * @mapping: A cryptographic hash of description of the socket
> + *	     connection being accepted if the socket is representing
> + *	     a connection other than an IPV4, IPV6 or UNIX domain
> + *	     socket.
> + *
> + * This structure is used to encapsulate the arguments provided to the
> + * tsem_socket_accept security event handler.
> + */
> +struct tsem_socket_accept_args {
> +	u16 family;
> +	u16 type;
> +	__be16 port;
> +	union {
> +		__be32 ipv4;
> +		struct in6_addr ipv6;
> +		struct unix_sock *af_unix;
> +		char path[UNIX_PATH_MAX + 1];
> +		u8 mapping[HASH_MAX_DIGESTSIZE];
> +	} u;
> +};
> +
> +/**
> + * struct tsem_task_kill_args - TSEM task kill arguments.
> + * @cross_model: A flag variable used to indicate whether or not the
> + *		 signal is originating from a security modeling
> + *		 namespace other than the namespace of the target process.
> + * @signal: The number of the signal being sent.
> + * @source: The task identifier of the process sending the signal
> + * @target: The task identifier of the target process.
> + *
> + * This structure is used to encapsulate the arguments provided to the
> + * tsem_task_kill security event handler.
> + */
> +struct tsem_task_kill_args {
> +	u32 cross_model;
> +	u32 signal;
> +	u8 source[HASH_MAX_DIGESTSIZE];
> +	u8 target[HASH_MAX_DIGESTSIZE];
> +};
> +
> +/**
> + * struct tsem_event - TSEM security event description.
> + * @index: The index number of the slot in the structure magazine that
> + *	   is being refilled.
> + * @u: A union that holds pointers to the structure whose magazine is
> + *     being refilled.
> + * @work: The work structure that manages the workqueue being used to
> + *	  refill the magazine entry.
> + * @event: The enumeration type describing the security event that the
> + *	   structure is defining.
> + * @locked: A boolean flag used to indicate whether or not the
> + *	    security event is running in atomic context.
> + * @pid: The process id number, in the global pid namespace, of the
> + *	 task that is requesting approval for a security event.
> + * @pathname: If the event is referencing a file this pointer will
> + *	      point to a null-terminated buffer containing the
> + *	      pathname to the file in the mount namespace that the
> + *	      process is running in.
> + * @comm: A pointer to a null terminated buffer containing the name of
> + *	  the process that is requesting the security event.
> + * @digestsize: The size in bytes of the cryptographic hash function
> + *		that is being used in the namespace in which the event
> + *		is being recorded.
> + * @task_id: The TSEM task identifier of the process that generated the
> + *	     security event described by an instance of this
> + *	     structure.
> + * @mapping: The security state coefficient that the event described
> + *	     by this structure generates.
> + * @COE: The struct tsem_COE structure that describes the Context Of
> + *	 Execution that generated the event described by this
> + *	 structure.
> + * @file: If the security event references a file this structure will
> + *	  contain the struct tsem_file structure that describes the
> + *	  characteristics of the file.
> + * @CELL: The CELL union is used to hold the data structures that
> + *	  characterize the CELL identity of the event.
> + * @CELL.event_type: In the case of a generically modeled event this
> + *		     member will contain the enumeration value
> + *		     identifying the event.
> + * @CELL.mmap_file: The structure describing the characteristics of
> + *		    a mmap_file security event.
> + * @CELL.socket_create: The structure describing the characteristics
> + *			of a socket_create security event.
> + * @CELL.socket_connect: The structure describing the characteristics
> + *			 of a socket_connect security event.
> + * @CELL.socket_accept: The structure describing the characteristics
> + *			of a socket accept security event.
> + * @CELL.task_kill: The structure describing the characteristics of a
> + *		    task_kill security event.
> + *
> + * This structure is the primary data structure for describing
> + * security events that are registered in a security modeling
> + * namespace.  Each unique security coefficient in the namespace will
> + * have one of these structures attached to it.
> + *
> + * This structure encapsulates the following three major sources of
> + * information about the event:
> + *
> + * * A description of the process initiating the event.
> + * * The characteristics that form the COE identity of the event.
> + * * The characteristics that form the CELL identity of the event.
> + *
> + * Since one event description has to ultimately characterize any
> + * security event that can occur the strategy is to use a union that
> + * contains security event specific structures that describe the
> + * characteristics of the event.
> + *
> + * The kref member of this structure is used to signal when the
> + * structure is to be deleted.  For example, in the case of an
> + * externally modeled event, when the export of the event description
> + * is complete.  In the case of an internally modeled namespace the
> + * structure will be released if it represents a security state
> + * coefficient that is already present in the model.
> + *
> + * The work member of this structure is used to support asynchronous
> + * updates to a TPM for the root modeling domain.  Asynchronous
> + * updates are used to improve the performance of modeling and to
> + * handle security events that are running in atomic context and
> + * cannot be scheduled away while the TPM transaction completes.
> + *
> + * The tsem_event_allocate() function is called by a TSEM security
> + * event handler to allocate and populate this structure.  The struct
> + * tsem_event_parameters structure is used to encapsulate all of the
> + * different structure types that are needed to characterize all of
> + * the different security events that occur.
> + *
> + * The tsem_event_allocate() function is called by either the
> + * tsem_map_event() or tsem_map_event_locked() functions.  After
> + * allocating and populating an event description structure the
> + * mapping functions generate a security state coefficient from the
> + * information in this structure.
> + *
> + * The two separate function call points for mapping are to allow the
> + * security event handlers to indicate the context in which the
> + * security event is occurring, ie. sleeping or atomic context.  After
> + * this point the context of the security event is represented by the
> + * locked member of this structure.
> + *
> + * After the event is mapped this structure is either passed to the
> + * internal trusted modeling agent or the contents of this structure
> + * is exported to the trust orchestrator attached to the namespace for
> + * modeling by an external trust modeling agent.
> + */
> +struct tsem_event {
> +	struct kref kref;
> +	struct list_head list;
> +	struct work_struct work;
> +
> +	enum tsem_event_type event;
> +	bool locked;
> +	pid_t pid;
> +	char *pathname;
> +	char comm[TASK_COMM_LEN];
> +
> +	unsigned int digestsize;
> +	u8 task_id[HASH_MAX_DIGESTSIZE];
> +	u8 mapping[HASH_MAX_DIGESTSIZE];
> +
> +	struct tsem_COE COE;
> +	struct tsem_file file;
> +
> +	union {
> +		u32 event_type;
> +		struct tsem_mmap_file_args mmap_file;
> +		struct tsem_socket_create_args socket_create;
> +		struct tsem_socket_connect_args socket_connect;
> +		struct tsem_socket_accept_args socket_accept;
> +		struct tsem_task_kill_args task_kill;
> +	} CELL;
> +};
> +
> +/**
> + * struct tsem_event_parameters - Security event argument descriptions
> + * @u: A union that encapsulates all of the different structures that
> + *     are used to characterize the argument so the TSEM security
> + *     event handlers.
> + * @u.event_type: This structure member holds the enum tsem_event_type
> + *		  enumeration value of the event whose characteristics
> + *		  are encapsulated in the function.
> + * @u.file: If the security event references a VFS file this member
> + *	    hold a pointer to the description of the file.
> + _file event.
> + * @u.socket_create: This member will point to a structure that
> + *		     describes the characteristics of a socket_create
> + *		     event.
> + * @u.socket_connect: This member will point to a structure that
> + *		      describes the characteristics of a socket_connect
> + *		      event.
> + * @u.socket_accept: This member will point to a structure that
> + *		     describes the characteristics of a socket_accept
> + *		     event.
> + * @u.task_kill: This member will point to a structure that describes
> + *		     the characteristics of a task_kill function.
> + *
> + * The purpose of this structure is to provide a common encapsulation
> + * method for passing the CELL characteristics of a security event
> + * into the tsem_event_init() function.  The characteristics passed in
> + * this event will be used to create and populate the struct
> + * tsem_event structure that will go on to be used to characterize
> + * the event either an internal or external modeling agent.
> + *
> + * The strategy followed is to allocate one of these structures on the
> + * stack for a security event call along with a call specific
> + * characteristics description structure, both of which will no longer
> + * be needed after completion of the call since the requisite
> + * information has been transferred to a struct tsem_event structure.
> + */
> +struct tsem_event_parameters {
> +	union {
> +		u32 event_type;
> +		struct file *file;
> +		struct tsem_mmap_file_args *mmap_file;
> +		struct tsem_socket_create_args *socket_create;
> +		struct tsem_socket_connect_args *socket_connect;
> +		struct tsem_socket_accept_args *socket_accept;
> +		struct tsem_task_kill_args *task_kill;
> +	} u;
> +};
> +
> +/**
> + * struct tsem_event_point - TSEM security coefficient characteristics.
> + * @list: The list structure used to link together all of the security
> + *	  state coefficients for a modeling namespace.
> + * @valid: A boolean value use to indicate whether or not the security
> + *	   state point is a valid coefficient in the model.
> + * @count: The number of times this coefficient has been expressed by
> + *	   security model for the namespace.
> + * @point: The security state coefficient for the point created by
> + *	   the cryptographic hash function being used for the modeling
> + *	   namespace.
> + *
> + * This structure is used by internal trusted modeling agents to
> + * represent each unique state point in a security model.  Security
> + * state coefficients are unique within a model so only one struct
> + * tsem_event_point structure will be generated regardless of how many
> + * times the security event that generates the point occurs.  The
> + * count member of this structure represents the total number of
> + * security events that have occurred that have generated the point.
> + *
> + * The valid member of this structure is used to flag whether this
> + * is consistent with the model for the namespace or was generated by
> + * a 'forensic', ie. out of model, event.
> + *
> + * Within each security namespace these structures are linked together
> + * in a list that describes the functional value of the security model
> + * assigned to the namespace.  Entries are only added to this list and
> + * never removed.
> + *
> + * The desired state of a security model is created by using the TSEM
> + * control plane to inject a list of acceptable security state
> + * coefficients into the model.  Sealing a model causes any security
> + * events that produce a coefficient different from those already in
> + * the model to be rejected as an invalid security event and logged as
> + * a forensic event for the model.
> + */
> +struct tsem_event_point {
> +	struct list_head list;
> +	bool valid;
> +	u64 count;
> +	u8 point[HASH_MAX_DIGESTSIZE];
> +};
> +
> +/**
> + * struct tsem_inode - TSEM inode status structure.
> + * @mutex: The mutex that will protect the list of struct
> + *	   tsem_inode_digest structures that have been created for the
> + *	   inode containing a struct tsem_inode structure.
> + * @list: The list structure that points to the list of struct
> + *	  tsem_inode_structures.
> + * @status: The digest collection state of the inode.  See the
> + *	    discussion of enum tsem_inode_state for what information
> + *	    is conveyed by the value of this structure member.
> +
> + * This structure is the second of the two primary control structures
> + * that are implemented through the LSM blob functionality.  It is
> + * automatically created when the inode structure is created for
> + * system resources that are referenced by a struct inode structure.
> + *
> + * This structure has two primary purposes.  The status member is used
> + * to signal that the tsem_file_open() function should return that
> + * permission to access the file is returned when the security hook is
> + * invoked by the integrity_kernel_read() function.  See the
> + * discussion on enum tsem_inode_state to more details.
> + *
> + * The second purpose of this structure is to maintain a list of
> + * digest values that have been computed by the inode that this
> + * structure references.  Maintenance of multiple digest values is
> + * required since there is no concept of a fixed digest function for
> + * TSEM as each modeling namespace can have its own digest function.
> + *
> + * Each digest value in use has a struct tsem_inode_digest structure
> + * allocated for it.  The digest_list member of this structure points
> + * to a list of these structures.
> + *
> + * The mutex implemented in this structure should be held by any
> + * process that is accessing the list.
> + */
> +struct tsem_inode {
> +	struct mutex mutex;
> +	struct list_head digest_list;
> +	enum tsem_inode_state status;
> +};
> +
> +/**
> + * struct tsem_inode_digest - Digest specific file checksum.
> + * @list:	The list structure used to link multiple digest values
> + *		for an inode.
> + * @version:	The version number of the inode that generated the digest
> + *		value that is currently represented.
> + * @name:	A pointer to a null-terminated character buffer containing
> + *		the name of the hash function that generated the current
> + *		digest value.
> + * @value:	The digest value of the file.
> + *
> + * A linked list of these structures is maintained for each inode that
> + * is modeled by TSEM and is used to support multiple hash specific
> + * digest values for a file represented by the inode.  The tsem_inode
> + * structure that represents the TSEM security status of the inode
> + * contains the pointer to this list of structures.
> + *
> + * The version member of the structure contains the inode version number
> + * that was in effect when the last digest value of this type was computed.
> + * This version number value is used to detect changes and to trigger an
> + * update of the digest value.
> + *
> + * The name member of structure contains the name of the hash function
> + * that generated the checksum value.  This name is used to locate the
> + * correct structure by comparing its value against the hash function
> + * that is being used for the modeling domain that is accessing the
> + * inode.
> + */
> +struct tsem_inode_digest {
> +	struct list_head list;
> +	char *name;
> +	u64 version;
> +	u8 value[HASH_MAX_DIGESTSIZE];
> +};
> +
> +/*
> + * The following three variables are the only globally visible
> + * variables used in the TSEM implementation.
> + *
> + * The tsem_blob_sizes variable is used by the LSM infrastructure to
> + * describe the amount of space that will be needed by the struct
> + * tsem_task and struct tsem_inode structures.
> + *
> + * The tsem_names array is defined in the tsem.c file and contains an
> + * array of pointers to the strings that define the names for each of
> + * the TSEM security event handles.  The enum tsem_event_type
> + * enumeration indexes this array.
> + *
> + * The tsem_root_actions array is also indexed by the enum
> + * tsem_event_type enumeration and is used to determine the type of
> + * response that a TSEM security event handler is to return to the
> + * caller, ie. either logging or enforcing.  The contents of this
> + * array is inherited by copying the array into the struct
> + * tsem_context structure for modeling namespaces that are subordinate
> + * to the root model.
> + */
> +extern struct lsm_blob_sizes tsem_blob_sizes;
> +extern const char * const tsem_names[TSEM_EVENT_CNT];
> +extern enum tsem_action_type tsem_root_actions[TSEM_EVENT_CNT];
> +
> +/*
> + * The following section of the file contains the definitions for the
> + * externally visible functions in each of the TSEM compilation units.
> + */
> +extern struct dentry *tsem_fs_create_external(const char *name);
> +extern void tsem_fs_show_trajectory(struct seq_file *c, struct tsem_event *ep);
> +extern void tsem_fs_show_field(struct seq_file *c, const char *field);
> +extern void tsem_fs_show_key(struct seq_file *c, char *term, char *key,
> +			     char *fmt, ...);
> +extern int tsem_fs_init(void);
> +
> +extern struct tsem_model *tsem_model_allocate(size_t size);
> +extern void tsem_model_free(struct tsem_context *ctx);
> +extern int tsem_model_event(struct tsem_event *ep);
> +extern int tsem_model_load_point(u8 *point);
> +extern int tsem_model_load_pseudonym(u8 *mapping);
> +extern int tsem_model_has_pseudonym(struct tsem_inode *tsip,
> +				    struct tsem_file *ep);
> +extern void tsem_model_load_base(u8 *mapping);
> +extern int tsem_model_add_aggregate(void);
> +extern void tsem_model_compute_state(void);
> +extern void tsem_model_magazine_free(struct tsem_model *model);
> +extern int tsem_model_cache_init(struct tsem_model *model, size_t size);
> +
> +extern void tsem_ns_put(struct tsem_context *ctx);
> +extern int tsem_ns_event_key(u8 *task_key, const char *keystr, u8 *key);
> +extern int tsem_ns_create(const enum tsem_control_type type,
> +			  const char *digest, const enum tsem_ns_reference ns,
> +			  const char *key, const unsigned int cache_size);
> +
> +extern int tsem_export_show(struct seq_file *m, void *v);
> +extern int tsem_export_event(struct tsem_event *ep);
> +extern int tsem_export_action(enum tsem_event_type event, bool locked);
> +extern int tsem_export_aggregate(void);
> +extern int tsem_export_magazine_allocate(struct tsem_external *ext,
> +					 size_t size);
> +extern void tsem_export_magazine_free(struct tsem_external *ext);
> +extern int tsem_export_cache_init(void);
> +
> +extern int tsem_map_task(struct file *file, u8 *mapping);
> +struct tsem_event *tsem_map_event(enum tsem_event_type event,
> +				  struct tsem_event_parameters *param);
> +struct tsem_event *tsem_map_event_locked(enum tsem_event_type event,
> +					 struct tsem_event_parameters *param);
> +
> +extern struct tsem_event *tsem_event_allocate(bool locked);
> +extern struct tsem_event *tsem_event_init(enum tsem_event_type event,
> +					  struct tsem_event_parameters *params,
> +					  bool locked);
> +extern void tsem_event_put(struct tsem_event *ep);
> +extern void tsem_event_get(struct tsem_event *ep);
> +extern int tsem_event_magazine_allocate(struct tsem_context *ctx, size_t size);
> +extern void tsem_event_magazine_free(struct tsem_context *ctx);
> +extern int tsem_event_cache_init(void);
> +
> +extern u8 *tsem_trust_aggregate(void);
> +extern int tsem_trust_add_event(struct tsem_event *ep);
> +
> +/*
> + * The remaining inline function declarations follow the design
> + * pattern of the other LSM's and implement functions that return
> + * various TSEM characteristics of tasks, modeling contexts and
> + * inodes.
> + */
> +static inline struct tsem_task *tsem_task(struct task_struct *task)
> +{
> +	return task->security + tsem_blob_sizes.lbs_task;
> +}
> +
> +static inline bool tsem_task_trusted(struct task_struct *task)
> +{
> +	return tsem_task(task)->trust_status & TSEM_TASK_TRUSTED;
> +}
> +
> +static inline bool tsem_task_untrusted(struct task_struct *task)
> +{
> +	return tsem_task(task)->trust_status & ~TSEM_TASK_TRUSTED;
> +}
> +
> +static inline struct tsem_context *tsem_context(struct task_struct *task)
> +{
> +	return tsem_task(task)->context;
> +}
> +
> +static inline struct tsem_model *tsem_model(struct task_struct *task)
> +{
> +	return tsem_task(task)->context->model;
> +}
> +
> +static inline struct tsem_inode *tsem_inode(struct inode *inode)
> +{
> +	return inode->i_security + tsem_blob_sizes.lbs_inode;
> +}
> +
> +static inline struct crypto_shash *tsem_digest(void)
> +{
> +	return tsem_context(current)->tfm;
> +}
> +
> +static inline unsigned int tsem_digestsize(void)
> +{
> +	return crypto_shash_digestsize(tsem_digest());
> +}

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 05/13] Add primary TSEM implementation file.
  2023-07-10 10:23 ` [PATCH 05/13] Add primary TSEM implementation file Dr. Greg
@ 2023-08-07 21:00   ` Casey Schaufler
  2023-08-11  7:21     ` Dr. Greg
  0 siblings, 1 reply; 36+ messages in thread
From: Casey Schaufler @ 2023-08-07 21:00 UTC (permalink / raw)
  To: Dr. Greg, linux-security-module, linux-kernel, corbet, Casey Schaufler

On 7/10/2023 3:23 AM, Dr. Greg wrote:
> The tsem.c file is the 'master' file in the TSEM implementation.
> It is responsible for initializing the LSM and providing
> implementions of the security event hooks implemented by TSEM.
>
> In addition to initializing the LSM, the set_ready() function
> implements a secondary initialization that is used to to indicate
> that security event modeling can begin.  This is required
> secondary to the fact that the cryptographic API's do not become
> ready until after the 'fs' phase of system initialization is
> complete.
>
> This file also handles the implementation of kernel command-line
> parameters that are used to configure the root security modeling
> namespace.
>
> The 'tsem_mode' parameter, if set to a value of 1, causes modeling
> to be not conducted for the root security modeling namespace.
> One use case is to allow development platform to develop security
> models without the overhead of full platform modeling.
>
> The 'tsem_digest' parameter is used to set the cryptographic hash
> function that is used to generate security state coefficients in
> the root model.  TSEM can use any cryptographic hash function
> implemented in the kernel, on a namespace by namespace basis.
> Subordinate modeling namespaces can select their hash function
> as part of the namespace creation process but the 'tsem_digest'
> parameter has to be used to set the function for the root
> modeling namespace.
>
> The hash function used in the root modeling namespace but be
> compiled into the kernel since the function is used before module
> loading becomes available.  The TSEM kernel configuration selects
> the SHA256 function to be included as the default cryptographic
> modeling function.
>
> The 'tsem_cache' variable sets the size of the pre-allocated
> structures that are used for security event modeling in the root
> modeling namespace.  This cache is used to support the modeling
> and export of events that run in atomic context.  The cache size
> can be set independently for each subordinate security modeling
> on a namespace by namespace basis.
>
> This file also contains the implementation of the tsem_names
> array that contains the ASCII text names that are assigned to
> each security event handler.  This name is used as one of the
> characteristics in the security state points that are generated.
> This array is also used to provide symbolic names for the export
> of security event descriptions, either through the TSEM control
> plane or for export to external trust orchestrators.
>
> Signed-off-by: Greg Wettstein <greg@enjellic.com>
> ---
>  security/tsem/tsem.c | 1987 ++++++++++++++++++++++++++++++++++++++++++

Please use kernel doc comments throughout.
I've made a few minor comments below, but you need to break this up
somehow for review. Also, having the data definitions elsewhere makes
review tough.

>  1 file changed, 1987 insertions(+)
>  create mode 100644 security/tsem/tsem.c
>
> diff --git a/security/tsem/tsem.c b/security/tsem/tsem.c
> new file mode 100644
> index 000000000000..8ec630354240
> --- /dev/null
> +++ b/security/tsem/tsem.c
> @@ -0,0 +1,1987 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +/*
> + * Copyright (C) 2023 Enjellic Systems Development, LLC
> + * Author: Dr. Greg Wettstein <greg@enjellic.com>
> + *
> + * TSEM initialization infrastructure.
> + */
> +#define TRAPPED_MSG_LENGTH 128
> +
> +#define LOCKED true
> +#define NOLOCK false
> +
> +#include <linux/magic.h>
> +#include <linux/mman.h>
> +#include <linux/binfmts.h>
> +#include <linux/bpf.h>
> +#include <linux/ipv6.h>
> +
> +#include "tsem.h"
> +
> +struct lsm_blob_sizes tsem_blob_sizes __ro_after_init = {
> +	.lbs_task = sizeof(struct tsem_task),

Do you really want this for the task? It would seem you might
want to use the cred blob instead.

> +	.lbs_inode = sizeof(struct tsem_inode)
> +};
> +
> +enum tsem_action_type tsem_root_actions[TSEM_EVENT_CNT] = {
> +	TSEM_ACTION_EPERM	/* Undefined. */
> +};
> +
> +static struct tsem_model root_model = {
> +	.point_lock = __SPIN_LOCK_INITIALIZER(root_model.point_lock),
> +	.point_list = LIST_HEAD_INIT(root_model.point_list),
> +	.point_end_mutex = __MUTEX_INITIALIZER(root_model.point_end_mutex),
> +
> +	.trajectory_lock = __SPIN_LOCK_INITIALIZER(root_model.trajectory_lock),
> +	.trajectory_list = LIST_HEAD_INIT(root_model.trajectory_list),
> +	.trajectory_end_mutex = __MUTEX_INITIALIZER(root_model.trajectory_end_mutex),
> +
> +	.forensics_lock = __SPIN_LOCK_INITIALIZER(root_model.forensics_lock),
> +	.forensics_list = LIST_HEAD_INIT(root_model.forensics_list),
> +	.forensics_end_mutex = __MUTEX_INITIALIZER(root_model.forensics_end_mutex),
> +
> +	.pseudonym_mutex = __MUTEX_INITIALIZER(root_model.pseudonym_mutex),
> +	.pseudonym_list = LIST_HEAD_INIT(root_model.pseudonym_list)
> +};
> +
> +static struct tsem_context root_context;
> +
> +static int tsem_ready __ro_after_init;
> +
> +static bool tsem_available __ro_after_init;
> +
> +static unsigned int magazine_size __ro_after_init = TSEM_ROOT_MAGAZINE_SIZE;
> +
> +static bool no_root_modeling __ro_after_init;
> +
> +static char *default_hash_function __ro_after_init;
> +
> +static int __init set_magazine_size(char *magazine_value)
> +{
> +	if (kstrtouint(magazine_value, 0, &magazine_size))
> +		pr_warn("tsem: Failed to parse root cache size.\n");
> +
> +	if (!magazine_size) {
> +		pr_warn("tsem: Forcing non-zero cache size.\n");
> +		magazine_size = TSEM_ROOT_MAGAZINE_SIZE;
> +	}
> +
> +	pr_info("tsem: Setting default root cache size to %u.\n",
> +		magazine_size);
> +	return 1;
> +}
> +__setup("tsem_cache=", set_magazine_size);
> +
> +static int __init set_modeling_mode(char *mode_value)
> +{
> +	unsigned long mode = 0;
> +
> +	if (kstrtoul(mode_value, 0, &mode)) {
> +		pr_warn("tsem: Failed to parse modeling mode.\n");
> +		return 1;
> +	}
> +
> +	if (mode == 1)
> +		no_root_modeling = true;
> +	else
> +		pr_warn("tsem: Unknown mode specified.\n");
> +	return 1;
> +}
> +__setup("tsem_mode=", set_modeling_mode);
> +
> +static int __init set_default_hash_function(char *hash_function)
> +{
> +
> +	default_hash_function = hash_function;
> +	return 1;
> +}
> +__setup("tsem_digest=", set_default_hash_function);
> +
> +const char * const tsem_names[TSEM_EVENT_CNT] = {
> +	"undefined",
> +	"bprm_set_creds",
> +	"generic_event",
> +	"task_kill",
> +	"task_setpgid",
> +	"task_getpgid",
> +	"task_getsid",
> +	"task_setnice",
> +	"task_setioprio",
> +	"task_getioprio",
> +	"task_prlimit",
> +	"task_setrlimit",
> +	"task_setscheduler",
> +	"task_getscheduler",
> +	"task_prctl",
> +	"file_open",
> +	"mmap_file",
> +	"file_ioctl",
> +	"file_lock",
> +	"file_fcntl",
> +	"file_receive",
> +	"unix_stream_connect",
> +	"unix_may_send",
> +	"socket_create",
> +	"socket_connect",
> +	"socket_bind",
> +	"socket_accept",
> +	"socket_listen",
> +	"socket_socketpair",
> +	"socket_sendmsg",
> +	"socket_recvmsg",
> +	"socket_getsockname",
> +	"socket_getpeername",
> +	"socket_setsockopt",
> +	"socket_shutdown",
> +	"ptrace_traceme",
> +	"kernel_module_request",
> +	"kernel_load_data",
> +	"kernel_read_file",
> +	"sb_mount",
> +	"sb_umount",
> +	"sb_remount",
> +	"sb_pivotroot",
> +	"sb_statfs",
> +	"move_mount",
> +	"shm_associate",
> +	"shm_shmctl",
> +	"shm_shmat",
> +	"sem_associate",
> +	"sem_semctl",
> +	"sem_semop",
> +	"syslog",
> +	"settime",
> +	"quotactl",
> +	"quota_on",
> +	"msg_queue_associate",
> +	"msg_queue_msgctl",
> +	"msg_queue_msgsnd",
> +	"msg_queue_msgrcv",
> +	"ipc_permission",
> +	"key_alloc",
> +	"key_permission",
> +	"netlink_send",
> +	"inode_create",
> +	"inode_link",
> +	"inode_unlink",
> +	"inode_symlink",
> +	"inode_mkdir",
> +	"inode_rmdir",
> +	"inode_mknod",
> +	"inode_rename",
> +	"inode_setattr",
> +	"inode_getattr",
> +	"inode_setxattr",
> +	"inode_getxattr",
> +	"inode_listxattr",
> +	"inode_removexattr",
> +	"inode_killpriv",
> +	"tun_dev_create",
> +	"tun_dev_attach_queue",
> +	"tun_dev_attach",
> +	"tun_dev_open",
> +	"bpf",
> +	"bpf_map",
> +	"bpf_prog"
> +};
> +
> +static const int pseudo_filesystems[] = {
> +	PROC_SUPER_MAGIC,
> +	SYSFS_MAGIC,
> +	DEBUGFS_MAGIC,
> +	TMPFS_MAGIC,
> +	DEVPTS_SUPER_MAGIC,
> +	BINFMTFS_MAGIC,
> +	SECURITYFS_MAGIC,
> +	SELINUX_MAGIC,
> +	SMACK_MAGIC,
> +	CGROUP_SUPER_MAGIC,
> +	CGROUP2_SUPER_MAGIC,
> +	NSFS_MAGIC,
> +	EFIVARFS_MAGIC
> +};
> +
> +static bool bypass_inode(struct inode *inode)
> +{
> +	bool retn = true;
> +
> +	unsigned int lp;
> +
> +	if (!S_ISREG(inode->i_mode))
> +		goto done;
> +
> +	for (lp = 0; lp < ARRAY_SIZE(pseudo_filesystems); ++lp)
> +		if (inode->i_sb->s_magic == pseudo_filesystems[lp])
> +			goto done;
> +	retn = false;
> +
> + done:
> +	return retn;
> +}
> +
> +static int event_action(struct tsem_context *ctx, enum tsem_event_type event)
> +{
> +	int retn = 0;
> +
> +	if (tsem_task_trusted(current))
> +		return retn;
> +
> +	if (ctx->actions[event] == TSEM_ACTION_EPERM)
> +		retn = -EPERM;
> +
> +	return retn;
> +}
> +
> +static int return_trapped_task(enum tsem_event_type event, char *msg,

Why isn't this simply "trapped_task()"?

> +			       bool locked)
> +{
> +	int retn;
> +	struct tsem_context *ctx = tsem_context(current);
> +
> +	pr_warn("Untrusted %s: comm=%s, pid=%d, parameters='%s'\n",
> +		tsem_names[event], current->comm, task_pid_nr(current), msg);
> +
> +	if (ctx->external) {
> +		retn = tsem_export_action(event, locked);
> +		if (retn)
> +			return retn;
> +	}
> +
> +	return event_action(ctx, event);
> +}
> +
> +static int return_trapped_inode(enum tsem_event_type event,

Again, really odd function name.

... and that's all I have time for.


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/13] Add TSEM specific documentation.
  2023-07-10 10:23 ` [PATCH 02/13] Add TSEM specific documentation Dr. Greg
  2023-07-11  4:37   ` Randy Dunlap
@ 2023-08-08 18:48   ` Serge Hallyn
  2023-08-11 20:22     ` Dr. Greg
  2024-01-04  4:00   ` [PATCH 2/13] " Paul Moore
  2 siblings, 1 reply; 36+ messages in thread
From: Serge Hallyn @ 2023-08-08 18:48 UTC (permalink / raw)
  To: Dr. Greg; +Cc: linux-security-module, linux-kernel, corbet

On Mon, Jul 10, 2023 at 05:23:08AM -0500, Dr. Greg wrote:
> An entry was added to the ABI testing documentation to document

"Add an entry..." is the usual way to document this in commit msg.

> the files in the TSEM management filesystem.
> 
> The file documenting the kernel command-line parameters was
> updated to document the TSEM specific command-line parameters

A commit's actions are more normally in present tens
("The file documenting the kernel command-line parameters is")

> The primary TSEM documentation file was added to the LSM
> administration guide and the file was linked to the index of LSM
> documentation.
> 
> Signed-off-by: Greg Wettstein <greg@enjellic.com>
> ---
>  Documentation/ABI/testing/tsem                |  828 +++++++++
>  Documentation/admin-guide/LSM/index.rst       |    1 +
>  Documentation/admin-guide/LSM/tsem.rst        | 1526 +++++++++++++++++
>  .../admin-guide/kernel-parameters.txt         |   18 +
>  4 files changed, 2373 insertions(+)
>  create mode 100644 Documentation/ABI/testing/tsem
>  create mode 100644 Documentation/admin-guide/LSM/tsem.rst
> 
> diff --git a/Documentation/ABI/testing/tsem b/Documentation/ABI/testing/tsem
> new file mode 100644
> index 000000000000..cfb013b5f1f4
> --- /dev/null
> +++ b/Documentation/ABI/testing/tsem
> @@ -0,0 +1,828 @@
> +What:		/sys/kernel/security/tsem
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The /sys/kernel/security/tsem directory contains files
> +		and directories that implement the control plane for
> +		the Trusted Security Event Modeling (TSEM) LSM.
> +
> +		The files in this directory hierarchy, with the
> +		exception of the aggregate file, when read, reflect
> +		the values for the security modeling namespace that
> +		the process reading the files is operating in.
> +
> +What:		/sys/kernel/security/tsem/id
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The id file contains the ASCII base 10 representation

Why not use base 16 here?  Mixing bases amongst the files could get
confusing.

> +		of the model domain/namespace identifier that the
> +		reading process is operating in.
> +
> +		The root security modeling namespace has a value of
> +		zero, a non-zero value indicates a modeling namespace
> +		subordinate to the root model.
> +
> +		Each externally modeled domain will have a file, with
> +		this id number, created in the
> +		/sys/kernel/security/tsem/ExternalTMA directory that
> +		is documented below.
> +
> +What:		/sys/kernel/security/tsem/aggregate
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The aggregate file contains the ASCII base 16
> +		representation of the 256 bit hardware platform
> +		aggregate that TSEM is modeling under.  The platform
> +		aggregate is the linear extension measurement of the
> +		Trusted Platform Module PCR registers 0 through 8.
> +
> +		On a platform without a TPM this value will be all
> +		null bytes.
> +
> +What:		/sys/kernel/security/tsem/control
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The control file is the only writable file in the
> +		filesystem and is used by the trust orchestrator's to
> +		configure and control the behavior of the TSEM
> +		implementation.
> +
> +		The following keyword and arguments are recognized:
> +
> +		internal
> +			The internal keyword causes an internally
> +			modeled domain to be created for the calling
> +			process.
> +
> +		external
> +			The external keyword causes an externally
> +			modeled domain to be created for the calling
> +			process.
> +
> +			A modeling namespace created by these commands
> +			accept the following set of key=value pairs
> +			that configure the namespace:
> +
> +			nsref=initial|current
> +				The nsref key specifies the namespace
> +				that is to be referenced when
> +				determining the UID/GID values that
> +				define a COE or CELL identity.
> +
> +				The initial keyword specifies that the
> +				initial user namespace be used.  The
> +				current keyword specifies that the
> +				user namespace of the process that is
> +				invoking a security event handler
> +				(hook) is used.

Hm, does this allow a process in a container to escape the container's
policy, by creating a new domain inheriting from the initial userns?

> +TSEM implements its equivalent of mandatory access controls, without a
> +requirement for extended attributes, filesystem labeling or the need
> +to protect filesystem metadata against offline attack.  A mathematical

If the security policy is that no data from /dev/tty, because it is
untrusted, may flow into high integrity files, then how do you track
the files which are high integrity, without labeling high integrity
files?  You're intending for the agent to track the files using
inode number and fsid?

> +The root security model extends each security state coefficient into a
> +PCR.  The default PCR is 11 but is configurable through the kernel

Note pcr 11 will conflict with systemd's usage

https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/

> +It is up to the trust orchestrator and its security policy to
> +determine how it handles events that violate the security model being
> +enforced.  The Quixote trust orchestrators shut down the entire
> +workload running in the security namespace if an asynchronously
> +modeled event violates the security model being enforced and the model
> +is running in enforcing mode.

So instead of returning EPERM, you'll let the process speculatively
continue until quixote has a chance to catch up and return a "no not
allowed" message, after which the whole workload will be killed?

> +From a hardware perspective, this is important with respect to the
> +notion of a TMA being a model for a successor to the TPM.  From a
> +system trust or integrity perspective, a TPM is designed to provide a
> +retrospective assessment of the actions that have occurred on a
> +platform.  A verifying party uses the TPM event log and a PCR based
> +summary measurement, to verify what actions have occurred on the host,
> +in order to allow a determination of whether or not the platform
> +should be 'trusted'.

FWIW TPM EA policies also refuse access to secrets based on those and
other data.  It's not purely for retrospective assessment.  But indeed
TPM does not authorize actions as trusted.  Not because it fails to do
so but because it's not part of its design.

> +
> +In contrast, a TSEM/TMA based system enforces, on a real time basis,
> +that a platform or workload remains in a trusted state.  Security
> +relevant actions cannot be conducted unless the TMA authorizes the
> +actions as being trusted.
> +
> +This is particularly important with respect to embedded systems.  A
> +TPM based architecture would not prevent a system from having its
> +trust status altered.  Maintaining the system in a trusted state would
> +require attestation polling of the system, and presumably, executing
> +actions if the platform has engaged in untrusted behavior.
> +
> +Conversely, a trust orchestrated software implementation enforces that
> +a system or workload remain in a security/trust state that it's
> +security model was unit tested to.

To be convinced that there is *any* use case for this in the real world,
you'd need to show me how any useful rule, like your above /etc/shadow
set, could actually indicate a less trustworthy state in a robust way,
without turning into an easy accidental-self-DOS.

I'm afraid the answer is going to be "AI"...

> +Security model functional definitions
> +-------------------------------------
> +
> +Previously, classic trusted system implementations supported the
> +notion of the 'measurement' of the system.  The measurement is the
> +value of a linear extension function of all the security relevant
> +actions recorded by a trust measurement system such as IMA.
> +
> +In TPM based trust architectures, this measurement is maintained in a
> +PCR.  A measurement value is submitted to the TPM that extends the
> +current measurement using the following formula:
> +
> +MEASUREMENT = HASH(CURRENT || NEW)
> +
> +	Where:
> +		MEASUREMENT = The new measurement value to be maintained
> +			      in the register for the system.
> +
> +		||	    = Concatenation operator.
> +
> +		HASH	    = A cryptographic hash function supported
> +			      by the TPM device.
> +
> +		CURRENT     = The current measurement value.
> +
> +		NEW	    = A new measurement value to be added to
> +			      the current measurement.
> +
> +In TPM1 based systems, the HASH function was SHA1.  Due to well
> +understood security concerns about the cryptographic vitality of this
> +function, TPM2 based systems provide additional HASH functions with
> +stronger integrity guarantees, most principally SHA related functions
> +with longer digest values such as SHA256, SHA384 and SM3.

This previous paragraph simply is not needed in this document.

> +The use of a cryptographic function produces a non-commutative sum
> +that can be used to verify the integrity of a series of measurements.
> +With respect to security modeling theory, this can be thought of as a
> +'time-dependent' measurement of the system.  Stated more simply, the
> +measurement value is sensitive to the order in which the measurements
> +were made.
> +
> +In systems such as IMA, the measurement value reflects the sum of
> +digest values of what are considered to be security critical entities,
> +most principally, files that are accessed, based on various policies.
> +
> +In TSEM based TMA's, the measurement of a modeling namespace is the
> +sum of the security state coefficients generated by the operative
> +security model being enforced.  As previously noted, on systems with a
> +TPM, the root modeling namespace measurement is maintained by default
> +in PCR 11 or the PCR that was selected at kernel configuration time.
> +
> +The challenge associated with classic integrity measurements is the
> +time dependent nature of using a non-commutative summing function.
> +The almost universal embrace of SMP based hardware architectures, in
> +addition to standard kernel task scheduling issues, makes the
> +measurement values non-deterministic.  This requires a verifying party
> +to evaluate an event log, verified by a measurement value, to
> +determine whether or not the system is in a security appropriate
> +state.
> +
> +TSEM addresses this issue by implementing a strategy designed to
> +produce a single functional value that represents the security state

You've spent a lot of space discussing the "time based" (I think
"order dependent" might be better) nature of IMA and TPM measurements.
But after reading this section twice, I'm still not seeing what TMA
does to work around it.

If a process normally reads files F1, F2, .. F10, then writes F11,
but next time it reads F1, F3, F2, F4, .. F10, how will these two
different vectors be used in TMA?

> +of a model.  This allows a TMA to attest to the trust/security status
> +of a platform or workload by signing this singular value and
> +presenting it to a verifying party.
> +
> +In TSEM nomenclature, this singular value is referred to as the
> +'state' of the model.  The attestation model is to use trust
> +orchestrators to generate the state value of a workload by unit
> +testing.  This state value can be packaged with a utility or container
> +to represent a summary trust characteristic that can be attested by a
> +TMA, eliminating the need for a verifying partner to review and verify
> +an event log.
> +
> +TMA's implement this architecture by maintaining a single instance
> +vector of the set of security state coefficients that have been
> +generated.  A state measurement is generated by sorting the vector in
> +big-endian hash format and then generating a standard measurement
> +digest over this new vector.

Are you saying the TMA will keep every meaningful measurement for the
duration of the workload, so that it can always sort them?

> +Any security event that generates an associated state coefficient that
> +is not in the model will resulted in a perturbed state function value.
> +That perturbed value would be interpreted by a verifying party as an
> +indication of an untrusted system.
> +
> +Since the TMA maintains the security event descriptions in time
> +ordered form, the option to provide a classic event log and
> +measurement are preserved and available.  Extensive experience in the
> +development of TSEM modeled systems has demonstrated the superiority
> +of state value interpretation over classic measurement schemes.

I think you're saying that keeping the tens of thousands security
relevant events instead of keeping a hash of those events gives you
more information... which is true.  It also gives you more information.
In a presumably limited space and over a presumably limited link.  No
performance impact?

I'd really like to see what a conscise but useful policy looks like.

-serge

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 04/13] Add TSEM master header file.
  2023-08-07 20:39   ` Casey Schaufler
@ 2023-08-10  2:57     ` Dr. Greg
  2023-08-10 15:03       ` Casey Schaufler
  0 siblings, 1 reply; 36+ messages in thread
From: Dr. Greg @ 2023-08-10  2:57 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: linux-security-module, linux-kernel, corbet

On Mon, Aug 07, 2023 at 01:39:22PM -0700, Casey Schaufler wrote:

Hi Casey, thank you for the review comments.

> On 7/10/2023 3:23 AM, Dr. Greg wrote:
> > TSEM is designed, from a functional perspective, to be contained
> > entirely in its own directory.
> >
> > The tsem.h header file defines the enumeration types, structure
> > definitions and externally visiable functions that are referenced
> > by all of the compilation units of the TSEM LSM implementation in
> > that directory.

> Extensive documentation notwithstanding, it's impossible to review
> the data structures and constants without the code that goes along
> with them.

Big picture, I couldn't resist passing along an actual quote from my
mentor in Computer Science and modeling theory.  An algebraic
topologist by training who had Robert Ellis once briefly convinced
that it could be proven that it was possible to comb the hair on a
coconut, who also did significant work in data structures:

	"If one carefully studies and understands the data structures
	acted upon, including a description of their character, role
	and importance; the code itself, upon simple examination,
	will speak clearly, eloquently and stridently with respect to
	its intent and purpose for existence."

:-)

We approached the patch series from the perspective of tsem.h being a
reference document for the compilation units.

The rules are pretty simple.  Any structure, variable or function with
a tsem_ prefix, in some form of appropriate capitalization, can be
found quickly in tsem.h, along with what we hope is a complete
description on how and why the entity is implemented.

We were somewhat influenced by SMACK that uses a single include file
for its globally visible state.

Other LSM's seem to use multiple include files, is that a preferred
approach?

The tsem_event structure is the poster child of the challenges
associated with the latter model.  It gets used by all eight compilation
units so its declaration is going to be isolated from its use in most
cases.

This model seems to inevitably come down to something like 'common.h'
which puts you sort of back to where things started.

We may have missed it but I don't see anything in the kernel
developers guide with respect best practices for introducing blocks of
entire sub-system code.

Recommendations welcome.

> > The structure and enumeration types are extensively documented
> > and are the recommended starting point for understanding TSEM
> > implementation and functionality.
> >
> > Signed-off-by: Greg Wettstein <greg@enjellic.com>
> > ---
> >  security/tsem/tsem.h | 1516 ++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 1516 insertions(+)
> >  create mode 100644 security/tsem/tsem.h
> >
> > diff --git a/security/tsem/tsem.h b/security/tsem/tsem.h
> > new file mode 100644
> > index 000000000000..03915f47529b
> > --- /dev/null
> > +++ b/security/tsem/tsem.h
> > @@ -0,0 +1,1516 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +
> > +/*
> > + * Copyright (C) 2023 Enjellic Systems Development, LLC
> > + * Author: Dr. Greg Wettstein <greg@enjellic.com>
> > + *
> > + * This is the single include file that documents all of the externally
> > + * visible types and functions that are used by TSEM.  This file is
> > + * currently organized into four major sections in the following order;
> > + *
> > + * includes used by all compilation units
> > + * CPP definitions
> > + * enumeration types
> > + * structure definitions
> > + * function declarations
> > + * inline encapsulation functions.
> > + *
> > + * Include files that are referenced by more than a single compilation
> > + * should be included in this file.  Includes that are needed to
> > + * satisfy compilation requirements for only a single file should be
> > + * included in the file needing that include.
> > + *
> > + * Understanding the overall implementation and architecture of TSEM
> > + * will be facilitated by reviewing the documentation in this file.
> > + */
> > +
> > +#include <uapi/linux/in.h>
> > +#include <uapi/linux/in6.h>
> > +#include <linux/wait.h>
> > +#include <linux/kref.h>
> > +#include <linux/lsm_hooks.h>
> > +#include <linux/capability.h>
> > +#include <crypto/hash.h>
> > +#include <crypto/hash_info.h>
> > +#include <net/af_unix.h>
> > +
> > +/* The capability needed to manage TSEM. */
> > +#define TSEM_CONTROL_CAPABILITY CAP_ML

> Why would you do this? You gave the capability a name that even you
> don't want to use.

A simple placeholder that allows the capability used to control
security modeling to be set in one place, and one place only, until
the debate over the capability issue is settled.

We never envisioned this define lasting beyond the initial reviews.

> > +
> > +/*
> > + * The number of 'slots' in the structure magazines that are used to
> > + * satisfy modeling of security events that are called in atomic context.
> > + */
> > +#define TSEM_ROOT_MAGAZINE_SIZE	96
> > +#define TSEM_MAGAZINE_SIZE_INTERNAL 16
> > +#define TSEM_MAGAZINE_SIZE_EXTERNAL 96
> > +
> > +/**
> > + * enum tsem_event_type - Ordinal value for a security event.
> > + * @TSEM_BPRM_SET_CREDS: Ordinal value for bprm_creds_for_exec.
> > + * @TSEM_GENERIC_EVENT: Ordinal value for a generically modeled event.
> > + * @TSEM_TASK_KILL: Ordinal value for task kill.
> > + * @....: Remainder follows with a similar naming format that has
> > + *        TSEM_ prep ended to the raw LSM security hook name.
> > + * @TSEM_EVENT_CNT: The final ordinal value is used to define the
> > + *		    length of the following arrays that are indexed
> > + *		    by the ordinal value of the hook:
> > + *
> > + * This enumeration is used to designate an ordinal value for each
> > + * security event, ie. LSM hook, that TSEM is implementing modeling
> > + * for.  This value is used to identify the hook that is either having
> > + * its event description being exported to an external Trusted Modeling
> > + * Agent (TMA) or modeled by the internal TMA implementation.
> > + *
> > + * The primary use of this enumeration is to conditionalize code paths
> > + * based on the security hook being processed and to index the
> > + * tsem_names array and the array that defines the action that is to
> > + * be taken in response to an event that generates a permissions
> > + * violation.
> > + */
> > +enum tsem_event_type {
> > +	TSEM_BPRM_SET_CREDS = 1,
> > +	TSEM_GENERIC_EVENT,
> > +	TSEM_TASK_KILL,
> > +	TSEM_TASK_SETPGID,
> > +	TSEM_TASK_GETPGID,
> > +	TSEM_TASK_GETSID,
> > +	TSEM_TASK_SETNICE,
> > +	TSEM_TASK_SETIOPRIO,
> > +	TSEM_TASK_GETIOPRIO,
> > +	TSEM_TASK_PRLIMIT,
> > +	TSEM_TASK_SETRLIMIT,
> > +	TSEM_TASK_SETSCHEDULER,
> > +	TSEM_TASK_GETSCHEDULER,
> > +	TSEM_TASK_PRCTL,
> > +	TSEM_FILE_OPEN,
> > +	TSEM_MMAP_FILE,
> > +	TSEM_FILE_IOCTL,
> > +	TSEM_FILE_LOCK,
> > +	TSEM_FILE_FCNTL,
> > +	TSEM_FILE_RECEIVE,
> > +	TSEM_UNIX_STREAM_CONNECT,
> > +	TSEM_UNIX_MAY_SEND,
> > +	TSEM_SOCKET_CREATE,
> > +	TSEM_SOCKET_CONNECT,
> > +	TSEM_SOCKET_BIND,
> > +	TSEM_SOCKET_ACCEPT,
> > +	TSEM_SOCKET_LISTEN,
> > +	TSEM_SOCKET_SOCKETPAIR,
> > +	TSEM_SOCKET_SENDMSG,
> > +	TSEM_SOCKET_RECVMSG,
> > +	TSEM_SOCKET_GETSOCKNAME,
> > +	TSEM_SOCKET_GETPEERNAME,
> > +	TSEM_SOCKET_SETSOCKOPT,
> > +	TSEM_SOCKET_SHUTDOWN,
> > +	TSEM_PTRACE_TRACEME,
> > +	TSEM_KERNEL_MODULE_REQUEST,
> > +	TSEM_KERNEL_LOAD_DATA,
> > +	TSEM_KERNEL_READ_FILE,
> > +	TSEM_SB_MOUNT,
> > +	TSEM_SB_UMOUNT,
> > +	TSEM_SB_REMOUNT,
> > +	TSEM_SB_PIVOTROOT,
> > +	TSEM_SB_STATFS,
> > +	TSEM_MOVE_MOUNT,
> > +	TSEM_SHM_ASSOCIATE,
> > +	TSEM_SHM_SHMCTL,
> > +	TSEM_SHM_SHMAT,
> > +	TSEM_SEM_ASSOCIATE,
> > +	TSEM_SEM_SEMCTL,
> > +	TSEM_SEM_SEMOP,
> > +	TSEM_SYSLOG,
> > +	TSEM_SETTIME,
> > +	TSEM_QUOTACTL,
> > +	TSEM_QUOTA_ON,
> > +	TSEM_MSG_QUEUE_ASSOCIATE,
> > +	TSEM_MSG_QUEUE_MSGCTL,
> > +	TSEM_MSG_QUEUE_MSGSND,
> > +	TSEM_MSG_QUEUE_MSGRCV,
> > +	TSEM_IPC_PERMISSION,
> > +	TSEM_KEY_ALLOC,
> > +	TSEM_KEY_PERMISSION,
> > +	TSEM_NETLINK_SEND,
> > +	TSEM_INODE_CREATE,
> > +	TSEM_INODE_LINK,
> > +	TSEM_INODE_UNLINK,
> > +	TSEM_INODE_SYMLINK,
> > +	TSEM_INODE_MKDIR,
> > +	TSEM_INODE_RMDIR,
> > +	TSEM_INODE_MKNOD,
> > +	TSEM_INODE_RENAME,
> > +	TSEM_INODE_SETATTR,
> > +	TSEM_INODE_GETATTR,
> > +	TSEM_INODE_SETXATTR,
> > +	TSEM_INODE_GETXATTR,
> > +	TSEM_INODE_LISTXATTR,
> > +	TSEM_INODE_REMOVEXATTR,
> > +	TSEM_INODE_KILLPRIV,
> > +	TSEM_TUN_DEV_CREATE,
> > +	TSEM_TUN_DEV_ATTACH_QUEUE,
> > +	TSEM_TUN_DEV_ATTACH,
> > +	TSEM_TUN_DEV_OPEN,
> > +	TSEM_BPF,
> > +	TSEM_BPF_MAP,
> > +	TSEM_BPF_PROG,
> > +	TSEM_EVENT_CNT
> > +};
> > +
> > +/**
> > + * enum tsem_action_type - Ordinal value for security responses.
> > + * @TSEM_ACTION_LOG: Ordinal value to indicate that a security event
> > + *		     that results in a model permissions violation
> > + *		     should be logged.
> > + * @TSEM_ACTION_EPERM: Ordinal value to indicate that a security event
> > + *		       generating a model permissions violation should
> > + *		       return -EPERM to the caller.
> > + *
> > + * This enumeration type is used to designate what type of action is
> > + * to be taken when the processing of a security event hook results in
> > + * a model violation.  The TSEM_ACTION_LOG and TSEM_ACTION_EPERM
> > + * translate into the classical concepts of logging or enforcing
> > + * actions used by other mandatory access control architectures.
> > + */
> > +enum tsem_action_type {
> > +	TSEM_ACTION_LOG = 0,
> > +	TSEM_ACTION_EPERM,
> > +	TSEM_ACTION_CNT
> > +};
> > +
> > +/**
> > + * enum tsem_control_type - Ordinal values for TSEM control actions.
> > + * @TSEM_CONTROL_INTERNAL: This ordinal value is set when the first
> > + *			   word of an argument string written to the
> > + *			   control file is the word 'internal'.  This
> > + *			   designates that the security namespace will
> > + *			   be modeled by the internal TMA.
> > + * @TSEM_CONTROL_EXTERNAL: This ordinal value is set when the first
> > + *			   word of an argument string written to the
> > + *			   control file is the word 'external'.  This
> > + *			   designates that the security namespace will
> > + *			   be model by an external TMA.
> > + * @TSEM_CONTROL_ENFORCE: This ordinal value is set when the word
> > + *			  'enforce' is written to the control file.
> > + *			  This indicates that model is to be placed
> > + *			  in 'enforcing' mode and security events that
> > + *			  result in model violations will return EPERM.
> > + * @TSEM_CONTROL_SEAL: This ordinal value is set when the word 'seal'
> > + *		       is written to the control file.  This indicates
> > + *		       that the model for security domain will treat
> > + *		       all security events that do not conform to the
> > + *		       model as 'forensics' events.
> > + * @TSEM_CONTROL_TRUSTED: This ordinal value is used when the first
> > + *			  word of an argument string written to the
> > + *			  control file is the word 'trusted'.  This
> > + *			  is interpreted as a directive to set the
> > + *			  trust status of the task that executed the
> > + *			  security event to be trusted.
> > + * @TSEM_CONTROL_UNTRUSTED: This ordinal value is used when the first
> > + *			    word of an argument string written to the
> > + *			    control file is the word 'untrusted'.
> > + *			    This is interpreted as a directive to set
> > + *			    the trust status of the task that executed
> > + *			    the security event to be untrusted.
> > + * @TSEM_CONTROL_MAP_STATE: This ordinal value is used when the first
> > + *			    word of an argument string written to the
> > + *			    control file is the word 'state'.  The
> > + *			    argument to this directive will be an
> > + *			    ASCII hexadecimally encoded string of the
> > + *			    current model's digest size that will be
> > + *			    treated as a security state point for
> > + *			    inclusion in the security model for the
> > + *			    security domain/namespace.
> > + * @TSEM_CONTROL_MAP_PSEUDONYM: This ordinal value is used when the
> > + *				first word of an argument string
> > + *				written to the control file is the
> > + *				word 'pseudonym'.  The argument to
> > + *				this directive will be an ASCII
> > + *				hexadecimally encoded string of the
> > + *				current model's digest size that will
> > + *				be treated as a pseudonym directive
> > + *				for the security domain/namespace.
> > + * TSEM_CONTROL_MAP_BASE: This ordinal value is used when the first
> > + *			  word of an argument string written to the
> > + *			  control file is the word 'base'.  The
> > + *			  argument to this directive will be an ASCII
> > + *			  hexadecimally encoded string of the current
> > + *			  model's digest size that will be treated as
> > + *			  the base value for the computation of the
> > + *			  functional values (measurement and state) of
> > + *			  the security domain/namespace.
> > +
> > + * This enumeration type is used to designate what type of control
> > + * action is to be implemented when arguments are written to the TSEM
> > + * control file (/sys/kernel/security/tsem/control).  The ordinal
> > + * values govern the processing of the command and the interpretation
> > + * of the rest of the command argument string.
> > + */
> > +enum tsem_control_type {
> > +	TSEM_CONTROL_INTERNAL = 0,
> > +	TSEM_CONTROL_EXTERNAL,
> > +	TSEM_CONTROL_ENFORCE,
> > +	TSEM_CONTROL_SEAL,
> > +	TSEM_CONTROL_TRUSTED,
> > +	TSEM_CONTROL_UNTRUSTED,
> > +	TSEM_CONTROL_MAP_STATE,
> > +	TSEM_CONTROL_MAP_PSEUDONYM,
> > +	TSEM_CONTROL_MAP_BASE
> > +};
> > +
> > +/**
> > + * enum tsem_ns_reference - Ordinal value for DAC namespace reference.
> > + * @TSEM_NS_INITIAL: This ordinal value indicates that the uid/gid
> > + *		     values should be interpreted against the initial
> > + *		     user namespace.
> > + * @TSEM_NS_CURRENT: This ordinal value indicates that the uid/gid
> > + *		     values should be interpreted against the user
> > + *		     namespace that is in effect for the process being
> > + *		     modeled.
> > + *
> > + * This enumeration type is used to indicate what user namespace
> > + * should be referenced when the uid/gid values are interpreted for
> > + * the creation of either the COE or CELL identities.  The enumeration
> > + * ordinal passed to the tsem_ns_create() function, to configure the
> > + * security domain/namespace, is set by the nsref argument to either
> > + * the 'internal' or 'external' control commands.
> > + */
> > +enum tsem_ns_reference {
> > +	TSEM_NS_INITIAL = 1,
> > +	TSEM_NS_CURRENT
> > +};
> > +
> > +/**
> > + * enum tsem_task_trust - Ordinal value describing task trust status.
> > + * @TSEM_TASK_TRUSTED: This ordinal value indicates that the task has
> > + *		       not executed a security event that has resulted
> > + *		       in a security behavior not described by the
> > + *		       security model the task is being governed by.
> > + * @TSEM_TASK_UNTRUSTED: This ordinal value indicates that the task
> > + *		          has requested the execution of a security event
> > + *		          that resulted in a security behavior not
> > + *		          permitted by the security model the task is
> > + *		          being governed by.
> > + * @TSEM_TASK_TRUST_PENDING: This ordinal value indicates that the setting
> > + *			     of the task trust status is pending a response
> > + *		             from an external TMA.
> > + *
> > + * This enumeration type is used to specify the three different trust
> > + * states that a task can be in.  The trust status of a task is
> > + * regulated by the trust_status member of struct tsem_task.  A task
> > + * carrying the status of TSEM_TASK_TRUSTED means that it has
> > + * not requested the execution of any security events that are
> > + * inconsistent with the security model that the task is running in.
> > + *
> > + * If a task requests execution of a security event that is
> > + * inconsistent with the security model it is operating in, and the
> > + * domain is running in 'sealed' mode, the task trust status is set to
> > + * TSEM_TASK_UNTRUSTED.  This value is 'sticky' in that it will be
> > + * propagated to any child tasks that are spawned from an untrusted
> > + * task.
> > + *
> > + * In the case of an externally modeled security domain/namespace, the
> > + * task trust status cannot be determined until the modeling of the
> > + * security event has been completed.  The tsem_export_event()
> > + * function sets the trust status TSEM_TASK_TRUST_PENDING and then
> > + * places the task into an interruptible sleep state.
> > + *
> > + * Only two events will cause the task to be removed from sleep state.
> > + * Either the task is killed or a control message is written to the
> > + * TSEM control file that specifies the trust status of the task.  See
> > + * the description of the TSEM_CONTROL_TRUSTED and
> > + * TSEM_CONTROL_UNTRUSTED enumeration types.
> > + */
> > +enum tsem_task_trust {
> > +	TSEM_TASK_TRUSTED = 1,
> > +	TSEM_TASK_UNTRUSTED = 2,
> > +	TSEM_TASK_TRUST_PENDING = 4

> What happened to 3?

The enumerations represent bit values used in the 'trust_status'
member of the tsem_task structure.

If a task thinks that it has a trust status value of three it would
indicate the task needs massive doses of chlorpromazine.

> > +};
> > +
> > +/**
> > + * enum tsem_inode_state - Ordinal value for inode reference state.
> > + * @TSEM_INODE_COLLECTING: This ordinal value indicates that the uid/gid
> > + *			   values should be interpreted against the initial
> > + *			   user namespace.
> > + * @TSEM_INODE_COLLECTED: This ordinal value indicates that the uid/gid
> > + *			  values should be interpreted against the user
> > + *			  namespace that is in effect for the process being
> > + *		          modeled.
> > + *
> > + * This enumeration type is used to specify the status of the inode
> > + * that is having a digest value computed on the file that it is
> > + * referencing.  The purpose of this enumeration is so that the
> > + * recursive call to the TSEM_FILE_OPEN hook, caused by the kernel
> > + * opening the file to compute the checksum, can be bypassed.
> > + *
> > + * The state value of the inode is carried in struct tsem_inode and is
> > + * set and interrogated by the add_file_digest() function.  If the
> > + * status of the inode is TSEM_INODE_COLLECTED and the iversion of the
> > + * inode is the same as the collection time, the cached value for
> > + * currently active model digest is returned.
> > +
> > + * If the test for the relevancy of the cached digest value fails the
> > + * status of the inode is set to TSEM_INODE_COLLECTING.  The
> > + * tsem_file_open() function will check the inode status when it is
> > + * invoked by the integrity_kernel_read() function and if it is
> > + * set to 'collecting', a successful permissions check is returned so
> > + * that the kernel can open the file and compute its digest.
> > + */
> > +enum tsem_inode_state {
> > +	TSEM_INODE_COLLECTING = 1,
> > +	TSEM_INODE_COLLECTED
> > +};
> > +
> > +/**
> > + * struct tsem_task - TSEM task control structure.
> > + * @tma_for_ns: The context identity number of the namespace that
> > + *		the task has control over if any.
> > + * @trust_status: The enumeration type that specifies the trust state of
> > + *		  the process.
> > + * @task_id: The hash specific digest that identifies the process.
> > + * @task_key: A hash specific digest value that is used to
> > + *	      authenticate a task that is running as a trust
> > + *	      orchestrator to a task that is under the control of the
> > + *	      orchestrator.
> > + * @context: A pointer to the tsem_context structure that defines the
> > + *	     modeling context that the task is running under.
> > + *
> > + * This structure is one of the two primary control structures that
> > + * are implemented through the LSM blob functionality.  It is
> > + * automatically created when the task control structure is allocated
> > + * for a new task that is being created.  It's role is to control the
> > + * status of the task with respect to its security model.
> > + *
> > + * The trust_status member of structure determines whether or not the
> > + * task is in a condition to be trusted.  It represents whether or not
> > + * the task has requested execution of a security event that is
> > + * inconsistent with the model that the task is running under.
> > + * Reference the tsem_trust_status enumeration type for more
> > + * information on this member.  The trust status value is propagated
> > + * to any child tasks that are spawned from a task.
> > + *
> > + * The digest value that the task_id member contains is generated by
> > + * the tsem_tsem_bprm_creds_for_exec() function that computes the
> > + * task identity based on the COE identity and the CELL identity of
> > + * the executable that is being started.  This task_id value is used
> > + * in the computation of the security state point values in
> > + * combination with the COE and CELL identities for this event.  The
> > + * task_id digest creates security state points that are specific to
> > + * the executable file that was used to start the task.
> > + *
> > + * The task_key member holds the authentication key that will be used
> > + * to authenticate a process that is requesting the ability to set the
> > + * trust status of a process.  This value is generated for the task
> > + * structure of the trust orchestrator when a security modeling
> > + * namespace is created by the orchestrator.
> > + *
> > + * As an additional protection, the creation of a namespace causes the
> > + * context id of the created namespace to be placed in the task that
> > + * will serve as the trust orchestrator for the namespace.  This
> > + * context id must match the context id of a process that a trust
> > + * control request is being sent to.  Like the authentication key
> > + * this value is not propagated on task allocation so only the task
> > + * that has nominated the security modeling namespace will have
> > + * possession of the necessary credentials to control it.
> > + *
> > + * The context member of the structure contains a pointer to the
> > + * tsem_context structure allocated when a security modeling namespace
> > + * is created by the tsem_ns_create() function.  This structure will
> > + * contain all of the information needed to define how the task is to
> > + * have its security behavior modeled.
> > + */
> > +struct tsem_task {
> > +	u64 tma_for_ns;
> > +	enum tsem_task_trust trust_status;
> > +	u8 task_id[HASH_MAX_DIGESTSIZE];
> > +	u8 task_key[HASH_MAX_DIGESTSIZE];
> > +	struct tsem_context *context;
> > +};
> > +
> > +/**
> > + * struct tsem_context - TSEM modeling context description.
> > + * @kref: Reference count for the context.
> > + * @work: Work structure for delayed release of the context.
> > + * @id: The index number of the context.
> > + * @sealed: Status variable indicating whether or not the
> > + *	    modeling context can be modified.
> > + * @use_current_ns: Status variable indicating which user namespace
> > + *		    should be used for resolution of uid/gid values.
> > + * @actions: An array of enum tsem_action_type variables indicating
> > + *	     the type of response that should be returned in
> > + *	     response to the modeling of a security event that
> > + *	     is inconsistent with the model being used for the
> > + *	     security context.
> > + * @digestname: A pointer to a null-terminated buffer containing the
> > + *		name of the digest function that is to be used for
> > + *		this security context.
> > + * @zero_digest: The digest value for a 'zero-length' digest value.
> > + * @tfm: A pointer to the digest transformation structure that is to
> > + *	 be used for this context.
> > + * @magazine_size: The number of struct tsem_event structures that
> > + *		   are held in reserve for security event hooks that
> > + *		   are called in atomic context.
> > + * @magazine_lock: The spinlock that protects access to the event
> > + *		   magazine for the security context.
> > + * @magazine_index: The bitmap that is used to track the magazine slots
> > + *		    that have been allocated.
> > + * @ws: An array of work structures that are used to refill the magazine
> > + *	slots.
> > + * @magazine: An array of pointers to struct tsem_event structures that
> > + *	      are pre-allocated for security hooks called in atomic
> > + *	      context.
> > + * @model: If the modeling context is implemented with a kernel based
> > + *	   trusted model agent this pointer will point to the struct
> > + *	   tsem_model structure that maintains the state of the
> > + *	   security model.
> > + * @external: If the modeling context is implemented with an external
> > + *	      modeling agent this pointer will point to the struct
> > + *	      tsem_external structure that implements the interface to
> > + *	      the external trusted modeling agent.
> > +
> > + * This structure is used to represent the state of a TSEM security
> > + * modeling namespace.  A pointer to this structure is stored in the
> > + * struct tsem_task structure.
> > + *
> > + * This structure is allocated by the tsem_ns_create() function in
> > + * response to a TSEM control request.  This structure maintains all
> > + * of the information that describes the security modeling namespace
> > + * that is not specific to the type of namespace, ie. external or
> > + * internal that is being implemented.
> > +
> > + * The id member is a 64-bit counter that cannot feasibly be
> > + * overflowed and that is incremented for each namespace creation that
> > + * is created.  The root modeling namespace has a value of zero so the
> > + * TSEM code uses a pattern of testing this value for non-zero status
> > + * as an indication of whether or not the task is running in a
> > + * subordinate modeling namespace.
> > +
> > + * Each security modeling namespace can have an independent
> > + * cryptographic digest function that is used as the compression
> > + * function for generating the digest values that are used to model
> > + * the security events that occur in a namespace.  A single struct tfm
> > + * is allocated for this digest function at the time that the
> > + * tsem_context structure is created and is maintained in this
> > + * structure for subsequent use during event processing.
> > +
> > + * Each cryptographic digest function has a 'zero message' value that
> > + * is the result of the initialization and closure of a hash function
> > + * that has no other input.  This zero digest value is computed at the
> > + * time of the creation of the array.  This digest value is returned
> > + * for files with zero sizes or that have pseudonyms declared for
> > + * them.
> > + *
> > + * The actions array contains a specification of how each security
> > + * event should be handled in the event that the model detects a
> > + * security event consistent with the model designated for the
> > + * namespace.  This array allows the specification of whether the
> > + * model should be enforcing or logging.  Currently the specification
> > + * is all or nothing for all of the events, with plans to make the
> > + * actions individually configurable.
> > +
> > + * Each security event that is processed requires a struct tsem_event
> > + * structure that drives either the internal modeling of an event or
> > + * its export to an external modeling agent.  Some security event
> > + * hooks are called while a task is running in atomic context. Since
> > + * memory cannot be allocated while a process is in atomic context, a
> > + * magazine of these structures is maintained by this structure for
> > + * security events that run in atomic context.  The size of this
> > + * magazine is dynamic and is configurable for each security modeling
> > + * namespace that is created.
> > + *
> > + * When a tsem_event structure is allocated for an atomic event a
> > + * request for the refill of the slot that is vacated is dispatched to
> > + * an asynchronous workqueue.  The ws member of this structure points
> > + * to an array of work structures for this refill capability, one for
> > + * each slot in the magazine.
> > + *
> > + * All of this infrastructure is generic for each security modeling
> > + * namespace.  How the security modeling is done is governed by the
> > + * model and external members of this structure.  These members point
> > + * to data structures that either maintain the security model state
> > + * for an in kernel trusted modeling agent or handle the export of the
> > + * event to an external trusted modeling agent.
> > + *
> > + * Each task that is created in a non-root security modeling namespace
> > + * increments the reference count maintained in the kref member of
> > + * this structure in the tsem_task_alloc() function.  The
> > + * tsem_task_free() function decrements this reference count.  When
> > + * the reference count expires, ie. when the last task using the
> > + * modeling namespace exits, an asynchronous workqueue request is
> > + * dispatched to dispose of the context.  The work member of this
> > + * structure is used to reference that workqueue request.
> > + */
> > +struct tsem_context {
> > +	struct kref kref;
> > +	struct work_struct work;
> > +
> > +	u64 id;
> > +	bool sealed;
> > +	bool use_current_ns;
> > +
> > +	enum tsem_action_type actions[TSEM_EVENT_CNT];
> > +
> > +	char *digestname;
> > +	u8 zero_digest[HASH_MAX_DIGESTSIZE];
> > +	struct crypto_shash *tfm;
> > +
> > +	unsigned int magazine_size;
> > +	spinlock_t magazine_lock;
> > +	unsigned long *magazine_index;
> > +	struct tsem_work *ws;
> > +	struct tsem_event **magazine;
> > +
> > +	struct tsem_model *model;
> > +	struct tsem_external *external;
> > +};

> Odd use of whitespace in the structure definition.

It is a carry over from our userspace coding style.  As a team we have
found it helpful to visually segregate members of a structure that
have a common and distinct purpose.

FWIW, it would seem that include/linux/sched.h seems to embrace
a similar concept for 'struct task_struct'.

[ ... rest of tsem.h trimmed ... ]

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 04/13] Add TSEM master header file.
  2023-08-10  2:57     ` Dr. Greg
@ 2023-08-10 15:03       ` Casey Schaufler
  0 siblings, 0 replies; 36+ messages in thread
From: Casey Schaufler @ 2023-08-10 15:03 UTC (permalink / raw)
  To: Dr. Greg; +Cc: linux-security-module, linux-kernel, corbet, Casey Schaufler

On 8/9/2023 7:57 PM, Dr. Greg wrote:
> On Mon, Aug 07, 2023 at 01:39:22PM -0700, Casey Schaufler wrote:
>
> Hi Casey, thank you for the review comments.
>
>> On 7/10/2023 3:23 AM, Dr. Greg wrote:
>>> TSEM is designed, from a functional perspective, to be contained
>>> entirely in its own directory.
>>>
>>> The tsem.h header file defines the enumeration types, structure
>>> definitions and externally visiable functions that are referenced
>>> by all of the compilation units of the TSEM LSM implementation in
>>> that directory.
>> Extensive documentation notwithstanding, it's impossible to review
>> the data structures and constants without the code that goes along
>> with them.
> ...
>
> We may have missed it but I don't see anything in the kernel
> developers guide with respect best practices for introducing blocks of
> entire sub-system code.
>
> Recommendations welcome.

You've broken the code into progressive units. Include the data structure
definitions as required in those progressive units. Include the .h's as
they are needed by the .c's.

>
>>> The structure and enumeration types are extensively documented
>>> and are the recommended starting point for understanding TSEM
>>> implementation and functionality.
>>>
>>> Signed-off-by: Greg Wettstein <greg@enjellic.com>
>>> ---
>>>  security/tsem/tsem.h | 1516 ++++++++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 1516 insertions(+)
>>>  create mode 100644 security/tsem/tsem.h
>>>
>>> diff --git a/security/tsem/tsem.h b/security/tsem/tsem.h
>>> new file mode 100644
>>> index 000000000000..03915f47529b
>>> --- /dev/null
>>> +++ b/security/tsem/tsem.h
>>> @@ -0,0 +1,1516 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>> +
>>> +/*
>>> + * Copyright (C) 2023 Enjellic Systems Development, LLC
>>> + * Author: Dr. Greg Wettstein <greg@enjellic.com>
>>> + *
>>> + * This is the single include file that documents all of the externally
>>> + * visible types and functions that are used by TSEM.  This file is
>>> + * currently organized into four major sections in the following order;
>>> + *
>>> + * includes used by all compilation units
>>> + * CPP definitions
>>> + * enumeration types
>>> + * structure definitions
>>> + * function declarations
>>> + * inline encapsulation functions.
>>> + *
>>> + * Include files that are referenced by more than a single compilation
>>> + * should be included in this file.  Includes that are needed to
>>> + * satisfy compilation requirements for only a single file should be
>>> + * included in the file needing that include.
>>> + *
>>> + * Understanding the overall implementation and architecture of TSEM
>>> + * will be facilitated by reviewing the documentation in this file.
>>> + */
>>> +
>>> +#include <uapi/linux/in.h>
>>> +#include <uapi/linux/in6.h>
>>> +#include <linux/wait.h>
>>> +#include <linux/kref.h>
>>> +#include <linux/lsm_hooks.h>
>>> +#include <linux/capability.h>
>>> +#include <crypto/hash.h>
>>> +#include <crypto/hash_info.h>
>>> +#include <net/af_unix.h>
>>> +
>>> +/* The capability needed to manage TSEM. */
>>> +#define TSEM_CONTROL_CAPABILITY CAP_ML
>> Why would you do this? You gave the capability a name that even you
>> don't want to use.
> A simple placeholder that allows the capability used to control
> security modeling to be set in one place, and one place only, until
> the debate over the capability issue is settled.
>
> We never envisioned this define lasting beyond the initial reviews.

Intentional obfuscation is never going to make the review process
easier. I have enough trouble following clear and obvious code. I'm
going to search for CAP_ during a review. You just made that harder. 

> ...
>
> +
> +/**
> + * enum tsem_task_trust - Ordinal value describing task trust status.
> + * @TSEM_TASK_TRUSTED: This ordinal value indicates that the task has
> + *		       not executed a security event that has resulted
> + *		       in a security behavior not described by the
> + *		       security model the task is being governed by.
> + * @TSEM_TASK_UNTRUSTED: This ordinal value indicates that the task
> + *		          has requested the execution of a security event
> + *		          that resulted in a security behavior not
> + *		          permitted by the security model the task is
> + *		          being governed by.
> + * @TSEM_TASK_TRUST_PENDING: This ordinal value indicates that the setting
> + *			     of the task trust status is pending a response
> + *		             from an external TMA.
> + *
> + * This enumeration type is used to specify the three different trust
> + * states that a task can be in.  The trust status of a task is
> + * regulated by the trust_status member of struct tsem_task.  A task
> + * carrying the status of TSEM_TASK_TRUSTED means that it has
> + * not requested the execution of any security events that are
> + * inconsistent with the security model that the task is running in.
> + *
> + * If a task requests execution of a security event that is
> + * inconsistent with the security model it is operating in, and the
> + * domain is running in 'sealed' mode, the task trust status is set to
> + * TSEM_TASK_UNTRUSTED.  This value is 'sticky' in that it will be
> + * propagated to any child tasks that are spawned from an untrusted
> + * task.
> + *
> + * In the case of an externally modeled security domain/namespace, the
> + * task trust status cannot be determined until the modeling of the
> + * security event has been completed.  The tsem_export_event()
> + * function sets the trust status TSEM_TASK_TRUST_PENDING and then
> + * places the task into an interruptible sleep state.
> + *
> + * Only two events will cause the task to be removed from sleep state.
> + * Either the task is killed or a control message is written to the
> + * TSEM control file that specifies the trust status of the task.  See
> + * the description of the TSEM_CONTROL_TRUSTED and
> + * TSEM_CONTROL_UNTRUSTED enumeration types.
> + */
> +enum tsem_task_trust {
> +	TSEM_TASK_TRUSTED = 1,
> +	TSEM_TASK_UNTRUSTED = 2,
> +	TSEM_TASK_TRUST_PENDING = 4
>> What happened to 3?
> The enumerations represent bit values used in the 'trust_status'
> member of the tsem_task structure.

Someone can correct me if I'm wrong, but I think that's a misuse
of enum. 

>
> If a task thinks that it has a trust status value of three it would
> indicate the task needs massive doses of chlorpromazine.

If you're not using logical operations (&, |) why do you care if
they're "bit values"?

> ...
>
> + *
> + * Each task that is created in a non-root security modeling namespace
> + * increments the reference count maintained in the kref member of
> + * this structure in the tsem_task_alloc() function.  The
> + * tsem_task_free() function decrements this reference count.  When
> + * the reference count expires, ie. when the last task using the
> + * modeling namespace exits, an asynchronous workqueue request is
> + * dispatched to dispose of the context.  The work member of this
> + * structure is used to reference that workqueue request.
> + */
> +struct tsem_context {
> +	struct kref kref;
> +	struct work_struct work;
> +
> +	u64 id;
> +	bool sealed;
> +	bool use_current_ns;
> +
> +	enum tsem_action_type actions[TSEM_EVENT_CNT];
> +
> +	char *digestname;
> +	u8 zero_digest[HASH_MAX_DIGESTSIZE];
> +	struct crypto_shash *tfm;
> +
> +	unsigned int magazine_size;
> +	spinlock_t magazine_lock;
> +	unsigned long *magazine_index;
> +	struct tsem_work *ws;
> +	struct tsem_event **magazine;
> +
> +	struct tsem_model *model;
> +	struct tsem_external *external;
> +};
>> Odd use of whitespace in the structure definition.
> It is a carry over from our userspace coding style.  As a team we have
> found it helpful to visually segregate members of a structure that
> have a common and distinct purpose.
>
> FWIW, it would seem that include/linux/sched.h seems to embrace
> a similar concept for 'struct task_struct'.

I'm not formally objecting to it, but there's no obvious reason for it.

>
> [ ... rest of tsem.h trimmed ... ]
>
> As always,
> Dr. Greg
>
> The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 05/13] Add primary TSEM implementation file.
  2023-08-07 21:00   ` Casey Schaufler
@ 2023-08-11  7:21     ` Dr. Greg
  0 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2023-08-11  7:21 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: linux-security-module, linux-kernel, corbet

On Mon, Aug 07, 2023 at 02:00:12PM -0700, Casey Schaufler wrote:

Thank you for this review.

> On 7/10/2023 3:23 AM, Dr. Greg wrote:
> > The tsem.c file is the 'master' file in the TSEM implementation.
> > It is responsible for initializing the LSM and providing
> > implementions of the security event hooks implemented by TSEM.
> >
> > In addition to initializing the LSM, the set_ready() function
> > implements a secondary initialization that is used to to indicate
> > that security event modeling can begin.  This is required
> > secondary to the fact that the cryptographic API's do not become
> > ready until after the 'fs' phase of system initialization is
> > complete.
> >
> > This file also handles the implementation of kernel command-line
> > parameters that are used to configure the root security modeling
> > namespace.
> >
> > The 'tsem_mode' parameter, if set to a value of 1, causes modeling
> > to be not conducted for the root security modeling namespace.
> > One use case is to allow development platform to develop security
> > models without the overhead of full platform modeling.
> >
> > The 'tsem_digest' parameter is used to set the cryptographic hash
> > function that is used to generate security state coefficients in
> > the root model.  TSEM can use any cryptographic hash function
> > implemented in the kernel, on a namespace by namespace basis.
> > Subordinate modeling namespaces can select their hash function
> > as part of the namespace creation process but the 'tsem_digest'
> > parameter has to be used to set the function for the root
> > modeling namespace.
> >
> > The hash function used in the root modeling namespace but be
> > compiled into the kernel since the function is used before module
> > loading becomes available.  The TSEM kernel configuration selects
> > the SHA256 function to be included as the default cryptographic
> > modeling function.
> >
> > The 'tsem_cache' variable sets the size of the pre-allocated
> > structures that are used for security event modeling in the root
> > modeling namespace.  This cache is used to support the modeling
> > and export of events that run in atomic context.  The cache size
> > can be set independently for each subordinate security modeling
> > on a namespace by namespace basis.
> >
> > This file also contains the implementation of the tsem_names
> > array that contains the ASCII text names that are assigned to
> > each security event handler.  This name is used as one of the
> > characteristics in the security state points that are generated.
> > This array is also used to provide symbolic names for the export
> > of security event descriptions, either through the TSEM control
> > plane or for export to external trust orchestrators.
> >
> > Signed-off-by: Greg Wettstein <greg@enjellic.com>
> > ---
> >  security/tsem/tsem.c | 1987 ++++++++++++++++++++++++++++++++++++++++++

> Please use kernel doc comments throughout.

At this point we have standardized on using kernel doc comments for
externally visible entities only but we will take a gander at this
file to see if we have missed anything.

> I've made a few minor comments below, but you need to break this up
> somehow for review. Also, having the data definitions elsewhere
> makes review tough.

We will defer to this issue being covered elsewhere.

> >  1 file changed, 1987 insertions(+)
> >  create mode 100644 security/tsem/tsem.c
> >
> > diff --git a/security/tsem/tsem.c b/security/tsem/tsem.c
> > new file mode 100644
> > index 000000000000..8ec630354240
> > --- /dev/null
> > +++ b/security/tsem/tsem.c
> > @@ -0,0 +1,1987 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +
> > +/*
> > + * Copyright (C) 2023 Enjellic Systems Development, LLC
> > + * Author: Dr. Greg Wettstein <greg@enjellic.com>
> > + *
> > + * TSEM initialization infrastructure.
> > + */
> > +#define TRAPPED_MSG_LENGTH 128
> > +
> > +#define LOCKED true
> > +#define NOLOCK false
> > +
> > +#include <linux/magic.h>
> > +#include <linux/mman.h>
> > +#include <linux/binfmts.h>
> > +#include <linux/bpf.h>
> > +#include <linux/ipv6.h>
> > +
> > +#include "tsem.h"
> > +
> > +struct lsm_blob_sizes tsem_blob_sizes __ro_after_init = {
> > +	.lbs_task = sizeof(struct tsem_task),

> Do you really want this for the task? It would seem you might want
> to use the cred blob instead.

We would be interested in why you believe the cred blob to be superior.

For those reading along at home the 'struct tsem_task' is as follows:

struct tsem_task {
	u64 tma_for_ns;
	enum tsem_task_trust trust_status;
	u8 task_id[HASH_MAX_DIGESTSIZE];
	u8 task_key[HASH_MAX_DIGESTSIZE];
	struct tsem_context *context;
};

Credentials seem to imply some type of permission.  We look at this
basket of information as relevant to determining how the task will be
modeled and whether or not the task has deviated from its model definition.

> > +	.lbs_inode = sizeof(struct tsem_inode)
> > +};
> > +
> > +enum tsem_action_type tsem_root_actions[TSEM_EVENT_CNT] = {
> > +	TSEM_ACTION_EPERM	/* Undefined. */
> > +};
> > +
> > +static struct tsem_model root_model = {
> > +	.point_lock = __SPIN_LOCK_INITIALIZER(root_model.point_lock),
> > +	.point_list = LIST_HEAD_INIT(root_model.point_list),
> > +	.point_end_mutex = __MUTEX_INITIALIZER(root_model.point_end_mutex),
> > +
> > +	.trajectory_lock = __SPIN_LOCK_INITIALIZER(root_model.trajectory_lock),
> > +	.trajectory_list = LIST_HEAD_INIT(root_model.trajectory_list),
> > +	.trajectory_end_mutex = __MUTEX_INITIALIZER(root_model.trajectory_end_mutex),
> > +
> > +	.forensics_lock = __SPIN_LOCK_INITIALIZER(root_model.forensics_lock),
> > +	.forensics_list = LIST_HEAD_INIT(root_model.forensics_list),
> > +	.forensics_end_mutex = __MUTEX_INITIALIZER(root_model.forensics_end_mutex),
> > +
> > +	.pseudonym_mutex = __MUTEX_INITIALIZER(root_model.pseudonym_mutex),
> > +	.pseudonym_list = LIST_HEAD_INIT(root_model.pseudonym_list)
> > +};
> > +
> > +static struct tsem_context root_context;
> > +
> > +static int tsem_ready __ro_after_init;
> > +
> > +static bool tsem_available __ro_after_init;
> > +
> > +static unsigned int magazine_size __ro_after_init = TSEM_ROOT_MAGAZINE_SIZE;
> > +
> > +static bool no_root_modeling __ro_after_init;
> > +
> > +static char *default_hash_function __ro_after_init;
> > +
> > +static int __init set_magazine_size(char *magazine_value)
> > +{
> > +	if (kstrtouint(magazine_value, 0, &magazine_size))
> > +		pr_warn("tsem: Failed to parse root cache size.\n");
> > +
> > +	if (!magazine_size) {
> > +		pr_warn("tsem: Forcing non-zero cache size.\n");
> > +		magazine_size = TSEM_ROOT_MAGAZINE_SIZE;
> > +	}
> > +
> > +	pr_info("tsem: Setting default root cache size to %u.\n",
> > +		magazine_size);
> > +	return 1;
> > +}
> > +__setup("tsem_cache=", set_magazine_size);
> > +
> > +static int __init set_modeling_mode(char *mode_value)
> > +{
> > +	unsigned long mode = 0;
> > +
> > +	if (kstrtoul(mode_value, 0, &mode)) {
> > +		pr_warn("tsem: Failed to parse modeling mode.\n");
> > +		return 1;
> > +	}
> > +
> > +	if (mode == 1)
> > +		no_root_modeling = true;
> > +	else
> > +		pr_warn("tsem: Unknown mode specified.\n");
> > +	return 1;
> > +}
> > +__setup("tsem_mode=", set_modeling_mode);
> > +
> > +static int __init set_default_hash_function(char *hash_function)
> > +{
> > +
> > +	default_hash_function = hash_function;
> > +	return 1;
> > +}
> > +__setup("tsem_digest=", set_default_hash_function);
> > +
> > +const char * const tsem_names[TSEM_EVENT_CNT] = {
> > +	"undefined",
> > +	"bprm_set_creds",
> > +	"generic_event",
> > +	"task_kill",
> > +	"task_setpgid",
> > +	"task_getpgid",
> > +	"task_getsid",
> > +	"task_setnice",
> > +	"task_setioprio",
> > +	"task_getioprio",
> > +	"task_prlimit",
> > +	"task_setrlimit",
> > +	"task_setscheduler",
> > +	"task_getscheduler",
> > +	"task_prctl",
> > +	"file_open",
> > +	"mmap_file",
> > +	"file_ioctl",
> > +	"file_lock",
> > +	"file_fcntl",
> > +	"file_receive",
> > +	"unix_stream_connect",
> > +	"unix_may_send",
> > +	"socket_create",
> > +	"socket_connect",
> > +	"socket_bind",
> > +	"socket_accept",
> > +	"socket_listen",
> > +	"socket_socketpair",
> > +	"socket_sendmsg",
> > +	"socket_recvmsg",
> > +	"socket_getsockname",
> > +	"socket_getpeername",
> > +	"socket_setsockopt",
> > +	"socket_shutdown",
> > +	"ptrace_traceme",
> > +	"kernel_module_request",
> > +	"kernel_load_data",
> > +	"kernel_read_file",
> > +	"sb_mount",
> > +	"sb_umount",
> > +	"sb_remount",
> > +	"sb_pivotroot",
> > +	"sb_statfs",
> > +	"move_mount",
> > +	"shm_associate",
> > +	"shm_shmctl",
> > +	"shm_shmat",
> > +	"sem_associate",
> > +	"sem_semctl",
> > +	"sem_semop",
> > +	"syslog",
> > +	"settime",
> > +	"quotactl",
> > +	"quota_on",
> > +	"msg_queue_associate",
> > +	"msg_queue_msgctl",
> > +	"msg_queue_msgsnd",
> > +	"msg_queue_msgrcv",
> > +	"ipc_permission",
> > +	"key_alloc",
> > +	"key_permission",
> > +	"netlink_send",
> > +	"inode_create",
> > +	"inode_link",
> > +	"inode_unlink",
> > +	"inode_symlink",
> > +	"inode_mkdir",
> > +	"inode_rmdir",
> > +	"inode_mknod",
> > +	"inode_rename",
> > +	"inode_setattr",
> > +	"inode_getattr",
> > +	"inode_setxattr",
> > +	"inode_getxattr",
> > +	"inode_listxattr",
> > +	"inode_removexattr",
> > +	"inode_killpriv",
> > +	"tun_dev_create",
> > +	"tun_dev_attach_queue",
> > +	"tun_dev_attach",
> > +	"tun_dev_open",
> > +	"bpf",
> > +	"bpf_map",
> > +	"bpf_prog"
> > +};
> > +
> > +static const int pseudo_filesystems[] = {
> > +	PROC_SUPER_MAGIC,
> > +	SYSFS_MAGIC,
> > +	DEBUGFS_MAGIC,
> > +	TMPFS_MAGIC,
> > +	DEVPTS_SUPER_MAGIC,
> > +	BINFMTFS_MAGIC,
> > +	SECURITYFS_MAGIC,
> > +	SELINUX_MAGIC,
> > +	SMACK_MAGIC,
> > +	CGROUP_SUPER_MAGIC,
> > +	CGROUP2_SUPER_MAGIC,
> > +	NSFS_MAGIC,
> > +	EFIVARFS_MAGIC
> > +};
> > +
> > +static bool bypass_inode(struct inode *inode)
> > +{
> > +	bool retn = true;
> > +
> > +	unsigned int lp;
> > +
> > +	if (!S_ISREG(inode->i_mode))
> > +		goto done;
> > +
> > +	for (lp = 0; lp < ARRAY_SIZE(pseudo_filesystems); ++lp)
> > +		if (inode->i_sb->s_magic == pseudo_filesystems[lp])
> > +			goto done;
> > +	retn = false;
> > +
> > + done:
> > +	return retn;
> > +}
> > +
> > +static int event_action(struct tsem_context *ctx, enum tsem_event_type event)
> > +{
> > +	int retn = 0;
> > +
> > +	if (tsem_task_trusted(current))
> > +		return retn;
> > +
> > +	if (ctx->actions[event] == TSEM_ACTION_EPERM)
> > +		retn = -EPERM;
> > +
> > +	return retn;
> > +}
> > +
> > +static int return_trapped_task(enum tsem_event_type event, char *msg,

> Why isn't this simply "trapped_task()"?

Probably because at the time the code was written we were thinking of
it as a declarative name for what the function did, ie. it returns the
permission value for a task that has been trapped by a security event
handler because the task was considered to be in an untrusted state.

Since it is consistently used as an argument to the return command we
will drop the return_ prefix.

> > +			       bool locked)
> > +{
> > +	int retn;
> > +	struct tsem_context *ctx = tsem_context(current);
> > +
> > +	pr_warn("Untrusted %s: comm=%s, pid=%d, parameters='%s'\n",
> > +		tsem_names[event], current->comm, task_pid_nr(current), msg);
> > +
> > +	if (ctx->external) {
> > +		retn = tsem_export_action(event, locked);
> > +		if (retn)
> > +			return retn;
> > +	}
> > +
> > +	return event_action(ctx, event);
> > +}
> > +
> > +static int return_trapped_inode(enum tsem_event_type event,

> Again, really odd function name.

Same reasoning as above and we will drop the return_ prefix.

> ... and that's all I have time for.

We do appreciate all modicum's of time that people are willing to
extend to this.

Have a good day.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/13] Add TSEM specific documentation.
  2023-08-08 18:48   ` Serge Hallyn
@ 2023-08-11 20:22     ` Dr. Greg
  2024-01-04 15:54       ` Paul Moore
  0 siblings, 1 reply; 36+ messages in thread
From: Dr. Greg @ 2023-08-11 20:22 UTC (permalink / raw)
  To: Serge Hallyn; +Cc: linux-security-module, linux-kernel, corbet

On Tue, Aug 08, 2023 at 01:48:25PM -0500, Serge Hallyn wrote:

Good afternoon Serge, thank you for the comments.

> On Mon, Jul 10, 2023 at 05:23:08AM -0500, Dr. Greg wrote:
> > An entry was added to the ABI testing documentation to document

> "Add an entry..." is the usual way to document this in commit msg.

Will modify the commit message when there is a need for it to
reappear.

> > the files in the TSEM management filesystem.
> > 
> > The file documenting the kernel command-line parameters was
> > updated to document the TSEM specific command-line parameters

> A commit's actions are more normally in present tens ("The file
> documenting the kernel command-line parameters is")

Will also correct the diction used here.

> > The primary TSEM documentation file was added to the LSM
> > administration guide and the file was linked to the index of LSM
> > documentation.
> > 
> > Signed-off-by: Greg Wettstein <greg@enjellic.com>
> > ---
> >  Documentation/ABI/testing/tsem                |  828 +++++++++
> >  Documentation/admin-guide/LSM/index.rst       |    1 +
> >  Documentation/admin-guide/LSM/tsem.rst        | 1526 +++++++++++++++++
> >  .../admin-guide/kernel-parameters.txt         |   18 +
> >  4 files changed, 2373 insertions(+)
> >  create mode 100644 Documentation/ABI/testing/tsem
> >  create mode 100644 Documentation/admin-guide/LSM/tsem.rst
> > 
> > diff --git a/Documentation/ABI/testing/tsem b/Documentation/ABI/testing/tsem
> > new file mode 100644
> > index 000000000000..cfb013b5f1f4
> > --- /dev/null
> > +++ b/Documentation/ABI/testing/tsem
> > @@ -0,0 +1,828 @@
> > +What:		/sys/kernel/security/tsem
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The /sys/kernel/security/tsem directory contains files
> > +		and directories that implement the control plane for
> > +		the Trusted Security Event Modeling (TSEM) LSM.
> > +
> > +		The files in this directory hierarchy, with the
> > +		exception of the aggregate file, when read, reflect
> > +		the values for the security modeling namespace that
> > +		the process reading the files is operating in.
> > +
> > +What:		/sys/kernel/security/tsem/id
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The id file contains the ASCII base 10 representation

> Why not use base 16 here?  Mixing bases amongst the files could get
> confusing.

No reason not to, the primary entities reading the file are external
trust orchestrators.

We will prefix it with 0x to make it easy for strtol running in '0'
mode.

> > +		of the model domain/namespace identifier that the
> > +		reading process is operating in.
> > +
> > +		The root security modeling namespace has a value of
> > +		zero, a non-zero value indicates a modeling namespace
> > +		subordinate to the root model.
> > +
> > +		Each externally modeled domain will have a file, with
> > +		this id number, created in the
> > +		/sys/kernel/security/tsem/ExternalTMA directory that
> > +		is documented below.
> > +
> > +What:		/sys/kernel/security/tsem/aggregate
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The aggregate file contains the ASCII base 16
> > +		representation of the 256 bit hardware platform
> > +		aggregate that TSEM is modeling under.  The platform
> > +		aggregate is the linear extension measurement of the
> > +		Trusted Platform Module PCR registers 0 through 8.
> > +
> > +		On a platform without a TPM this value will be all
> > +		null bytes.
> > +
> > +What:		/sys/kernel/security/tsem/control
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The control file is the only writable file in the
> > +		filesystem and is used by the trust orchestrator's to
> > +		configure and control the behavior of the TSEM
> > +		implementation.
> > +
> > +		The following keyword and arguments are recognized:
> > +
> > +		internal
> > +			The internal keyword causes an internally
> > +			modeled domain to be created for the calling
> > +			process.
> > +
> > +		external
> > +			The external keyword causes an externally
> > +			modeled domain to be created for the calling
> > +			process.
> > +
> > +			A modeling namespace created by these commands
> > +			accept the following set of key=value pairs
> > +			that configure the namespace:
> > +
> > +			nsref=initial|current
> > +				The nsref key specifies the namespace
> > +				that is to be referenced when
> > +				determining the UID/GID values that
> > +				define a COE or CELL identity.
> > +
> > +				The initial keyword specifies that the
> > +				initial user namespace be used.  The
> > +				current keyword specifies that the
> > +				user namespace of the process that is
> > +				invoking a security event handler
> > +				(hook) is used.

> Hm, does this allow a process in a container to escape the
> container's policy, by creating a new domain inheriting from the
> initial userns?

First, to seek some clarification.

When you write 'container policy', are you referring to a TSEM
security model or a uid/gid userns mapping or other OCI container
security policy?

Casey had commented, in an unrelated thread, that 'domain' is
over-used, so we have standardized on 'security modeling namespace'.
I see above that we missed a case where we used domain in the
document, so we will fix that and assume that by 'creating a new
domain' you mean a new security modeling namespace.

FWIW, for TSEM, we have standardized on 'security model' rather than
policy for similar reasons.

Security modeling namespaces are, by design, only one level deep.  The
trust orchestrators drop CAP_WHATEVER after setting up a modeling
namespace, this locks the workload into whatever security model was
specified for the security modeling namespace with no opportunity for
the workload to change model context.

> > +TSEM implements its equivalent of mandatory access controls, without a
> > +requirement for extended attributes, filesystem labeling or the need
> > +to protect filesystem metadata against offline attack.  A mathematical

> If the security policy is that no data from /dev/tty, because it is
> untrusted, may flow into high integrity files, then how do you track
> the files which are high integrity, without labeling high integrity
> files?  You're intending for the agent to track the files using
> inode number and fsid?

The CELL identity generative function for a file access encodes the
pathname to the file.  Access to the file will need to be through a
security event that generates a security state coefficient that
derives from a CELL identity referencing the file.

Moving forward, we will be adding support to include security labels
from extended attributes in the CELL identity generation function, in
order to allow security policies that are not dependent on pathnames.

Further, the generative function for the security state coefficient
includes the concept of a 'task id' that serves to restrict
information flow only through a specific corpus of executable code
that is anchored by a cryptographic digest of said code.

> > +The root security model extends each security state coefficient into a
> > +PCR.  The default PCR is 11 but is configurable through the kernel

> Note pcr 11 will conflict with systemd's usage
> 
> https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/

Thank you for providing the reference, we will choose the next
available PCR according to that document.

> > +It is up to the trust orchestrator and its security policy to
> > +determine how it handles events that violate the security model being
> > +enforced.  The Quixote trust orchestrators shut down the entire
> > +workload running in the security namespace if an asynchronously
> > +modeled event violates the security model being enforced and the model
> > +is running in enforcing mode.

> So instead of returning EPERM, you'll let the process speculatively
> continue until quixote has a chance to catch up and return a "no not
> allowed" message, after which the whole workload will be killed?

For an externally modeled namespace, that is currently the only option
available.

The trust orchestrator also has the ability to set the task trust
status to untrusted, if the process still exists, which would block
any subsequent attempts to invoke security sensitive operations.

We've received a fair amount of feedback, that even if the workload
doesn't get killed, people feel that it is useful to quickly find out,
with a high degree of precision, that a workload is in the process of
getting p0wned.

The latency to action time isn't a function of quixote 'catching up',
but rather a function of how long the TMA takes to run the security
coefficient generative function and determine the provenance of the
event in the context of the operative security model.  That varies
with the TMA implementation, with the stock userspace implementation
taking in the range of 400-700 micro-seconds.

The only way to fix this is to implement a completion callback LSM
hook that can be invoked after the initial LSM hook was called from
atomic context and asynchronously submits the security event
characteristics to the TMA.  We have patches for internal use to do
this, but hopefully from an understandable perspective, no appetite
for submitting something like that.

This limitation isn't inconsistent with how security is getting done
in the wild with agent based systems.  An example from what we have
the most experience and visibility into.

CrowdStrike's NGAV product advertises the use of 'Cloud based
artificial intelligence, behavioral detection and machine learning
algorithms for threat detection and exploit mitigation'.

I think it can be stated, with a reasonably high degree of confidence,
that all of that doesn't typically occur within ~500 micro-seconds
after an event occurs that is inconsistent with the desired security
state of a workload/platform.

Finally, if any delay in response is unacceptable, TSEM offers the
ability to run the TMA implementation in the kernel where it would not
suffer from this limitation.

> > +From a hardware perspective, this is important with respect to the
> > +notion of a TMA being a model for a successor to the TPM.  From a
> > +system trust or integrity perspective, a TPM is designed to provide a
> > +retrospective assessment of the actions that have occurred on a
> > +platform.  A verifying party uses the TPM event log and a PCR based
> > +summary measurement, to verify what actions have occurred on the host,
> > +in order to allow a determination of whether or not the platform
> > +should be 'trusted'.

> FWIW TPM EA policies also refuse access to secrets based on those
> and other data.  It's not purely for retrospective assessment.  But
> indeed TPM does not authorize actions as trusted.  Not because it
> fails to do so but because it's not part of its design.

No argument there and no criticism of TPM's at large implied by any of
what we are proposing.

Technology has changed significantly in the 23+ years since TPM's were
introduced and we believe that the concept of a TMA, regardless of
where it is implemented, introduces the possibility of a more useful
superset of TPM type security capabilities.

> > +In contrast, a TSEM/TMA based system enforces, on a real time basis,
> > +that a platform or workload remains in a trusted state.  Security
> > +relevant actions cannot be conducted unless the TMA authorizes the
> > +actions as being trusted.
> > +
> > +This is particularly important with respect to embedded systems.  A
> > +TPM based architecture would not prevent a system from having its
> > +trust status altered.  Maintaining the system in a trusted state would
> > +require attestation polling of the system, and presumably, executing
> > +actions if the platform has engaged in untrusted behavior.
> > +
> > +Conversely, a trust orchestrated software implementation enforces that
> > +a system or workload remain in a security/trust state that it's
> > +security model was unit tested to.

> To be convinced that there is *any* use case for this in the real
> world, you'd need to show me how any useful rule, like your above
> /etc/shadow set, could actually indicate a less trustworthy state in
> a robust way, without turning into an easy accidental-self-DOS.

TSEM in its essence embraces 'default deny, exception allow'; the same
concept that every firewall on the planet implements.  With the
exception of all the vendors that are now rapidly claiming to do 'AI'
on deep packet inspection.

A TSEM security model is the set of coefficients that represent, at a
very granular level, the allowed security states of a workload.  In an
enforcing model, only these actions are allowed.

Our trust predicate is that if the workload has not allowed a security
behavior inconsistent with its desired security model, it can be
considered trusted.

Tasks that depart from the model are considered untrusted and get
EPERM'ed.  It is unclear where the 'accidental-self-denial-of-service'
issue would arise, since the only events that would get denied are
those that should not be occurring.

We would certainly entertain an elaboration on this issue so we could
better understand any possible deficiencies in what we are proposing.

> I'm afraid the answer is going to be "AI"...

No, not if we understand correctly the issue you raise.

That being said, we do feel that TSEM opens the door to implementing
the most accurate 'AI' models possible, for environments where
deterministic or quasi-deterministic security modeling is infeasible.

We certainly do understand antipathy with respect to AI, but it seems
that it is going to be a fact of life in the security industry and
beyond for a significant period of time.

I even see that Cisco is doubling down from its 'Talos AI-driven
Threat Intelligence' with the June announcement of its 'AI-First
Security Cloud'.... :-)

We are trying to give Linux the best method, of any OS, to implement
security modeling, regardless of its type.

> > +Security model functional definitions
> > +-------------------------------------
> > +
> > +Previously, classic trusted system implementations supported the
> > +notion of the 'measurement' of the system.  The measurement is the
> > +value of a linear extension function of all the security relevant
> > +actions recorded by a trust measurement system such as IMA.
> > +
> > +In TPM based trust architectures, this measurement is maintained in a
> > +PCR.  A measurement value is submitted to the TPM that extends the
> > +current measurement using the following formula:
> > +
> > +MEASUREMENT = HASH(CURRENT || NEW)
> > +
> > +	Where:
> > +		MEASUREMENT = The new measurement value to be maintained
> > +			      in the register for the system.
> > +
> > +		||	    = Concatenation operator.
> > +
> > +		HASH	    = A cryptographic hash function supported
> > +			      by the TPM device.
> > +
> > +		CURRENT     = The current measurement value.
> > +
> > +		NEW	    = A new measurement value to be added to
> > +			      the current measurement.
> > +
> > +In TPM1 based systems, the HASH function was SHA1.  Due to well
> > +understood security concerns about the cryptographic vitality of this
> > +function, TPM2 based systems provide additional HASH functions with
> > +stronger integrity guarantees, most principally SHA related functions
> > +with longer digest values such as SHA256, SHA384 and SM3.

> This previous paragraph simply is not needed in this document.

Yes, not sure how that persisted through internal review, we will drop
it.

> > +The use of a cryptographic function produces a non-commutative sum
> > +that can be used to verify the integrity of a series of measurements.
> > +With respect to security modeling theory, this can be thought of as a
> > +'time-dependent' measurement of the system.  Stated more simply, the
> > +measurement value is sensitive to the order in which the measurements
> > +were made.
> > +
> > +In systems such as IMA, the measurement value reflects the sum of
> > +digest values of what are considered to be security critical entities,
> > +most principally, files that are accessed, based on various policies.
> > +
> > +In TSEM based TMA's, the measurement of a modeling namespace is the
> > +sum of the security state coefficients generated by the operative
> > +security model being enforced.  As previously noted, on systems with a
> > +TPM, the root modeling namespace measurement is maintained by default
> > +in PCR 11 or the PCR that was selected at kernel configuration time.
> > +
> > +The challenge associated with classic integrity measurements is the
> > +time dependent nature of using a non-commutative summing function.
> > +The almost universal embrace of SMP based hardware architectures, in
> > +addition to standard kernel task scheduling issues, makes the
> > +measurement values non-deterministic.  This requires a verifying party
> > +to evaluate an event log, verified by a measurement value, to
> > +determine whether or not the system is in a security appropriate
> > +state.
> > +
> > +TSEM addresses this issue by implementing a strategy designed to
> > +produce a single functional value that represents the security state

> You've spent a lot of space discussing the "time based" (I think
> "order dependent" might be better) nature of IMA and TPM
> measurements.  But after reading this section twice, I'm still not
> seeing what TMA does to work around it.

Time dependent vs. time independent models tends to be a lingua franca
in modeling theory.

We will see if we can work some prose in that relates this to
ordering.

> If a process normally reads files F1, F2, .. F10, then writes F11,
> but next time it reads F1, F3, F2, F4, .. F10, how will these two
> different vectors be used in TMA?

I believe this is discussed below and we will treat it further there.

> > +of a model.  This allows a TMA to attest to the trust/security status
> > +of a platform or workload by signing this singular value and
> > +presenting it to a verifying party.
> > +
> > +In TSEM nomenclature, this singular value is referred to as the
> > +'state' of the model.  The attestation model is to use trust
> > +orchestrators to generate the state value of a workload by unit
> > +testing.  This state value can be packaged with a utility or container
> > +to represent a summary trust characteristic that can be attested by a
> > +TMA, eliminating the need for a verifying partner to review and verify
> > +an event log.
> > +
> > +TMA's implement this architecture by maintaining a single instance
> > +vector of the set of security state coefficients that have been
> > +generated.  A state measurement is generated by sorting the vector in
> > +big-endian hash format and then generating a standard measurement
> > +digest over this new vector.

> Are you saying the TMA will keep every meaningful measurement for
> the duration of the workload, so that it can always sort them?

Correct, every unique security state coefficient.

The approach isn't unique and without precedent.  Roberto Sassu is
using a similar strategy in order generate a time/order independent
PCR value for unlocking TPM sealed keys by parsing RPM and .deb
distribution manifests.

Paul Moore, in his comments in February to the V1 series, even
seriously questioned why we would expose the classic linear extension
measurement from a TMA.

> > +Any security event that generates an associated state coefficient that
> > +is not in the model will resulted in a perturbed state function value.
> > +That perturbed value would be interpreted by a verifying party as an
> > +indication of an untrusted system.
> > +
> > +Since the TMA maintains the security event descriptions in time
> > +ordered form, the option to provide a classic event log and
> > +measurement are preserved and available.  Extensive experience in the
> > +development of TSEM modeled systems has demonstrated the superiority
> > +of state value interpretation over classic measurement schemes.

> I think you're saying that keeping the tens of thousands security
> relevant events instead of keeping a hash of those events gives you
> more information... which is true.  It also gives you more
> information.  In a presumably limited space and over a presumably
> limited link.  No performance impact?

Obviously everything we do with respect to security has an impact, as
always, it comes down to a cost/benefit analysis.

We would offer the following observations:

The use of a security modeling namespace reduces the number of
coefficients that need to be stored.  Any serious initiative involving
modeling, deterministic or ML, will demand the notion of the concept
of a 'namespace'.

Only unique coefficients are stored.  There is a surprising amount of
redundancy in security state coefficients that are generated by a
workload, to wit:

The boot of a basic Debian implementation to a shell prompt will
generate approximately 7,800 unique coefficients from a field of
57,800 events.

Executing a runc based workload, up to the point where you can do
something with a shell, yields 98 coefficients from a field of 478.

As will likely be the case with TPM's moving forward, it seems
unlikely that the future will consist of TMA's being discrete hardware
devices.  As we note in our documentation, the Quixote/TSEM userspace
tools demonstrate the viability of a number of different physical
modeling environments.

Quixote/TSEM may actually be the 'killer' application for SGX but it
seemed we were unable to communicate that effectively.

All of that being said.  If you download the source for the userspace
tools, it will build firmware for a TMA implementation that will run
on the Nordic NRF52840-DONGLE micro-controller (USB form factor and
comms, 32 bit ARM, 256K RAM), think Yubikey class and style device
that GOOGLE is using for its OpenSK initiative.

We use it to model a runc based workload consisting of a Java Log4J2
exploit demonstration.  Getting Java cranked up doesn't exactly blow
your hair back but the Tomcat application is surprisingly responsive
after that.

Finally, in order to support modeling of the root namespace anchored
by a TPM trust root we needed to implement asynchronous TPM updates.

Until we did that, boot performance on systems with discrete TPM's was
brutally slow, which underscores that classic TPM based trust models
are challenged when it comes to anchoring model based security
architectures.

> I'd really like to see what a conscise but useful policy looks like.

Given the above, what in your mind would be a 'useful' policy?

> -serge

Thanks for the comments.

Have a good weekend.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 03/13] Implement CAP_TRUST capability.
  2023-08-07 20:21   ` Casey Schaufler
@ 2023-08-15 10:19     ` Dr. Greg
  2023-08-15 17:15       ` Casey Schaufler
  0 siblings, 1 reply; 36+ messages in thread
From: Dr. Greg @ 2023-08-15 10:19 UTC (permalink / raw)
  To: Casey Schaufler; +Cc: linux-security-module, linux-kernel, corbet

On Mon, Aug 07, 2023 at 01:21:35PM -0700, Casey Schaufler wrote:

Good morning, I hope this note finds the day starting well for
everyone.

> On 7/10/2023 3:23 AM, Dr. Greg wrote:
> > TSEM was designed to support a Trust Orchestration System (TOS)
> > security architecture.  A TOS based system uses the concept of a
> > minimum Trusted Computing Base of utilities, referred to as trust
> > orchestrators, that maintain workloads in a trusted execution
> > state.  The trust orchestrators are thus, from a security
> > perspective, the most security privileged processes running on
> > the platform.
> >
> > The CAP_ML (machine modeling) capability is defined as a
> > capability that allows a process to alter the modeling and hence
> > the trust status of the platform.  In a fully orchestrated system
> > only the trust orchestrator carry this capability bit and then
> > drop the capability for the execution of the workload.  This is
> > designed to prevent a security vulnerability in workloads to be
> > leveraged to create an entity that could conduct adversarial
> > modifications to the trust status of the platform.
> >
> > With the introduction of TSEM there are three generic mechanisms
> > for implementing security contols, each with its own capability
> > bit for management, ie:
> >
> > DAC - CAP_DAC_ADMIN

> There is no CAP_DAC_ADMIN. There are several capabilities related to
> changing the DAC state of the system.

Our apologies, I believe we were thinking of CAP_DAC_OVERRIDE.

> > MAC - CAP_MAC_ADMIN

> Since your system implements a mandatory access control policy
> you should be using CAP_MAC_ADMIN.

See below.

> > Security modeling - CAP_ML

> First, the name you've chosen makes no sense at all. It isn't
> descriptive and fails even as an abbreviation. Second, you aren't
> doing anything that wouldn't be covered under CAP_MAC_ADMIN.

Apologies for the name, we choose it ad-hoc as an acronym for 'Machine
Learning' which is what TSEM uses, in potentially multiple forms, to
implement its security controls.  I wouldn't anticipate it to be
forthcoming from your corner, but feel free to suggest an alternative.

You note above that CAP_MAC_ADMIN should be used because TSEM ends up
implementing access control decsions that are mandatory in nature

As our documentation notes, with the introduction of TSEM there are
three mechanisms that are now available to implement security
controls: DAC, static MAC and dynamic controls based on
modeling/machine learning.

Our premise for proposing a separate capability is that different
methods of achieving security controls should use different
capabilities, so that the capability controls remain orthogonal and
independent of one another.

Additionally.

The mandatory controls implemented by TSEM are subtly different in
intent from those implemented by the incumbent LSM's, since TSEM's
controls can be generated and implemented by software developers or
users.  You had noted in other replies that classic mandatory controls
should only be implemented by system administrators or security
architects.

Finally.

TSEM brings with it the ability to allow the creation of security
control namespaces that do not conflict with other security
namespaces, with the exception that the non-namespaced controls will
also exert their authority if they are 'stacked' with TSEM.  If we
read user interest and expectations correctly, which I believe we do,
there will only be an increasing demand for this type of security
functionality.

Given that, it will be problematic, moving forward, if the capability
to create isolated security namespaces is not orthogonal with the
ability to modify how a policy can be configured or managed within an
isolated security namespace.

Given this latter issue, CAP_ML probably needs a different name,
once again, suggestions are welcome.

> > Having a separate capability bit for security modeling allows DAC
> > and classic label or path based MAC systems to be implemented in
> > the context of a security modeling namespace.  Looking forward it
> > is not unreasonable to consider the implementation of a modeling
> > policy that would verify the status of extended attributes being
> > used for label based MAC controls.

> It seems reasonable that being trusted with the privilege to change
> the modeling policy would imply sufficient trust to change other
> security states where allowed. As the Smack maintainer, and having
> introduced CAP_MAC_ADMIN, I say that there's insufficient grounds to
> introduce a new, single purpose capability.

First, no one, least of all our group, doubts your contributions to
the art.

We are also very confident, in the level of skills and experience in
the fields of modeling and security operations, of the team that is
bringing forward TSEM.

Based on these experiences, as we noted above, we believe it will be
unwise to not make the ability to control the creation, isolation and
protection of a security namespace from the ability to modify the
configuration of a security policy within a namespace.

Secondly.

With respect to the capability being 'single purpose'.  We haven't
seen a clear pathway or discussion regarding namespaces for other
security architectures, given the known structural issues involved
with classic labeling or pathname based implementations.  Paul
suggests that there is ongoing thinking on how to address this issue
and you've noted that the stacking work needs to go in before further
functionality can be considered.

The new capability bit will be available when those initiatives move
forward.  Kernel doctrine has been that at least a single use of
functionality must be present for a feature to be added, TSEM provides
that initial use.

Finally.

In his 'ANN' document, regarding LSM submission requirements, Paul
Moore noted that he did not want to require the need to demonstrate a
'community of support' around an LSM in order to avoid a 'chicken and
egg' problem.  He further noted that LSM authors need to be able to
guarantee that API's will be durable for 20+ years.

Within the security industry there is already a 'chicken and egg'
problem.  A new security architecture or scheme will not evolve
without the system, at a minimum, being in the Linux kernel.  New
security architectures do not organically appear and evolve, we can
state this fact with significant authority.

Without generic availability and use of a technology, it is difficult
to reason how correct 20+ year guesses on needed functionality can be
made.  So there needs to be a 'guess' on how to implement technology,
in the most generic form that does not lock the implementation into a
corner.

We've tried to make these 'guesses' with TSEM, based on, now 15+ years
of experience, with multiple implementations of security modeling and
namespacing.  Our advocacy for the new capability bit, whatever it is
named, is based on that body of experience.

We have proposed what we believe is the correct implementation and
API.  If the only way forward is an alternate implementation, we have
conducted our due diligence, which history will document if that
alternate implementation proves to be insufficient and constraining.

Best wishes for a productive remainder of the week.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 03/13] Implement CAP_TRUST capability.
  2023-08-15 10:19     ` Dr. Greg
@ 2023-08-15 17:15       ` Casey Schaufler
  0 siblings, 0 replies; 36+ messages in thread
From: Casey Schaufler @ 2023-08-15 17:15 UTC (permalink / raw)
  To: Dr. Greg; +Cc: linux-security-module, linux-kernel, corbet, Casey Schaufler

On 8/15/2023 3:19 AM, Dr. Greg wrote:
> On Mon, Aug 07, 2023 at 01:21:35PM -0700, Casey Schaufler wrote:
>
> Good morning, I hope this note finds the day starting well for
> everyone.
>
>> On 7/10/2023 3:23 AM, Dr. Greg wrote:
>>> TSEM was designed to support a Trust Orchestration System (TOS)
>>> security architecture.  A TOS based system uses the concept of a
>>> minimum Trusted Computing Base of utilities, referred to as trust
>>> orchestrators, that maintain workloads in a trusted execution
>>> state.  The trust orchestrators are thus, from a security
>>> perspective, the most security privileged processes running on
>>> the platform.
>>>
>>> The CAP_ML (machine modeling) capability is defined as a
>>> capability that allows a process to alter the modeling and hence
>>> the trust status of the platform.  In a fully orchestrated system
>>> only the trust orchestrator carry this capability bit and then
>>> drop the capability for the execution of the workload.  This is
>>> designed to prevent a security vulnerability in workloads to be
>>> leveraged to create an entity that could conduct adversarial
>>> modifications to the trust status of the platform.
>>>
>>> With the introduction of TSEM there are three generic mechanisms
>>> for implementing security contols, each with its own capability
>>> bit for management, ie:
>>>
>>> DAC - CAP_DAC_ADMIN
>> There is no CAP_DAC_ADMIN. There are several capabilities related to
>> changing the DAC state of the system.
> Our apologies, I believe we were thinking of CAP_DAC_OVERRIDE.

CAP_DAC_OVERRIDE allows you to circumvent the normal DAC checks.
It is not an administrative capability.

>
>>> MAC - CAP_MAC_ADMIN
>> Since your system implements a mandatory access control policy
>> you should be using CAP_MAC_ADMIN.
> See below.
>
>>> Security modeling - CAP_ML
>> First, the name you've chosen makes no sense at all. It isn't
>> descriptive and fails even as an abbreviation. Second, you aren't
>> doing anything that wouldn't be covered under CAP_MAC_ADMIN.
> Apologies for the name, we choose it ad-hoc as an acronym for 'Machine
> Learning' which is what TSEM uses, in potentially multiple forms, to
> implement its security controls.  I wouldn't anticipate it to be
> forthcoming from your corner, but feel free to suggest an alternative.

The name should be descriptive and unambiguous. CAP_SYS_ADMIN, for all
it's faults, tells you exactly what it's for, privileged administration
operations that are outside the scope of the system security mechanisms.
Your proposed capability should be named so as it make it obvious where
else in the system it could/should be used.

> You note above that CAP_MAC_ADMIN should be used because TSEM ends up
> implementing access control decsions that are mandatory in nature

That is correct.

> As our documentation notes, with the introduction of TSEM there are
> three mechanisms that are now available to implement security
> controls: DAC, static MAC and dynamic controls based on
> modeling/machine learning.

The static vs. dynamic distinction is fallacious. You can change Smack
rule sets at any time. You could easily create a modeling/machine learning
daemon that reads the syslog, audit files and various other system interfaces
and uses the data to reset the Smack rules to suit its idea of security.
That daemon would require CAP_MAC_ADMIN and sufficient privilege to read
the data it is interested in.

Having provided an example of a dynamic, modeling/machine learning system
for which CAP_MAC_ADMIN is appropriate, I remain of the opinion that your
proposed CAP_ML is unnecessary.

> Our premise for proposing a separate capability is that different
> methods of achieving security controls should use different
> capabilities, so that the capability controls remain orthogonal and
> independent of one another.

There are lots of people who agree with you. Unfortunately, the capability
mechanism does not scale well to large numbers of capabilities. It was
not designed (P1003.1e/2c) with fine grained privilege in mind. The use
of capabilities has been slow enough on the uptake as it is. Adding all
the capabilities that have been requested over the years would only make
it harder.

> Additionally.
>
> The mandatory controls implemented by TSEM are subtly different in
> intent from those implemented by the incumbent LSM's, since TSEM's
> controls can be generated and implemented by software developers or
> users.  You had noted in other replies that classic mandatory controls
> should only be implemented by system administrators or security
> architects.

Look at seccomp and landlock before you claim TSEM is unique in this way.

> Finally.
>
> TSEM brings with it the ability to allow the creation of security
> control namespaces that do not conflict with other security
> namespaces,

I read this several times, and can't tease out what it means. :(

>  with the exception that the non-namespaced controls will
> also exert their authority if they are 'stacked' with TSEM.  If we
> read user interest and expectations correctly, which I believe we do,
> there will only be an increasing demand for this type of security
> functionality.
>
> Given that, it will be problematic, moving forward, if the capability
> to create isolated security namespaces is not orthogonal with the
> ability to modify how a policy can be configured or managed within an
> isolated security namespace.

I don't see how "creating an isolated security namespace" isn't
a "configuraton" or "management" operation. You are going to have
some other mechanism to prevent processes in an isolated security
namespace from creating new isolated security namespaces if you
don't want them to, aren't you?

> Given this latter issue, CAP_ML probably needs a different name,
> once again, suggestions are welcome.
>
>>> Having a separate capability bit for security modeling allows DAC
>>> and classic label or path based MAC systems to be implemented in
>>> the context of a security modeling namespace.  Looking forward it
>>> is not unreasonable to consider the implementation of a modeling
>>> policy that would verify the status of extended attributes being
>>> used for label based MAC controls.
>> It seems reasonable that being trusted with the privilege to change
>> the modeling policy would imply sufficient trust to change other
>> security states where allowed. As the Smack maintainer, and having
>> introduced CAP_MAC_ADMIN, I say that there's insufficient grounds to
>> introduce a new, single purpose capability.
> First, no one, least of all our group, doubts your contributions to
> the art.
>
> We are also very confident, in the level of skills and experience in
> the fields of modeling and security operations, of the team that is
> bringing forward TSEM.
>
> Based on these experiences, as we noted above, we believe it will be
> unwise to not make the ability to control the creation, isolation and
> protection of a security namespace from the ability to modify the
> configuration of a security policy within a namespace.

Sorry, again, I read this several times and can't quite parse it.

> Secondly.
>
> With respect to the capability being 'single purpose'.  We haven't
> seen a clear pathway or discussion regarding namespaces for other
> security architectures, given the known structural issues involved
> with classic labeling or pathname based implementations.  Paul
> suggests that there is ongoing thinking on how to address this issue
> and you've noted that the stacking work needs to go in before further
> functionality can be considered.

AppArmor has a working implementation. Both SELinux and Smack have had
patches reviewed in the past. SELinux work continues, but it has been a
while since there have been postings. You're correct that no clear path
has been proposed for dealing with namespaces generically.

> The new capability bit will be available when those initiatives move
> forward.  Kernel doctrine has been that at least a single use of
> functionality must be present for a feature to be added, TSEM provides
> that initial use.

Requests for single-use capabilities come in all the time. The
capability system isn't set up to allow for them.

> Finally.
>
> In his 'ANN' document, regarding LSM submission requirements, Paul
> Moore noted that he did not want to require the need to demonstrate a
> 'community of support' around an LSM in order to avoid a 'chicken and
> egg' problem.  He further noted that LSM authors need to be able to
> guarantee that API's will be durable for 20+ years.
>
> Within the security industry there is already a 'chicken and egg'
> problem.  A new security architecture or scheme will not evolve
> without the system, at a minimum, being in the Linux kernel.  New
> security architectures do not organically appear and evolve, we can
> state this fact with significant authority.
>
> Without generic availability and use of a technology, it is difficult
> to reason how correct 20+ year guesses on needed functionality can be
> made.  So there needs to be a 'guess' on how to implement technology,
> in the most generic form that does not lock the implementation into a
> corner.
>
> We've tried to make these 'guesses' with TSEM, based on, now 15+ years
> of experience, with multiple implementations of security modeling and
> namespacing.  Our advocacy for the new capability bit, whatever it is
> named, is based on that body of experience.
>
> We have proposed what we believe is the correct implementation and
> API.  If the only way forward is an alternate implementation, we have
> conducted our due diligence, which history will document if that
> alternate implementation proves to be insufficient and constraining.

Yes, I hear you. Your arguments are fine, they just don't justify
a new, single use capability.

> Best wishes for a productive remainder of the week.

To you as well.

>
> As always,
> Dr. Greg
>
> The Quixote Project - Flailing at the Travails of Cybersecurity

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 2/13] Add TSEM specific documentation.
  2023-07-10 10:23 ` [PATCH 02/13] Add TSEM specific documentation Dr. Greg
  2023-07-11  4:37   ` Randy Dunlap
  2023-08-08 18:48   ` Serge Hallyn
@ 2024-01-04  4:00   ` Paul Moore
  2024-01-05  2:55     ` Dr. Greg
  2024-01-08 11:43     ` Dr. Greg
  2 siblings, 2 replies; 36+ messages in thread
From: Paul Moore @ 2024-01-04  4:00 UTC (permalink / raw)
  To: Dr. Greg, linux-security-module, linux-kernel, corbet

On Jul 10, 2023 "Dr. Greg" <greg@enjellic.com> wrote:
> 
> An entry was added to the ABI testing documentation to document
> the files in the TSEM management filesystem.
> 
> The file documenting the kernel command-line parameters was
> updated to document the TSEM specific command-line parameters
> 
> The primary TSEM documentation file was added to the LSM
> administration guide and the file was linked to the index of LSM
> documentation.
> 
> Signed-off-by: Greg Wettstein <greg@enjellic.com>
> ---
>  Documentation/ABI/testing/tsem                |  828 +++++++++
>  Documentation/admin-guide/LSM/index.rst       |    1 +
>  Documentation/admin-guide/LSM/tsem.rst        | 1526 +++++++++++++++++
>  .../admin-guide/kernel-parameters.txt         |   18 +
>  4 files changed, 2373 insertions(+)
>  create mode 100644 Documentation/ABI/testing/tsem
>  create mode 100644 Documentation/admin-guide/LSM/tsem.rst

Let me start by apologizing for the delay in responding, your patience
was appreciated.  Comments below ...

> diff --git a/Documentation/ABI/testing/tsem b/Documentation/ABI/testing/tsem
> new file mode 100644
> index 000000000000..cfb013b5f1f4
> --- /dev/null
> +++ b/Documentation/ABI/testing/tsem
> @@ -0,0 +1,828 @@
> +What:		/sys/kernel/security/tsem
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The /sys/kernel/security/tsem directory contains files
> +		and directories that implement the control plane for
> +		the Trusted Security Event Modeling (TSEM) LSM.
> +
> +		The files in this directory hierarchy, with the
> +		exception of the aggregate file, when read, reflect
> +		the values for the security modeling namespace that
> +		the process reading the files is operating in.
> +
> +What:		/sys/kernel/security/tsem/id
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The id file contains the ASCII base 10 representation
> +		of the model domain/namespace identifier that the
> +		reading process is operating in.
> +
> +		The root security modeling namespace has a value of
> +		zero, a non-zero value indicates a modeling namespace
> +		subordinate to the root model.
> +
> +		Each externally modeled domain will have a file, with
> +		this id number, created in the
> +		/sys/kernel/security/tsem/ExternalTMA directory that
> +		is documented below.

Just making sure you want to use uppercase here.  It's your call,
but it tends to go against convention, and changing it after the code
is in a tagged release it painful enough that it should be considered
practically impossible.  This applies not just to this file, but all
of the other mixed/upper case TSEM files under /sys.

> +What:		/sys/kernel/security/tsem/aggregate
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The aggregate file contains the ASCII base 16
> +		representation of the 256 bit hardware platform
> +		aggregate that TSEM is modeling under.  The platform
> +		aggregate is the linear extension measurement of the
> +		Trusted Platform Module PCR registers 0 through 8.

I believe we talked about hash agility previously, but just in case,
you may want to reword the above to provide some flexibility around
the hash algorithm used.  On the other hand, if you want to stick
with a single hash algorithm and 256-bit digest length, you might as
well specify the hash algorithm here.  I don't want to assume too much
about the TSEM design, but I'm guessing the aggregate is intended to
be a deterministic value based on the PCRs and therefore it seems like
there is value in providing a clear explanation of how it is
calculated.

> +		On a platform without a TPM this value will be all
> +		null bytes.

Just to clarify, are you intending this to be NULL bytes (as written)
or an ASCII base 16 zero value, padded out to the digest length,
similar as to what you might see in the output of the `tpm2_pcrread`
command for a zero-value PCR?  Once again, it's your call, I just
wanted to clarify.

> +What:		/sys/kernel/security/tsem/control
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The control file is the only writable file in the
> +		filesystem and is used by the trust orchestrator's to
> +		configure and control the behavior of the TSEM
> +		implementation.

I would drop the "only writable file ..." portion above; it may be the
only writable file under /sys/kernel/security/tsem at the moment, but
I imagine there is a good chance that will change over time and the
comment doesn't really add anything important.

> +		The following keyword and arguments are recognized:
> +
> +		internal
> +			The internal keyword causes an internally
> +			modeled domain to be created for the calling
> +			process.
> +
> +		external
> +			The external keyword causes an externally
> +			modeled domain to be created for the calling
> +			process.
> +
> +			A modeling namespace created by these commands
> +			accept the following set of key=value pairs
> +			that configure the namespace:

I assume whitespace is used as a delimiter?  That would be good to
document, both between the key-value-pairs as well as the initial
op/keyword.

Also, do these key-value-pairs apply to both internal and external
domains?  The text seems to indicate that they do, but the way the
document is structured hints that they only apply to the external
domain.  Perhaps a sentence in the internal domain description
indicating that all of the external domain configuration parameters
apply to internal domains as well, unless explicitly stated otherwise.

> +			nsref=initial|current
> +				The nsref key specifies the namespace
> +				that is to be referenced when
> +				determining the UID/GID values that
> +				define a COE or CELL identity.

Are COE or CELL acronyms?  If so, it would be nice to expand them on
first use in the document.

> +				The initial keyword specifies that the
> +				initial user namespace be used.  The
> +				current keyword specifies that the
> +				user namespace of the process that is
> +				invoking a security event handler
> +				(hook) is used.
> +
> +			digest=digestname
> +				The digest key is used to specify the
> +				cryptographic hash function that is to
> +				be used in the namespace for the
> +				creation of COE and CELL identities.
> +
> +				The digestname is the name used by the
> +				Linux kernel cryptographic API to
> +				identify the hash function.  Examples
> +				would include sha256, sha3-256, sm3
> +				etc.  The source files for the
> +				cryptographic hash function in the crypto
> +				directory of the kernel source has the
> +				names for hash functions implemented
> +				in the kernel.
> +
> +				The sha256 hash function is the
> +				default function for the root modeling
> +				domain.  This can be modified by the
> +				tsem_digest command-line parameter.
> +
> +				A hash function, used by the root
> +				modeling domain, must be built into
> +				the kernel.
> +
> +			cache=NN
> +				The cache key specifies the size of
> +				the caches to be used for holding
> +				pointers to structures used for the
> +				modeling or export of security events
> +				that are called while the invoking
> +				process is in atomic context.
> +
> +				The value NN is the ASCII base 10
> +				representation of the number of
> +				entries in the cache.
> +
> +				By default, the root modeling
> +				namespace and an externally modeled
> +				namespace will have 96 entries.  An
> +				internally modeled namespace will have
> +				16 entries.
> +
> +			key=HEXID
> +				The key argument is used to specify
> +				the authentication key that will be
> +				used by a trust orchestrator to
> +				authenticate trust control requests to
> +				a process running in the security
> +				modeling namespace.
> +
> +				The HEXID value is the ASCII base16
> +				encoded key that is to be used.  The
> +				length of this key, in binary, must be
> +				equal to the size of the digest
> +				produced by the cryptographic hash
> +				function that is being used in the
> +				modeling namespace.
> +
> +		enforce
> +			The enforce keyword causes the modeling
> +			domain/namespace of the process to enter
> +			enforcing mode.  In this mode, a value of
> +			-EPERM will be returned for a security event
> +			coefficient that does not map into the current
> +			set of allowed coefficients for the security
> +			model being implemented in the namespace.
> +
> +		seal
> +			The seal keyword causes the security model
> +			being implemented for the namespace to be
> +			placed in a sealed state.  In this state, the
> +			current set of security coefficients is
> +			considered to be the only set of valid
> +			coefficients for the model.  Any subsequent
> +			events that map to a coefficient not in the
> +			current model will be considered a violation
> +			of the model.
> +
> +		trusted pid=PID key=HEXID
> +			The trusted keyword is used by a trust
> +			orchestrator to indicate that the process
> +			identified by the PID argument should be
> +			allowed to run in trusted status after the
> +			modeling of a security event.

I mentioned this quite a few times in my review of the previous
patchset, PIDs are not a safe way to identify a process in the system.
PID reuse/recycling is a real danger and you need to account for this
risk.

> +			The HEXID argument is the authentication key
> +			that has been configured by a trust
> +			orchestrator for the namespace at the time of
> +			its creation.
> +
> +		untrusted pid=PID key=HEXID
> +			The untrusted keyword is used by a trust
> +			orchestrator to indicate that the process
> +			identified by the PID argument should be
> +			designated as an untrusted process.

See above, you can't use a PID to safely identify a process.

> +			The HEXID argument is the authentication key
> +			that has been configured by a trust
> +			orchestrator for the namespace at the time
> +			its creation.
> +
> +		state value=HEXID
> +			The state keyword is used to indicate that the
> +			security state coefficient identified by the
> +			ASCII base 16 encoded value specified by HEXID
> +			should be loaded into the current security
> +			model as a valid security event coefficient.
> +
> +		pseudonym valid=HEXID
> +			The pseudonym keyword is used to indicate that
> +			the pathname, identified by the ASCII base 16
> +			encoded value HEXID, should be designated to
> +			return a constant digest value for the
> +			contents of the file named by the pseudonym.
> +
> +			The HEXID value is computed with the following
> +			function:
> +
> +			HEXID = HF(PATHNAME_LENGTH || PATHNAME)
> +
> +			WHERE HF is the cryptographic hash function
> +			that has been designated for use by the
> +			security modeling namespace.

How do you handle hash collisions?  Given that users will likely be
able to create files with arbitrary names, it seems like identifying
files by a hash of their pathname without any way to safely resolve
digest collisions is a problem in waiting.

> +		base value=HEXID
> +			The base keyword is used to indicate that the
> +			ASCII base 16 encoded value HEXID should be
> +			registered as the value used to generate
> +			security state coefficients for the model
> +			implemented in the modeling namespace.
> +
> +			The binary length of the value specified by
> +			HEXID must match the digest size of the
> +			cryptographic hash function specified for use
> +			in the security modeling namespace.
> +
> +			A model specific base value is designed to be
> +			used as a 'freshness' nonce, similar to an
> +			attestation nonce, to prove that a model state
> +			value or measurement is current and not being
> +			replayed.
> +
> +What:		/sys/kernel/security/tsem/InternalTMA
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +
> +		This directory will contain directories that will be
> +		used to hold files that surface model parameters for
> +		Trusted Modeling Agents (TMA's) for internally modeled
> +		security namespaces.
> +
> +		There is currently only one internal TMA that is
> +		surfaced through the following directory:
> +
> +		/sys/kernel/security/tsem/InternalTMA/model0
> +
> +		The subsequent descriptions for the files implemented
> +		in this directory will use ROOTDIR to represent the
> +		above directory for space conservation purposes.
> +
> +What:		ROOTDIR/measurement
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The measurement file contains the ASCII base 16
> +		representation of the time dependent linear extension
> +		value of all the security state coefficients in the
> +		model implemented by the namespace of the calling
> +		process.

If I remember correctly, one of the motivations for TSEM was to
avoid the time/ordering aspect of traditional attestation approaches
as it can be fragile.  Assuming that my memory is correct, and this
still holds true in the revision of the patchset, why are you
continuing to export time/order dependent measurements to userspace?

Either the ordering is important, in which case TSEM's novelty isn't
useful, or the ordering isn't important and we can remove this sysfs
file.

> +What:		ROOTDIR/state
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The state file contains the ASCII base 16
> +		representation of the functional value of a security
> +		modeling namespace.
> +
> +		The state value is a time independent representation
> +		of the measurement of a security model, and unlike the
> +		measurement value, is a time independent
> +		representation of the state.
> +
> +		This value is designed to be a single value that can
> +		be attested to represent whether or not a workload has
> +		deviated from a defined security behavior.

Continuing the comment above regarding ROOTDIR/measurement, this file
makes much more sense in the context of TSEM.

> +What:		ROOTDIR/trajectory
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The trajectory file contains a description of the
> +		security events that have occurred in a security
> +		modeling namespace
> +
> +		Each entry in this file represents a single security
> +		event and consists of a JSON encoded record with key
> +		values that define the characteristics of the event.
> +
> +		Each line in a trajectory, or forensics, file will
> +		always have the event and COE keys.  The event key
> +		describes the characteristics of a security event
> +		while the COE field describes the Context Of Execution
> +		that is requesting execution of a security event.
> +
> +		The event key consists of the following
> +		characteristic definitions:
> +
> +			process: COMM
> +				Where COMM is the ASCII representation
> +				of the name of the process executing
> +				the event.

What happens if a process, either innocently or maliciously, changes
its name (see prctl(PR_SET_NAME))?  Would it result in a mismatch of
the security state of a process?

> +			type: EVENT_TYPE
> +				The value field for a type key is the
> +				name of the security event that is
> +				being modeled.  The list of EVENT_TYPE
> +				names is defined in the following
> +				source file:
> +
> +				security/tsem/tsem.c
> +
> +				If the security event is a generically
> +				modeled event the EVENT_TYPE will be
> +				generic_event.  In this case the CELL
> +				characteristics for the event will be
> +				described by a generic_event: key

I'm guessing EVENT_TYPE is an ASCII string representation?  It would
be good to clarify as you have in most (all?) of the other fields and
the omission here raises a red flag.

> +			task_id: HEXID
> +				The value of the task_id key will the
> +				ASCII base 16 representation of the
> +				identity of the task that is executing
> +				the security handler.  The length of
> +				HEXID will match the size of the
> +				digest value of the cryptographic hash
> +				function selected for use by the
> +				security modeling namespace.
> +
> +				The following documentation file:
> +
> +				Documentation/admin-guide/LSM/TSEM.rst

It looks like the file is lowercase ".../tsem.rst".

> +				Describes how the TASK_ID value is
> +				generated.

I would suggest either moving or copying the TASK_ID definition here
so that it is included in the TSEM ABI document.

> +		The COE key has the following characteristic keys.
> +		Keys that involve discretionary access values
> +		(uids/gids) will have their numeric value computed
> +		based on the user namespace reference value that is
> +		being implemented in the security modeling namespace.
> +
> +			uid: NN
> +				The ASCII base 10 representation of
> +				the numeric value of the discretionary
> +				user id of the process that is
> +				executing the security event.
> +
> +			euid: NN
> +				The ASCII base 10 representation of
> +				the numeric value of the effective
> +				discretionary user id of the process
> +				that is executing the security event.
> +
> +			euid: NN
> +				The ASCII base 10 representation of
> +				the numeric value of the effective
> +				discretionary user id of the process
> +				that is executing the security event.
> +
> +			suid: NN
> +				The ASCII base 10 representation of
> +				the numeric value of the saved user id
> +				of the process that is executing the
> +				security event.
> +
> +			gid: NN
> +				The ASCII base 10 representation of
> +				the numeric value of the discretionary
> +				group id of the process that is
> +				executing the security event.
> +
> +			egid: NN
> +				The ASCII base 10 representation of
> +				the numeric value of the discretionary
> +				effective group id of the process that
> +				is executing the security event.
> +
> +			egid: NN
> +				The ASCII base 10 representation of
> +				the numeric value of the discretionary
> +				effective group id of the process that
> +				is executing the security event.
> +
> +			sgid: NN
> +				The base 10 ASCII representation of
> +				the numeric value of the saved
> +				discretionary group id of the process
> +				that is executing the security event.
> +
> +			fsuid: NN
> +				The base 10 ASCII representation of
> +				the numeric value of the discretionary
> +				filesystem user id of the process that
> +				is executing the security event.
> +
> +			fsgid: NN
> +				The ASCII base 10 representation of
> +				the numeric value of the discretionary
> +				filesystem group id of the process
> +				that is executing the security event.
> +
> +			capeff: 0xNNN
> +				The ASCII base 16 representation of
> +				the numeric value of effective
> +				capabilities of the process that is
> +				executing the security event.
> +
> +		If the CELL value for a security event includes the
> +		definition of a file a file: key value will be
> +		included.  The following characteristics will be
> +		encoded in this field:
> +
> +			flags: NN
> +				The ASCII base 10 representation of
> +				the flags value of the 'struct file'
> +				structure that is the source of the
> +				file description.
> +
> +			uid: NN
> +				The ASCII base 10 representation of
> +				the discretionary user id of the file.
> +
> +			gid: NN
> +				The base 10 ASCII representation of
> +				the discretionary group id of the
> +				file.
> +
> +			mode: 0NNN
> +				The ASCII base 8 representation of the
> +				mode bits of the file.

Does the leading zero followed by three octets imply you don't record
the setuid/setgid/sticky bits?

> +			name_length: NN
> +				The ASCII base 10 representation of
> +				the length of the pathname that will
> +				be encoded in the name= characteristic.

To clarify, this is the length of the pathname used during the file
lookup and not the length of the hash digest of the previously
mentioned pathname, yes?

> +			name: NN
> +				The ASCII hexadecimal representation
> +				of the SHA256 checksum of the pathname
> +				of the file that is pre-pended with
> +				the little-endian binary value of the
> +				length of the pathname.

Hash agility?

It isn't clear to me if the length is prepended before or after the
hash, it would be good to clean this up.

Also, similar to some comments above, how are you handling hash
collisions?  As pathnames can be influenced by unprivileged users, this
would appear to be an issue.

> +			s_magic: 0xNN
> +				The ASCII base 16 representation of the
> +				magic number of the filesystem that
> +				contains the file.
> +
> +			s_id: NAME
> +				The ASCII name of the block device for
> +				the filesystem that contains the file.
> +
> +			s_UUID: HEX
> +				The ASCII base 16 representation of
> +				the hexadecimal value of the UUID of
> +				the filesystem that contains the file.
> +
> +			digest: HEX
> +				The ASCII base 16 representation of
> +				the SHA256 digest of the file.

Hash agility?

Is TSEM running a hash over every file included in a file-related
security event?

> +		If the event type is the memory mapping of a file a
> +		mmap_file key value will be included with
> +		the following characteristics:

Still part of the CELL?  COE?  This doc could benefit from better
explanations of the CELL and COE terms.

> +			type: N
> +				Where N is an ASCII 0 or 1 to indicate
> +				whether or not the mapping is file
> +				backed or anonymous.  A value of 1 is
> +				used to indicate an anonymous mapping.
> +
> +			reqprot: NN
> +				Where N is ASCII base 10
> +				representation of the protections
> +				requested for the mapping.
> +
> +			prot: NN
> +				Where N is the ASCII base 10
> +				representation of the protections that
> +				will be applied to the mapping.
> +
> +			flags: NN
> +				Where N is the ASCII base 10
> +				representation of the flags that will
> +				be used for the memory mapping operation.

You should specify the flags used in the fields above, or refer
readers to the mmap(2) flag definitions if appropriate.

> +		If the event type is a socket creation event a
> +		socket_create key value will be included with the
> +		following characteristics:
> +
> +			family: N
> +				Where N is the ASCII base 10
> +				representation of the family type of
> +				the socket.
> +
> +			type: N
> +				Where N is the ASCII base 10
> +				representation of the type of socket
> +				being created.
> +
> +			protocol: N
> +				Where N is the ASCII base 10
> +				representation of the protocol family
> +				for the socket.

Similar to the mmap flags above, I would refer people to where these
values are defined.  The applies to the other socket family/type/proto
fields described elsewhere in this document.

> +			kern: 0 | 1
> +				Where 0 or 1 is used to indicate
> +				whether or not the socket is kernel
> +				based.  A value of 1 implies it is
> +				kernel based.

I'm curious how TSEM would distinguish between different kernel
socket events.  I would expect most kernel sockets to share the same
event key (COE/CELL/etc.), is that not the case?

> +		If the event type is a socket_connect or a
> +		socket_bind, a socket_connect: or a socket_bind: key
> +		value will be included that will be characterized
> +		based on an encoding of either an IPV4, IPV6, AF_UNIX
> +		or a generic socket description.
> +
> +			family: N
> +				Where N is the ASCII base 10
> +				representation of the family type of
> +				the socket.
> +
> +			port: N
> +				Where N is the base ASCII base 10
> +				representation of the port number that
> +				is being used for either an IPV4 or
> +				IPV6 socket connection or bind.
> +
> +			addr: N | PATH | HEXID
> +				In the case of an IPV4 socket the
> +				value for the addr key will be the
> +				ASCII base 10 representation of the 32
> +				bit IPV4 address being bound or
> +				connected to.
> +
> +				In the case of an IPV6 connection the
> +				value to the key will be the ASCII
> +				base 16 representation of the 128 bit
> +				address being bound connected.
> +
> +				In the case of an AF_UNIX connection
> +				the value will be the pathname of the
> +				socket in the mount namespace that the
> +				process is running in.
> +
> +				In the case of any other type of
> +				socket the addr value will be the
> +				ASCII base 16 representation of the
> +				cryptographic digest value of the
> +				entire length of the address
> +				description.  The length of the
> +				representation will be the size of the
> +				digest produced by the cryptographic
> +				hash function that has been specified
> +				for the modeling namespace.
> +
> +			flow: N
> +				For an IPV6 socket the value of the
> +				flow key will be the ASCII base 10
> +				representation of the flow identifier
> +				assigned to the socket.
> +
> +			scope: N
> +				For an IPV6 socket the value of the
> +				scope key will be the ASCII base 10
> +				representation of the scope identifier
> +				assigned to the socket.

What will "flow" and "scope" be for non-AF_INET6 sockets?  You need
to specify that here.

> +		If the event type is a socket_accept a socket_accept
> +		key value will be included that characterizes either
> +		an IPV4, IPV6 or a generic socket description with the
> +		following event descriptions:
> +
> +			family: N
> +				Where N is the ASCII base 10
> +				representation of the family type of
> +				the socket.
> +
> +			type: N
> +				Where N is the ASCII base 10
> +				representation of the type of the
> +				socket being created.
> +
> +			port: N
> +				Where N is the base ASCII base 10
> +				representation of the port number that
> +				is being used for either an IPV4 or
> +				IPV6 socket connection or bind.
> +
> +			addr: N | PATH | HEXID
> +				In the case of an IPV4 socket the
> +				value for the addr key will be the
> +				ASCII base 10 representation of the 32
> +				bit IPV4 address being bound or
> +				connected to.
> +
> +				In the case of an IPV6 connection the
> +				value to the key will be the ASCII
> +				base 16 representation of the 128 bit
> +				address being bound connected.
> +
> +				In the case of an AF_UNIX connection
> +				the value will be the pathname of the
> +				socket in the mount namespace that the
> +				process is running in.
> +
> +				In the case of any other type of
> +				socket the addr value will be the
> +				ASCII base 16 representation of the
> +				cryptographic digest value of the
> +				entire length of the address
> +				description.  The length of the
> +				representation will be the size of the
> +				digest produced by the cryptographic
> +				hash function that has been specified
> +				for the modeling namespace.
> +
> +What:		ROOTDIR/trajectory_coefficients
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The trajectory_coefficients file will output the ASCII
> +		base16 representation of each security state
> +		coefficient that has been generated by the security
> +		modeling namespace of the calling process.
> +
> +		The length of each point will be the ASCII
> +		representation of the size of the cryptographic hash
> +		function that has been specified for the model.

Is this just the ROOTDIR/trajectory JSON in ASCII hex, or something
different?

> +What:		ROOTDIR/trajectory_counts
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The trajectory_coefficients file will output the ASCII
> +		base10 representation of the number of times each

Unless I'm mistaken, I believe you defined it as base16 above ... ?

> +		security state coefficient has been generated by the
> +		security modeling namespace of the calling process.

This looks like an old cut-n-paste error.  I'm guessing this file
reports on the number of coefficients in ASCII base10?

> +What:		ROOTDIR/forensics
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The forensics file contains the descriptions of
> +		security events that are inconsistent with the
> +		security model that the security namespace is
> +		implementing.  Forensics events are generated after a
> +		security model is 'sealed' and the events represent
> +		security state coefficients that have not already been
> +		generated by the model.
> +
> +		The format of lines in this file are identical to the
> +		output generated by the ROOTDIR/trajectory file
> +		that is documented above.
> +
> +What:		ROOTDIR/forensics_coefficients
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The forensics_coefficients file will output the ASCII
> +		base16 representation of each security state
> +		coefficient that have been generated by forensics
> +		events in the security modeling namespace of the
> +		calling process.
> +
> +		The length of each point will be the ASCII
> +		representation of the size of the cryptographic hash
> +		function that has been specified for the model.
> +
> +What:		ROOTDIR/forensics_counts
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The forensics_counts file will output the ASCII base10
> +		representation of the number of times each security
> +		state coefficient, generated by a forensics event, has
> +		been generated by the security modeling namespace of
> +		the calling process.
> +
> +What:		/sys/kernel/security/tsem/ExternalTMA
> +Date:		July 2023
> +Contact:	Greg Wettstein <greg@enjellic.com>
> +Description:
> +		The ExternalTMA directory is a container directory
> +		that hold files that will be used to export the
> +		security events, and their associated parameters, for
> +		externally modeled security modeling namespaces.
> +
> +		The files created in this directory will be named by
> +		the base 10 ASCII representation of the id value
> +		assigned to the security modeling namespace.  See the
> +		documentation for the /sys/kernel/security/tsem/id
> +		file in this documentation for more details on this
> +		value.
> +
> +		This file will is a read-only file that can be polled
> +		by a userspace trust orchestrator implementation to
> +		process security events that are to be modeled by an
> +		external Trusted Modeling Agent.
> +
> +		Each exported event is a JSON encoded record
> +		describing the event that is to be processed.
> +
> +		Each record will have an 'export' key that has a
> +		structure associated with it that has a 'type' key in
> +		it.  The 'type' key has a string value associated with
> +		it that defines the type of event that is being
> +		processed.
> +
> +		The following export 'type' strings are defined:
> +
> +		aggregate:
> +			The aggregate key has an associated structure
> +			value that defines a key named 'value' that
> +			has a string value associated with it that
> +			represents the hardware aggregate for the
> +			platform.

You need to define "hardware aggregate" here, if you can't go into
detail you need a good summary outlining its security relevant
properties.

> +			The hardware aggregate string is expressed as
> +			the ASCII base16 representation of the
> +			platform hardware aggregate value.  The length
> +			of the string will be the size of the digest
> +			produced by the cryptographic hash function
> +			that has been specified for the security
> +			modeling namespace of the process generating
> +			the event.
> +
> +		async_event:
> +			If the type of the export is async_event there
> +			will be a key named 'event' that has a structure
> +			value associated with it.
> +
> +			The structure associated with the 'event' key
> +			will be identical to the structure generated
> +			for the 'event' key that is described below.
> +
> +		event:
> +			If the type of the export is event there will
> +			be a key named 'event' that has a structure
> +			value associated with it that contains the
> +			follow key: value pairs.
> +
> +			pid: NNN
> +				Where the NNN is the ASCII base 10
> +				value of the id of the process that is
> +				executing the security event that will
> +				be modeled.

Once more, you can't use a PID to safely identify a process.

We discussed the PID reuse problem in the previous draft of TSEM and
you seem confident that this revision would solve the problem,
unfortunately I don't believe that to be the case.  Perhaps the code
is sound and the documentation is lagging/incorrect, but the doc
appears to be consistent enough in this area that I don't believe that
to be the case.  Before I can spend any more time looking at TSEM I
need to understand how it handles PID recycling.

I'm also concerned that it appears pathname digests, as opposed to the
pathnames themselves, are being used to help uniquely identify
security events.  Relying on pathnames unique identification can
already be a challenge, relying on a hashed pathname without any
provisions to manage/mitigate collisions seems like an attack waiting
to happen.  Please provide some additional explanations as to why
this is not a concern.

> +			process: COMM
> +				Where COMM is the ASCII representation
> +				of the name of the process executing
> +				the event.
> +
> +			type: EVENT_TYPE
> +				The value field for a type key is the
> +				name of the security event that is
> +				being modeled.  The list of EVENT_TYPE
> +				names is defined in the following
> +				source file:
> +
> +				security/tsem/tsem.c
> +
> +				If the security event is a generically
> +				modeled event the EVENT_TYPE will be
> +				generic_event.  In this case the CELL
> +				characteristics for the event will be
> +				described by a generic_event: key
> +
> +			task_id: HEXID
> +				The value of the task_id key will the
> +				ASCII base 16 representation of the
> +				identity of the task that is executing
> +				the security handler.  The length of
> +				HEXID will match the size of the
> +				digest value of the cryptographic hash
> +				function selected for use by the
> +				security modeling namespace.
> +
> +				The following documentation file:
> +
> +				Documentation/admin-guide/LSM/TSEM.rst
> +
> +				Describes how the TASK_ID value is
> +				generated.
> +
> +			There will be a COE key that references a
> +			value structure that has the same format as
> +			the COE key that is emitted for a trajectory
> +			or forensics event.
> +
> +			The record will have a key value that is
> +			identical to the value associated with the
> +			'type' key documented above.  The 'type' key
> +			will have a structure value that contains a
> +			definition of the event.  The definitions for
> +			the event will be identical to the description
> +			of the event that is emitted for a trajectory
> +			or forensics event in the internal TMA
> +			implementation.
> +
> +		log:
> +			An export type of log is emitted when an
> +			untrusted task attempts to execute a security
> +			event.
> +
> +			There will be a 'log' key in the record that
> +			references a structure containing the
> +			following key values:
> +
> +			process: COMM
> +				The process key has a string value
> +				associated with it that will contain
> +				the COMM name of the untrusted process
> +				that invoked processing of the
> +				security event.
> +
> +			event: NAME
> +				The event key has a string value
> +				associated with that will contain the
> +				name of the security event hook that
> +				was called by an untrusted process.
> +
> +				The names for the security events are
> +				defined in the following source file:
> +
> +				security/tsem/tsem.c
> +
> +			action: TYPE
> +				The action key has a string value that
> +				describes the action take by the TSEM
> +				security hook in response to being
> +				called by an untrusted process.
> +
> +				This string value will be either LOG
> +				or DENY.
> +SEM is premised on the theory that kernel security architects have
> +instrumented the LSM security event hooks to be called from all
> +locations, with appropriate descriptive parameters, that are relevant
> +to the security posture of the kernel.  With respect to modeling, the
> +security event hooks are conceptualized as representing the
> +independent variables of a basis set that yields a functional
> +definition for the security state of an execution trajectory.
> +
> +SEM can be framed in the context of classic subject/object mandatory
> +access controls, by the notion that a unique identity can be generated
> +for each element of an access vector matrix, rather than a boolean
> +value.  In SEM, a security execution trajectory is defined by the set
> +of security state coefficients that a process hierarchy (workload)
> +generates.  This execution trajectory produces a vector of identities,
> +whose sum in an appropriate form, yields a functional definition of
> +the security state of the system.
> +
> +Two subordinate identities are combined to yield a security event
> +state coefficient.  These subordinate identities are referred to as the
> +Context Of Execution (COE) and the CELL, which are conceptually
> +similar to the subject and object in mandatory access control.  The
> +COE identity is derived from the parameters that describe the security
> +relevant characteristics of a process, while the CELL value is derived
> +from the parameters used by a security event hook to describe the
> +characteristics of the event.
> +
> +A security policy is implemented by a modeling algorithm that
> +translates COE and CELL event parameters into their respective
> +identities.  The COE and CELL are combined to yield a security state
> +coefficient that uniquely describes the security event in the security
> +model.  Different security policies and criteria can be developed by
> +modifying how the modeling algorithm utilizes the COE and CELL
> +characteristics.
> +
> +Since the security policy is implemented with a modeling algorithm, a
> +single platform can support multiple and arbitrary security policies.
> +The equivalent of a resource namespace in SEM is referred to as a
> +security modeling namespace.
> +
> +The formation of the security state coefficients from existing kernel
> +parameters eliminates the need for the use of extended attributes to
> +hold security label definitions.  In SEM, a cryptographically signed
> +security model definition, designed to be interpreted by a modeling
> +algorithm, becomes the bearer's token for the security of the modeled
> +workload, rather than information encoded in filesystem security
> +attributes.
> +
> +Trusted Security Event Modeling
> +===============================
> +
> +	"Do you see over yonder, friend Sancho, thirty or forty
> +	 hulking giants?  I intend to do battle with them and slay
> +	 them."
> +				- Don Quixote
> +
> +In TSEM, the modeling algorithm is implemented in an entity known as a
> +Trusted Modeling Agent (TMA), in a 'trusted' environment where
> +modeling is immune from modification or alteration by any activity on
> +the platform or in a workload.  The notion of a TMA provides a
> +framework for next generation security co-processors that extend
> +functionality beyond what is defined by the concept of a Trusted
> +Platform Module (TPM).
> +
> +In addition to providing an attestation of an execution trajectory, a
> +TMA, in contrast to a TPM, has the ability to advise an operating
> +system on whether or not an event being modeled is consistent with the
> +security model that is being enforced.  In this manner, it introduces
> +a prospective rather than a retrospective trust model.
> +
> +TSEM is designed to support Trust Orchestration Systems (TOS).  In a
> +TOS, the trust orchestrators are supervisory programs that run
> +workloads in independent modeling namespaces , enforcing a workload

{snip}

--
paul-moore.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/13] Add TSEM specific documentation.
  2023-08-11 20:22     ` Dr. Greg
@ 2024-01-04 15:54       ` Paul Moore
  2024-01-05  3:54         ` Dr. Greg
  0 siblings, 1 reply; 36+ messages in thread
From: Paul Moore @ 2024-01-04 15:54 UTC (permalink / raw)
  To: Dr. Greg; +Cc: Serge Hallyn, linux-security-module, linux-kernel, corbet

On Fri, Aug 11, 2023 at 4:24 PM Dr. Greg <greg@enjellic.com> wrote:
> On Tue, Aug 08, 2023 at 01:48:25PM -0500, Serge Hallyn wrote:
> > On Mon, Jul 10, 2023 at 05:23:08AM -0500, Dr. Greg wrote:

...

> > > +of a model.  This allows a TMA to attest to the trust/security status
> > > +of a platform or workload by signing this singular value and
> > > +presenting it to a verifying party.
> > > +
> > > +In TSEM nomenclature, this singular value is referred to as the
> > > +'state' of the model.  The attestation model is to use trust
> > > +orchestrators to generate the state value of a workload by unit
> > > +testing.  This state value can be packaged with a utility or container
> > > +to represent a summary trust characteristic that can be attested by a
> > > +TMA, eliminating the need for a verifying partner to review and verify
> > > +an event log.
> > > +
> > > +TMA's implement this architecture by maintaining a single instance
> > > +vector of the set of security state coefficients that have been
> > > +generated.  A state measurement is generated by sorting the vector in
> > > +big-endian hash format and then generating a standard measurement
> > > +digest over this new vector.
>
> > Are you saying the TMA will keep every meaningful measurement for
> > the duration of the workload, so that it can always sort them?
>
> Correct, every unique security state coefficient.
>
> The approach isn't unique and without precedent.  Roberto Sassu is
> using a similar strategy in order generate a time/order independent
> PCR value for unlocking TPM sealed keys by parsing RPM and .deb
> distribution manifests.
>
> Paul Moore, in his comments in February to the V1 series, even
> seriously questioned why we would expose the classic linear extension
> measurement from a TMA.

To put my comment from the first revision into the proper context, and
with my understanding that TSEM's security model does not consider
event ordering/timing, I questioned what TSEM would expose an ordered
list of events to userspace in addition to its unordered, sorted list.
Either ordering is important to the security model, in which case you
expose the ordered list, or it isn't, in which case you expose the
list in whatever form is most convenient for the tooling/model; it
makes little sense to me to expose both.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 2/13] Add TSEM specific documentation.
  2024-01-04  4:00   ` [PATCH 2/13] " Paul Moore
@ 2024-01-05  2:55     ` Dr. Greg
  2024-01-08 11:43     ` Dr. Greg
  1 sibling, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2024-01-05  2:55 UTC (permalink / raw)
  To: Paul Moore; +Cc: linux-security-module, linux-kernel, corbet

On Wed, Jan 03, 2024 at 11:00:33PM -0500, Paul Moore wrote:

Good morning, I hope the year is starting well for everyone.

> On Jul 10, 2023 "Dr. Greg" <greg@enjellic.com> wrote:
> > 
> > An entry was added to the ABI testing documentation to document
> > the files in the TSEM management filesystem.
> > 
> > The file documenting the kernel command-line parameters was
> > updated to document the TSEM specific command-line parameters
> > 
> > The primary TSEM documentation file was added to the LSM
> > administration guide and the file was linked to the index of LSM
> > documentation.
> > 
> > Signed-off-by: Greg Wettstein <greg@enjellic.com>
> > ---
> >  Documentation/ABI/testing/tsem                |  828 +++++++++
> >  Documentation/admin-guide/LSM/index.rst       |    1 +
> >  Documentation/admin-guide/LSM/tsem.rst        | 1526 +++++++++++++++++
> >  .../admin-guide/kernel-parameters.txt         |   18 +
> >  4 files changed, 2373 insertions(+)
> >  create mode 100644 Documentation/ABI/testing/tsem
> >  create mode 100644 Documentation/admin-guide/LSM/tsem.rst

> Let me start by apologizing for the delay in responding, your
> patience was appreciated.  Comments below ...

No problem, you were sounding pretty jammed up before the holidays,
thank you for starting to find the time to look at this.

That being said, we have continued to advance TSEM over the last six
months based on input from our partners.  With the New Year behind us,
we were preparing for a V3 release sometime in mid-January if we can
stay on schedule.

Given that, and the value of your review time, you may want to hold
off on a more extensive review until we can get V3 out the door.

We have taken down all of your comments below and will incorporate
changes and improvement where still relevant.

You voiced two major concerns at the end of your e-mail that you
wanted clarified before you spent additional time on TSEM, I will skip
forward to those so we can reach a better understanding on those
fundamental issues.

> > diff --git a/Documentation/ABI/testing/tsem b/Documentation/ABI/testing/tsem
> > new file mode 100644
> > index 000000000000..cfb013b5f1f4

... [ Content elided ] ...

> > +		event:
> > +			If the type of the export is event there will
> > +			be a key named 'event' that has a structure
> > +			value associated with it that contains the
> > +			follow key: value pairs.
> > +
> > +			pid: NNN
> > +				Where the NNN is the ASCII base 10
> > +				value of the id of the process that is
> > +				executing the security event that will
> > +				be modeled.

> Once more, you can't use a PID to safely identify a process.

Correct, which is why we changed our approach.

> We discussed the PID reuse problem in the previous draft of TSEM and
> you seem confident that this revision would solve the problem,
> unfortunately I don't believe that to be the case.  Perhaps the code
> is sound and the documentation is lagging/incorrect, but the doc
> appears to be consistent enough in this area that I don't believe
> that to be the case.  Before I can spend any more time looking at
> TSEM I need to understand how it handles PID recycling.

We cover the threat model and addressed how we responded to it in the
TSEM documentation file.

We will put a header at the top of the ABI document advocating that
the TSEM documentation file be read before the ABI document is
consumed.

We use the PID infrastructure to locate the process that is waiting on
a response from an external trust orchestrator.  After that the kernel
uses an authentication process to verify that the task being acted on
has not been replaced by an alternate task outside the scope of
control of the orchestrator for the namespace.

In Documentation/admin-guide/LSM/tsem.rst, the discussion is under the
following sub-heading:

Trust Orchestrator/Process authentication
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since it is an important issue, I will take the liberty of pasting
this documentation section in-line below, so that people don't have to
go digging for it and it becomes part of this documentation thread on
lore:

---------------------------------------------------------------------------
The process identifier values (PID's) that are exported in the
security event descriptions are the unique global PID values, not the
value as seen through the lens of a PID namespace.

PID values are, by default, not considered to be a stable identifier
between the kernel and userspace.  In the case of TSEM external
modeling, the threat model for a namespace is whether or not an
adversarial process, running in either the root modeling namespace or
another subordinate modeling namespace, can kill a process that is
being orchestrated and substitute an alternate process with an
identical PID value.

The trust orchestrator would then be deluded into setting the trust
status of the adversarial process rather than the one that had emitted
the security event characteristics that were evaluated.  The threat
interval is the latency time required for the processing of the
security event description by the trust orchestrator and its
associated TMA.

Exploiting this theoretical race is extremely complex and requires an
in depth understanding of the TSEM architecture.  Rather than discuss
the conditions that must be met and their implications, this
discussion will focus on the generic threat model and the mechanisms
that TSEM implements in order to mitigate this threat.

In short, a process in an adversarial security modeling namespace
would desire to execute security events that are barred from its
security model with the hope of having them approved by an alternate
namespace.

In order to exploit the race, an adversarial process would have to
force the termination of a process in the target namespace and then
fork and exit a process a sufficient number of times in order to have
a process under its control match the PID value of the process that
was waiting for an orchestration response.

Measured modeling latency times for a trust orchestrator running the
deterministic Quixote TMA in userspace, on current generation i3
x86_64 hardware, averages 170 micro-seconds.  From the perspective of
an adversary, there is a requirement to force the termination of the
target process and then fork and execute a sufficient number of times
to force the PID collision during this time interval.

As a generic protection, TSEM in the tsem_task_kill() handler, blocks
the notion of 'cross-model' signals, ie. a signal originating from an
external modeling namespace.  This would require the adversary to
reliably force a process termination through a mechanism other than
signaling, for example, through the OOM killer whose signal
transmission would not be blocked by this policy control.

In addition.

When a subordinate security modeling namespace is created, the id
number of the namespace is registered in the tsem_task structure of
the trust orchestrator that is creating the namespace.  The TSEM
implementation will refuse to honor control plane requests affecting
the trust status of a process whose trust orchestrator security
namespace id does not match the namespace id of the process that it is
being asked to act on.

As an additional protection, TSEM uses an authentication strategy that
requires a process running in a security modeling namespace to verify
that a control request is coming from the trust orchestrator that
initiated the namespace the process is running in.  As part of the
setup of a security modeling namespace, a trust orchestrator is
required to provide a hexadecimally encoded authentication key that
matches the length of the cryptographic hash function being used to
generate security state coefficients in the modeling namespace.  This
authentication key must be provided by the trust orchestrator for
every subsequent control plane request.

The lead process that is being transferred to a subordinate security
modeling namespace generates a second random key that is hashed with
the authentication key provided by the trust orchestrator, using the
hash function that has been defined for the security namespace.  The
resultant digest value is compared to a list of authentication keys
for all currently executing namespaces.  The selection of the second
random key is repeated until a globally unique key is generated.

This randomly generated authentication key is stored in the tsem_task
structure of the process and propagated to any subsequent processes
that are created in the namespace.  The hash product of this key and
the orchestration authentication key, ie. the globally unique key, is
placed in the tsem_task control structure of the orchestration
process.

When a control plane request is received, the authentication key
provided by the trust orchestrator is used to re-generate an
authentication key based on the randomly generated namespace key held
by the process whose trust status is being updated, this key is
compared to the key in the tsem_task structure of the process issuing
the orchestration request.  The control plane will refuse to honor a
control plane request if the call specific key generation process does
not produce a key that matches the one that was generated at the time
the security namespace was created.
---------------------------------------------------------------------------

This implementation remains the same between the V2 and V3 releases.

See the following code locations for details:

security/tsem/namespace.c:tsem_ns_event_key()
security/tsem/namespace.c:generate_task_key()
security/tsem/namespace.c:remove_task_key()

security/tsem/fs.c:control_COE()

> I'm also concerned that it appears pathname digests, as opposed to
> the pathnames themselves, are being used to help uniquely identify
> security events.  Relying on pathnames unique identification can
> already be a challenge, relying on a hashed pathname without any
> provisions to manage/mitigate collisions seems like an attack
> waiting to happen.  Please provide some additional explanations as
> to why this is not a concern.

The V3 release no longer uses the cryptographic digest of the pathname
length and path as an independent entity.  The V3 release also now
includes a device name specification as a component of any pathname
specification.

That being said, the pathname identification is a component of the
input stream that is fed to the namespace specific cryptographic
digest function that generates the security state coefficient for an
event.  So it would seem that your criticism would extend to the very
notion of the generation of security state coefficients.

To be clear, without getting overtly wonky, TSEM is rather firmly
ensconced on the following security predicate:

"Given a digest value of an input stream generated by a
cryptographically relevant hash function, it is computationally
infeasible for an adversary to create a second input stream, different
from the first, that generates the same digest value."

Is it an error to have operated under this assumption in the
construction of TSEM?

We can grind into much deeper detail as to why TSEM would make this
type of attack difficult, but obtaining agreement on the validity of
the above predicate would seem to be the most important first step.

> paul-moore.com

Thank you again for finding time for this.

Let us know if additional clarifications would be helpful.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity
              https://github.com/Quixote-Project

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 02/13] Add TSEM specific documentation.
  2024-01-04 15:54       ` Paul Moore
@ 2024-01-05  3:54         ` Dr. Greg
  0 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2024-01-05  3:54 UTC (permalink / raw)
  To: Paul Moore; +Cc: Serge Hallyn, linux-security-module, linux-kernel, corbet

On Thu, Jan 04, 2024 at 10:54:47AM -0500, Paul Moore wrote:
> On Fri, Aug 11, 2023 at 4:24???PM Dr. Greg <greg@enjellic.com> wrote:
> > On Tue, Aug 08, 2023 at 01:48:25PM -0500, Serge Hallyn wrote:
> > > On Mon, Jul 10, 2023 at 05:23:08AM -0500, Dr. Greg wrote:
> 
> ...
> 
> > > > +of a model.  This allows a TMA to attest to the trust/security status
> > > > +of a platform or workload by signing this singular value and
> > > > +presenting it to a verifying party.
> > > > +
> > > > +In TSEM nomenclature, this singular value is referred to as the
> > > > +'state' of the model.  The attestation model is to use trust
> > > > +orchestrators to generate the state value of a workload by unit
> > > > +testing.  This state value can be packaged with a utility or container
> > > > +to represent a summary trust characteristic that can be attested by a
> > > > +TMA, eliminating the need for a verifying partner to review and verify
> > > > +an event log.
> > > > +
> > > > +TMA's implement this architecture by maintaining a single instance
> > > > +vector of the set of security state coefficients that have been
> > > > +generated.  A state measurement is generated by sorting the vector in
> > > > +big-endian hash format and then generating a standard measurement
> > > > +digest over this new vector.
> >
> > > Are you saying the TMA will keep every meaningful measurement for
> > > the duration of the workload, so that it can always sort them?
> >
> > Correct, every unique security state coefficient.
> >
> > The approach isn't unique and without precedent.  Roberto Sassu is
> > using a similar strategy in order generate a time/order independent
> > PCR value for unlocking TPM sealed keys by parsing RPM and .deb
> > distribution manifests.
> >
> > Paul Moore, in his comments in February to the V1 series, even
> > seriously questioned why we would expose the classic linear extension
> > measurement from a TMA.

> To put my comment from the first revision into the proper context,
> and with my understanding that TSEM's security model does not
> consider event ordering/timing, I questioned what TSEM would expose
>					       ^^^^ why??
> an ordered list of events to userspace in addition to its unordered,
> sorted list.
>
> Either ordering is important to the security model, in which case you
> expose the ordered list, or it isn't, in which case you expose the
> list in whatever form is most convenient for the tooling/model; it
> makes little sense to me to expose both.

As a generic clarification in furtherance of getting everyone on the
same page with respect to the focus of our work.

TSEM is about providing generic infrastructure for security modeling
and anomaly detection that acts at the most precise level of security
instrumentation that is available.

Secondary to that pursuit, TSEM offers security architects the ability
to choose from either a time dependent or a time independent appraisal
of a security modeling namespace.

The TSEM 'trajectory' file is always time ordered with respect to the
first unique occurrence of a security event.  In the V3 release, these
trajectory entries include a nanosecond timestamp reference, relative
to boot, of when the event occurred.

The 'measurement' pseudo-file allows a relying party to verify that
the trajectory list, as presented, is order/time consistent, if that
is what they choose to evaluate.

The 'state' pseudo-file allows a relying party to make a decision on
whether or not the security status of the system is idempotent, from
an event perspective, with a known reference state.

It addresses, among other issues, the problem that IMA is currently
facing with the fact that handling and examining unconstrained event
logs can be problematic from a number of perspectives.

Alternately, now in V3, a security model implementator can specify
that a security event stream from a modeling namespace be
asynchronously exported in its entirety and dealt with in whatever
fashion an external evaluator desires.

So TSEM doesn't implement or advocate a security model as much as it
implements security infrastructure.

> paul-moore.com

Have a good weekend.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity
              https://github.com/Quixote-Project

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 2/13] Add TSEM specific documentation.
  2024-01-04  4:00   ` [PATCH 2/13] " Paul Moore
  2024-01-05  2:55     ` Dr. Greg
@ 2024-01-08 11:43     ` Dr. Greg
  2024-02-05 16:09       ` Paul Moore
  1 sibling, 1 reply; 36+ messages in thread
From: Dr. Greg @ 2024-01-08 11:43 UTC (permalink / raw)
  To: Paul Moore; +Cc: linux-security-module, linux-kernel, corbet

On Wed, Jan 03, 2024 at 11:00:33PM -0500, Paul Moore wrote:
> On Jul 10, 2023 "Dr. Greg" <greg@enjellic.com> wrote:
> > 
> > An entry was added to the ABI testing documentation to document
> > the files in the TSEM management filesystem.
> > 
> > The file documenting the kernel command-line parameters was
> > updated to document the TSEM specific command-line parameters
> > 
> > The primary TSEM documentation file was added to the LSM
> > administration guide and the file was linked to the index of LSM
> > documentation.
> > 
> > Signed-off-by: Greg Wettstein <greg@enjellic.com>
> > ---
> >  Documentation/ABI/testing/tsem                |  828 +++++++++
> >  Documentation/admin-guide/LSM/index.rst       |    1 +
> >  Documentation/admin-guide/LSM/tsem.rst        | 1526 +++++++++++++++++
> >  .../admin-guide/kernel-parameters.txt         |   18 +
> >  4 files changed, 2373 insertions(+)
> >  create mode 100644 Documentation/ABI/testing/tsem
> >  create mode 100644 Documentation/admin-guide/LSM/tsem.rst

> Let me start by apologizing for the delay in responding, your patience
> was appreciated.  Comments below ...

In my previous reply I responded to what you considered to be your two
major concerns.

For clarification purposes I will follow up on the other issues you
raised so we can potentially make adjustments in V3.

> > diff --git a/Documentation/ABI/testing/tsem b/Documentation/ABI/testing/tsem
> > new file mode 100644
> > index 000000000000..cfb013b5f1f4
> > --- /dev/null
> > +++ b/Documentation/ABI/testing/tsem
> > @@ -0,0 +1,828 @@
> > +What:		/sys/kernel/security/tsem
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The /sys/kernel/security/tsem directory contains files
> > +		and directories that implement the control plane for
> > +		the Trusted Security Event Modeling (TSEM) LSM.
> > +
> > +		The files in this directory hierarchy, with the
> > +		exception of the aggregate file, when read, reflect
> > +		the values for the security modeling namespace that
> > +		the process reading the files is operating in.
> > +
> > +What:		/sys/kernel/security/tsem/id
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The id file contains the ASCII base 10 representation
> > +		of the model domain/namespace identifier that the
> > +		reading process is operating in.
> > +
> > +		The root security modeling namespace has a value of
> > +		zero, a non-zero value indicates a modeling namespace
> > +		subordinate to the root model.
> > +
> > +		Each externally modeled domain will have a file, with
> > +		this id number, created in the
> > +		/sys/kernel/security/tsem/ExternalTMA directory that
> > +		is documented below.

> Just making sure you want to use uppercase here.  It's your call,
> but it tends to go against convention, and changing it after the
> code is in a tagged release it painful enough that it should be
> considered practically impossible.  This applies not just to this
> file, but all of the other mixed/upper case TSEM files under /sys.

There are only two files with mixed case, we will convert them to the
following:

/sys/kernel/security/tsem/external_tma
/sys/kernel/security/tsem/internal_tma

Let us know if you disagree.

> > +What:		/sys/kernel/security/tsem/aggregate
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The aggregate file contains the ASCII base 16
> > +		representation of the 256 bit hardware platform
> > +		aggregate that TSEM is modeling under.  The platform
> > +		aggregate is the linear extension measurement of the
> > +		Trusted Platform Module PCR registers 0 through 8.

> I believe we talked about hash agility previously, but just in case,
> you may want to reword the above to provide some flexibility around
> the hash algorithm used.  On the other hand, if you want to stick
> with a single hash algorithm and 256-bit digest length, you might as
> well specify the hash algorithm here.

TSEM should now have the maximum amount of hash agility available on
Linux.

From the V2 cover letter enhancements:

- Allow cryptographic hash function used for coefficient generation to
  be configured on a namespace by namespace basis.

Which may understate the issue a bit.

TSEM can now use any hash function availble in Linux as the
compression function for a security modeling namespace.  Different
namespaces can operate with different hash functions simultaneously.

In V3 we will re-word all of the references to SHA256 to indicate that
the output value will be the ASCII expression of the digest function
specified for the modeling namespace.

> I don't want to assume too much about the TSEM design, but I'm
> guessing the aggregate is intended to be a deterministic value based
> on the PCRs and therefore it seems like there is value in providing
> a clear explanation of how it is calculated.

The aggregate is the linear extension sum over PCR registers 0 through
8 using the namespace hash function, we will cook up a generic
description, although it should be a common enough concept for anyone
working on trusted system implementations.

> > +		On a platform without a TPM this value will be all
> > +		null bytes.

> Just to clarify, are you intending this to be NULL bytes (as
> written) or an ASCII base 16 zero value, padded out to the digest
> length, similar as to what you might see in the output of the
> `tpm2_pcrread` command for a zero-value PCR?  Once again, it's your
> call, I just wanted to clarify.

It will be what would constitute the expression of least surprise, a
sequence of ASCII 0's padded to the digest size, the same as a pcrread
of a zero-value PCR.

> > +What:		/sys/kernel/security/tsem/control
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The control file is the only writable file in the
> > +		filesystem and is used by the trust orchestrator's to
> > +		configure and control the behavior of the TSEM
> > +		implementation.

> I would drop the "only writable file ..." portion above; it may be the
> only writable file under /sys/kernel/security/tsem at the moment, but
> I imagine there is a good chance that will change over time and the
> comment doesn't really add anything important.

Will change.

> > +		The following keyword and arguments are recognized:
> > +
> > +		internal
> > +			The internal keyword causes an internally
> > +			modeled domain to be created for the calling
> > +			process.
> > +
> > +		external
> > +			The external keyword causes an externally
> > +			modeled domain to be created for the calling
> > +			process.
> > +
> > +			A modeling namespace created by these commands
> > +			accept the following set of key=value pairs
> > +			that configure the namespace:

> I assume whitespace is used as a delimiter?  That would be good to
> document, both between the key-value-pairs as well as the initial
> op/keyword.

Yes, arguments are white space delimited, we use argv_split for the
parsing of all the control plane directives.

> Also, do these key-value-pairs apply to both internal and external
> domains?  The text seems to indicate that they do, but the way the
> document is structured hints that they only apply to the external
> domain.  Perhaps a sentence in the internal domain description
> indicating that all of the external domain configuration parameters
> apply to internal domains as well, unless explicitly stated
> otherwise.

We will take a look at making this more clear.

> > +			nsref=initial|current
> > +				The nsref key specifies the namespace
> > +				that is to be referenced when
> > +				determining the UID/GID values that
> > +				define a COE or CELL identity.

> Are COE or CELL acronyms?  If so, it would be nice to expand them on
> first use in the document.

COE is an acronym for Context Of Execution, in TSEM the security
characteristics of what would be the equivalent of the subject in a
MAC.

CELL doesn't stand for anything other than CELL, it is a term to
reflect the collection of characteristics that describe a security
event being modeled, roughly the equivalent of an object in MAC.

We use CELL in respect to Turing computability theory in that TSEM is
based on the predicate that a unique identity can be generated for
each security event that an execution 'head' passes over.

The first contribution of wonkiness for today's e-mail... :-)

> > +				The initial keyword specifies that the
> > +				initial user namespace be used.  The
> > +				current keyword specifies that the
> > +				user namespace of the process that is
> > +				invoking a security event handler
> > +				(hook) is used.
> > +
> > +			digest=digestname
> > +				The digest key is used to specify the
> > +				cryptographic hash function that is to
> > +				be used in the namespace for the
> > +				creation of COE and CELL identities.
> > +
> > +				The digestname is the name used by the
> > +				Linux kernel cryptographic API to
> > +				identify the hash function.  Examples
> > +				would include sha256, sha3-256, sm3
> > +				etc.  The source files for the
> > +				cryptographic hash function in the crypto
> > +				directory of the kernel source has the
> > +				names for hash functions implemented
> > +				in the kernel.
> > +
> > +				The sha256 hash function is the
> > +				default function for the root modeling
> > +				domain.  This can be modified by the
> > +				tsem_digest command-line parameter.
> > +
> > +				A hash function, used by the root
> > +				modeling domain, must be built into
> > +				the kernel.
> > +
> > +			cache=NN
> > +				The cache key specifies the size of
> > +				the caches to be used for holding
> > +				pointers to structures used for the
> > +				modeling or export of security events
> > +				that are called while the invoking
> > +				process is in atomic context.
> > +
> > +				The value NN is the ASCII base 10
> > +				representation of the number of
> > +				entries in the cache.
> > +
> > +				By default, the root modeling
> > +				namespace and an externally modeled
> > +				namespace will have 96 entries.  An
> > +				internally modeled namespace will have
> > +				16 entries.
> > +
> > +			key=HEXID
> > +				The key argument is used to specify
> > +				the authentication key that will be
> > +				used by a trust orchestrator to
> > +				authenticate trust control requests to
> > +				a process running in the security
> > +				modeling namespace.
> > +
> > +				The HEXID value is the ASCII base16
> > +				encoded key that is to be used.  The
> > +				length of this key, in binary, must be
> > +				equal to the size of the digest
> > +				produced by the cryptographic hash
> > +				function that is being used in the
> > +				modeling namespace.
> > +
> > +		enforce
> > +			The enforce keyword causes the modeling
> > +			domain/namespace of the process to enter
> > +			enforcing mode.  In this mode, a value of
> > +			-EPERM will be returned for a security event
> > +			coefficient that does not map into the current
> > +			set of allowed coefficients for the security
> > +			model being implemented in the namespace.
> > +
> > +		seal
> > +			The seal keyword causes the security model
> > +			being implemented for the namespace to be
> > +			placed in a sealed state.  In this state, the
> > +			current set of security coefficients is
> > +			considered to be the only set of valid
> > +			coefficients for the model.  Any subsequent
> > +			events that map to a coefficient not in the
> > +			current model will be considered a violation
> > +			of the model.
> > +
> > +		trusted pid=PID key=HEXID
> > +			The trusted keyword is used by a trust
> > +			orchestrator to indicate that the process
> > +			identified by the PID argument should be
> > +			allowed to run in trusted status after the
> > +			modeling of a security event.

> I mentioned this quite a few times in my review of the previous
> patchset, PIDs are not a safe way to identify a process in the
> system.  PID reuse/recycling is a real danger and you need to
> account for this risk.

We will defer that discussion to our previous e-mail where we
discussed how this is addressed.

> > +			The HEXID argument is the authentication key
> > +			that has been configured by a trust
> > +			orchestrator for the namespace at the time of
> > +			its creation.
> > +
> > +		untrusted pid=PID key=HEXID
> > +			The untrusted keyword is used by a trust
> > +			orchestrator to indicate that the process
> > +			identified by the PID argument should be
> > +			designated as an untrusted process.
>
> See above, you can't use a PID to safely identify a process.
> 
> > +			The HEXID argument is the authentication key
> > +			that has been configured by a trust
> > +			orchestrator for the namespace at the time
> > +			its creation.
> > +
> > +		state value=HEXID
> > +			The state keyword is used to indicate that the
> > +			security state coefficient identified by the
> > +			ASCII base 16 encoded value specified by HEXID
> > +			should be loaded into the current security
> > +			model as a valid security event coefficient.
> > +
> > +		pseudonym valid=HEXID
> > +			The pseudonym keyword is used to indicate that
> > +			the pathname, identified by the ASCII base 16
> > +			encoded value HEXID, should be designated to
> > +			return a constant digest value for the
> > +			contents of the file named by the pseudonym.
> > +
> > +			The HEXID value is computed with the following
> > +			function:
> > +
> > +			HEXID = HF(PATHNAME_LENGTH || PATHNAME)
> > +
> > +			WHERE HF is the cryptographic hash function
> > +			that has been designated for use by the
> > +			security modeling namespace.

> How do you handle hash collisions?  Given that users will likely be
> able to create files with arbitrary names, it seems like identifying
> files by a hash of their pathname without any way to safely resolve
> digest collisions is a problem in waiting.

Also addressed in our first e-mail, we will stand by for your comments
there.

> > +		base value=HEXID
> > +			The base keyword is used to indicate that the
> > +			ASCII base 16 encoded value HEXID should be
> > +			registered as the value used to generate
> > +			security state coefficients for the model
> > +			implemented in the modeling namespace.
> > +
> > +			The binary length of the value specified by
> > +			HEXID must match the digest size of the
> > +			cryptographic hash function specified for use
> > +			in the security modeling namespace.
> > +
> > +			A model specific base value is designed to be
> > +			used as a 'freshness' nonce, similar to an
> > +			attestation nonce, to prove that a model state
> > +			value or measurement is current and not being
> > +			replayed.
> > +
> > +What:		/sys/kernel/security/tsem/InternalTMA
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +
> > +		This directory will contain directories that will be
> > +		used to hold files that surface model parameters for
> > +		Trusted Modeling Agents (TMA's) for internally modeled
> > +		security namespaces.
> > +
> > +		There is currently only one internal TMA that is
> > +		surfaced through the following directory:
> > +
> > +		/sys/kernel/security/tsem/InternalTMA/model0
> > +
> > +		The subsequent descriptions for the files implemented
> > +		in this directory will use ROOTDIR to represent the
> > +		above directory for space conservation purposes.
> > +
> > +What:		ROOTDIR/measurement
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The measurement file contains the ASCII base 16
> > +		representation of the time dependent linear extension
> > +		value of all the security state coefficients in the
> > +		model implemented by the namespace of the calling
> > +		process.

> If I remember correctly, one of the motivations for TSEM was to
> avoid the time/ordering aspect of traditional attestation approaches
> as it can be fragile.  Assuming that my memory is correct, and this
> still holds true in the revision of the patchset, why are you
> continuing to export time/order dependent measurements to userspace?
>
> Either the ordering is important, in which case TSEM's novelty isn't
> useful, or the ordering isn't important and we can remove this sysfs
> file.

We addressed that in the second e-mail we sent last Friday.

As we indicated in that e-mail, TSEM is about implementing
infrastructure for building arbitrary mandatory security models.  We
don't advocate for either a time dependent or time independent model,
we leave that up to whoever is implementing a security model to be
executed in a modeling namespace by TSEM.

Hopefully we have established that there is some small modicum of
novelty in TSEM beyond the notion of a time independent measurement of
the state state of a workload...

> > +What:		ROOTDIR/state
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The state file contains the ASCII base 16
> > +		representation of the functional value of a security
> > +		modeling namespace.
> > +
> > +		The state value is a time independent representation
> > +		of the measurement of a security model, and unlike the
> > +		measurement value, is a time independent
> > +		representation of the state.
> > +
> > +		This value is designed to be a single value that can
> > +		be attested to represent whether or not a workload has
> > +		deviated from a defined security behavior.

> Continuing the comment above regarding ROOTDIR/measurement, this
> file makes much more sense in the context of TSEM.

Once again, we offer both since TSEM is a general purpose security
modeling framework.

> > +What:		ROOTDIR/trajectory
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The trajectory file contains a description of the
> > +		security events that have occurred in a security
> > +		modeling namespace
> > +
> > +		Each entry in this file represents a single security
> > +		event and consists of a JSON encoded record with key
> > +		values that define the characteristics of the event.
> > +
> > +		Each line in a trajectory, or forensics, file will
> > +		always have the event and COE keys.  The event key
> > +		describes the characteristics of a security event
> > +		while the COE field describes the Context Of Execution
> > +		that is requesting execution of a security event.
> > +
> > +		The event key consists of the following
> > +		characteristic definitions:
> > +
> > +			process: COMM
> > +				Where COMM is the ASCII representation
> > +				of the name of the process executing
> > +				the event.

> What happens if a process, either innocently or maliciously, changes
> its name (see prctl(PR_SET_NAME))?  Would it result in a mismatch of
> the security state of a process?

The process name isn't incorporated into the security state
coefficient, it is included as an aid for developers or security
architects who are analysing security event description streams.

At the risk of injecting a bit more wonkiness, TSEM approaches
security from the perspective of Hegelian epistemology, roughly
translated, TSEM security decisions are exclusively experiential,
ie. derived from unit testing of a workload.

If the process name was included in the composition of a security
state coefficient, any subsequent execution of the workload would have
to use that name, otherwise it would generate a security model
violation.

Additionally, TSEM implements a handler for the task_prctl event.  If
a process in a workload would attempt to use prctl to change its
process name, and that was not a modeled event, a security event
coefficient would be generated which would be inconsistent with the
security model being enforced.

> > +			type: EVENT_TYPE
> > +				The value field for a type key is the
> > +				name of the security event that is
> > +				being modeled.  The list of EVENT_TYPE
> > +				names is defined in the following
> > +				source file:
> > +
> > +				security/tsem/tsem.c
> > +
> > +				If the security event is a generically
> > +				modeled event the EVENT_TYPE will be
> > +				generic_event.  In this case the CELL
> > +				characteristics for the event will be
> > +				described by a generic_event: key

> I'm guessing EVENT_TYPE is an ASCII string representation?  It would
> be good to clarify as you have in most (all?) of the other fields
> and the omission here raises a red flag.

We will clarify, but for future reference all of the control plane
output files emit ASCII exclusively.

> > +			task_id: HEXID
> > +				The value of the task_id key will the
> > +				ASCII base 16 representation of the
> > +				identity of the task that is executing
> > +				the security handler.  The length of
> > +				HEXID will match the size of the
> > +				digest value of the cryptographic hash
> > +				function selected for use by the
> > +				security modeling namespace.
> > +
> > +				The following documentation file:
> > +
> > +				Documentation/admin-guide/LSM/TSEM.rst

> It looks like the file is lowercase ".../tsem.rst".

Good catch, we missed that in the release review.

> > +				Describes how the TASK_ID value is
> > +				generated.

> I would suggest either moving or copying the TASK_ID definition here
> so that it is included in the TSEM ABI document.

As we mentioned in the first e-mail, we were considering putting a
disclaimer at the top of the ABI document that the tsem.rst file
should be consumed first as a primer for understanding the ABI.

> > +		The COE key has the following characteristic keys.
> > +		Keys that involve discretionary access values
> > +		(uids/gids) will have their numeric value computed
> > +		based on the user namespace reference value that is
> > +		being implemented in the security modeling namespace.
> > +
> > +			uid: NN
> > +				The ASCII base 10 representation of
> > +				the numeric value of the discretionary
> > +				user id of the process that is
> > +				executing the security event.
> > +
> > +			euid: NN
> > +				The ASCII base 10 representation of
> > +				the numeric value of the effective
> > +				discretionary user id of the process
> > +				that is executing the security event.
> > +
> > +			euid: NN
> > +				The ASCII base 10 representation of
> > +				the numeric value of the effective
> > +				discretionary user id of the process
> > +				that is executing the security event.
> > +
> > +			suid: NN
> > +				The ASCII base 10 representation of
> > +				the numeric value of the saved user id
> > +				of the process that is executing the
> > +				security event.
> > +
> > +			gid: NN
> > +				The ASCII base 10 representation of
> > +				the numeric value of the discretionary
> > +				group id of the process that is
> > +				executing the security event.
> > +
> > +			egid: NN
> > +				The ASCII base 10 representation of
> > +				the numeric value of the discretionary
> > +				effective group id of the process that
> > +				is executing the security event.
> > +
> > +			egid: NN
> > +				The ASCII base 10 representation of
> > +				the numeric value of the discretionary
> > +				effective group id of the process that
> > +				is executing the security event.
> > +
> > +			sgid: NN
> > +				The base 10 ASCII representation of
> > +				the numeric value of the saved
> > +				discretionary group id of the process
> > +				that is executing the security event.
> > +
> > +			fsuid: NN
> > +				The base 10 ASCII representation of
> > +				the numeric value of the discretionary
> > +				filesystem user id of the process that
> > +				is executing the security event.
> > +
> > +			fsgid: NN
> > +				The ASCII base 10 representation of
> > +				the numeric value of the discretionary
> > +				filesystem group id of the process
> > +				that is executing the security event.
> > +
> > +			capeff: 0xNNN
> > +				The ASCII base 16 representation of
> > +				the numeric value of effective
> > +				capabilities of the process that is
> > +				executing the security event.
> > +
> > +		If the CELL value for a security event includes the
> > +		definition of a file a file: key value will be
> > +		included.  The following characteristics will be
> > +		encoded in this field:
> > +
> > +			flags: NN
> > +				The ASCII base 10 representation of
> > +				the flags value of the 'struct file'
> > +				structure that is the source of the
> > +				file description.
> > +
> > +			uid: NN
> > +				The ASCII base 10 representation of
> > +				the discretionary user id of the file.
> > +
> > +			gid: NN
> > +				The base 10 ASCII representation of
> > +				the discretionary group id of the
> > +				file.
> > +
> > +			mode: 0NNN
> > +				The ASCII base 8 representation of the
> > +				mode bits of the file.

> Does the leading zero followed by three octets imply you don't
> record the setuid/setgid/sticky bits?

The full value of the mode variable is output, including the
setuid/setgid/sticky bits, the NNN is an arguably confusing
representation and we will figure out an alternative way to document
this.

> > +			name_length: NN
> > +				The ASCII base 10 representation of
> > +				the length of the pathname that will
> > +				be encoded in the name= characteristic.

> To clarify, this is the length of the pathname used during the file
> lookup and not the length of the hash digest of the previously
> mentioned pathname, yes?

As we mentioned previously, this no longer exists in V3.

> > +			name: NN
> > +				The ASCII hexadecimal representation
> > +				of the SHA256 checksum of the pathname
> > +				of the file that is pre-pended with
> > +				the little-endian binary value of the
> > +				length of the pathname.

> Hash agility?

Maximized in V3... :-)

> It isn't clear to me if the length is prepended before or after the
> hash, it would be good to clean this up.
> 
> Also, similar to some comments above, how are you handling hash
> collisions?  As pathnames can be influenced by unprivileged users, this
> would appear to be an issue.

Addressed in previous e-mail.

Succinctly, to our knowledge, there are no computationally feasible
2nd pre-image attacks against modern hash functions that would be used
for TSEM.

If you have information otherwise, we, and probably the rest of the
security industry, would be deeply interested if not concerned.

To extend a bit further.

The viability of a pathname or security coefficient stream collision
attack needs to be assessed with respect to the experiential nature of
the TSEM security models.

If an adversary was attempting to change pathnames in order to to
exploit a collision against an existing security state coefficient the
model under which the workload was running would need to reflect the
security states that would be needed for the pathname changes,
otherwise the workload would be in violation of its model.

Without digging too deep, at a minimum, a tsem_inode_create event
would be presumably triggered on the creation of a new candidate
filename to exploit the collision.

> > +			s_magic: 0xNN
> > +				The ASCII base 16 representation of the
> > +				magic number of the filesystem that
> > +				contains the file.
> > +
> > +			s_id: NAME
> > +				The ASCII name of the block device for
> > +				the filesystem that contains the file.
> > +
> > +			s_UUID: HEX
> > +				The ASCII base 16 representation of
> > +				the hexadecimal value of the UUID of
> > +				the filesystem that contains the file.
> > +
> > +			digest: HEX
> > +				The ASCII base 16 representation of
> > +				the SHA256 digest of the file.

> Hash agility?
> 
> Is TSEM running a hash over every file included in a file-related
> security event?

Yes, unless the model developer has tagged the file as having a
digest pseudonym.

> > +		If the event type is the memory mapping of a file a
> > +		mmap_file key value will be included with
> > +		the following characteristics:

> Still part of the CELL?  COE?  This doc could benefit from better
> explanations of the CELL and COE terms.

This would be the CELL, since it characterizes the security event.

> > +			type: N
> > +				Where N is an ASCII 0 or 1 to indicate
> > +				whether or not the mapping is file
> > +				backed or anonymous.  A value of 1 is
> > +				used to indicate an anonymous mapping.
> > +
> > +			reqprot: NN
> > +				Where N is ASCII base 10
> > +				representation of the protections
> > +				requested for the mapping.
> > +
> > +			prot: NN
> > +				Where N is the ASCII base 10
> > +				representation of the protections that
> > +				will be applied to the mapping.
> > +
> > +			flags: NN
> > +				Where N is the ASCII base 10
> > +				representation of the flags that will
> > +				be used for the memory mapping operation.

> You should specify the flags used in the fields above, or refer
> readers to the mmap(2) flag definitions if appropriate.

In V3 all of the security events are fully parameterized.  We will
include documentation that the CELL field for each event encodes the
arguments to the event.

In light of this we will be evaluating how to best express the ABI
documentation.

> > +		If the event type is a socket creation event a
> > +		socket_create key value will be included with the
> > +		following characteristics:
> > +
> > +			family: N
> > +				Where N is the ASCII base 10
> > +				representation of the family type of
> > +				the socket.
> > +
> > +			type: N
> > +				Where N is the ASCII base 10
> > +				representation of the type of socket
> > +				being created.
> > +
> > +			protocol: N
> > +				Where N is the ASCII base 10
> > +				representation of the protocol family
> > +				for the socket.

> Similar to the mmap flags above, I would refer people to where these
> values are defined.  The applies to the other socket family/type/proto
> fields described elsewhere in this document.

That will be part of the ABI review in V3.

> > +			kern: 0 | 1
> > +				Where 0 or 1 is used to indicate
> > +				whether or not the socket is kernel
> > +				based.  A value of 1 implies it is
> > +				kernel based.

> I'm curious how TSEM would distinguish between different kernel
> socket events.  I would expect most kernel sockets to share the same
> event key (COE/CELL/etc.), is that not the case?

In V3 all of the generation of security state coefficient that include
a struct sock * argument to the handler include the TASK_ID of the
task that created the socket, this causes the security state
coefficients to be tied to the corpus of executable code that created
the socket.

The same is being done with other resource types that are 'created' in
a modeling namespace, ie. ipc, inodes etc.

> > +		If the event type is a socket_connect or a
> > +		socket_bind, a socket_connect: or a socket_bind: key
> > +		value will be included that will be characterized
> > +		based on an encoding of either an IPV4, IPV6, AF_UNIX
> > +		or a generic socket description.
> > +
> > +			family: N
> > +				Where N is the ASCII base 10
> > +				representation of the family type of
> > +				the socket.
> > +
> > +			port: N
> > +				Where N is the base ASCII base 10
> > +				representation of the port number that
> > +				is being used for either an IPV4 or
> > +				IPV6 socket connection or bind.
> > +
> > +			addr: N | PATH | HEXID
> > +				In the case of an IPV4 socket the
> > +				value for the addr key will be the
> > +				ASCII base 10 representation of the 32
> > +				bit IPV4 address being bound or
> > +				connected to.
> > +
> > +				In the case of an IPV6 connection the
> > +				value to the key will be the ASCII
> > +				base 16 representation of the 128 bit
> > +				address being bound connected.
> > +
> > +				In the case of an AF_UNIX connection
> > +				the value will be the pathname of the
> > +				socket in the mount namespace that the
> > +				process is running in.
> > +
> > +				In the case of any other type of
> > +				socket the addr value will be the
> > +				ASCII base 16 representation of the
> > +				cryptographic digest value of the
> > +				entire length of the address
> > +				description.  The length of the
> > +				representation will be the size of the
> > +				digest produced by the cryptographic
> > +				hash function that has been specified
> > +				for the modeling namespace.
> > +
> > +			flow: N
> > +				For an IPV6 socket the value of the
> > +				flow key will be the ASCII base 10
> > +				representation of the flow identifier
> > +				assigned to the socket.
> > +
> > +			scope: N
> > +				For an IPV6 socket the value of the
> > +				scope key will be the ASCII base 10
> > +				representation of the scope identifier
> > +				assigned to the socket.

> What will "flow" and "scope" be for non-AF_INET6 sockets?  You need
> to specify that here.

There will be no 'flow' or 'scope' values for non-AF_INET6 sockets.

The JSON encoded security event descriptions are designed to be
self-expressive by whatever is interpreting the event stream, ie. if
the socket family is AF_INET the interpreter will not look for keys
that would express characteristics not expected in an IPV4 socket
description.

> > +		If the event type is a socket_accept a socket_accept
> > +		key value will be included that characterizes either
> > +		an IPV4, IPV6 or a generic socket description with the
> > +		following event descriptions:
> > +
> > +			family: N
> > +				Where N is the ASCII base 10
> > +				representation of the family type of
> > +				the socket.
> > +
> > +			type: N
> > +				Where N is the ASCII base 10
> > +				representation of the type of the
> > +				socket being created.
> > +
> > +			port: N
> > +				Where N is the base ASCII base 10
> > +				representation of the port number that
> > +				is being used for either an IPV4 or
> > +				IPV6 socket connection or bind.
> > +
> > +			addr: N | PATH | HEXID
> > +				In the case of an IPV4 socket the
> > +				value for the addr key will be the
> > +				ASCII base 10 representation of the 32
> > +				bit IPV4 address being bound or
> > +				connected to.
> > +
> > +				In the case of an IPV6 connection the
> > +				value to the key will be the ASCII
> > +				base 16 representation of the 128 bit
> > +				address being bound connected.
> > +
> > +				In the case of an AF_UNIX connection
> > +				the value will be the pathname of the
> > +				socket in the mount namespace that the
> > +				process is running in.
> > +
> > +				In the case of any other type of
> > +				socket the addr value will be the
> > +				ASCII base 16 representation of the
> > +				cryptographic digest value of the
> > +				entire length of the address
> > +				description.  The length of the
> > +				representation will be the size of the
> > +				digest produced by the cryptographic
> > +				hash function that has been specified
> > +				for the modeling namespace.
> > +
> > +What:		ROOTDIR/trajectory_coefficients
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The trajectory_coefficients file will output the ASCII
> > +		base16 representation of each security state
> > +		coefficient that has been generated by the security
> > +		modeling namespace of the calling process.
> > +
> > +		The length of each point will be the ASCII
> > +		representation of the size of the cryptographic hash
> > +		function that has been specified for the model.

> Is this just the ROOTDIR/trajectory JSON in ASCII hex, or something
> different?

These are the security state coefficients that each event in the
trajectory file encodes into under the current model.

> > +What:		ROOTDIR/trajectory_counts
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The trajectory_coefficients file will output the ASCII
> > +		base10 representation of the number of times each

> Unless I'm mistaken, I believe you defined it as base16 above ... ?

These are base 10 values that describe how many times each unique
security event has been experienced in the model.

> > +		security state coefficient has been generated by the
> > +		security modeling namespace of the calling process.
> 
> This looks like an old cut-n-paste error.  I'm guessing this file
> reports on the number of coefficients in ASCII base10?

Correct.

> > +What:		ROOTDIR/forensics
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The forensics file contains the descriptions of
> > +		security events that are inconsistent with the
> > +		security model that the security namespace is
> > +		implementing.  Forensics events are generated after a
> > +		security model is 'sealed' and the events represent
> > +		security state coefficients that have not already been
> > +		generated by the model.
> > +
> > +		The format of lines in this file are identical to the
> > +		output generated by the ROOTDIR/trajectory file
> > +		that is documented above.
> > +
> > +What:		ROOTDIR/forensics_coefficients
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The forensics_coefficients file will output the ASCII
> > +		base16 representation of each security state
> > +		coefficient that have been generated by forensics
> > +		events in the security modeling namespace of the
> > +		calling process.
> > +
> > +		The length of each point will be the ASCII
> > +		representation of the size of the cryptographic hash
> > +		function that has been specified for the model.
> > +
> > +What:		ROOTDIR/forensics_counts
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The forensics_counts file will output the ASCII base10
> > +		representation of the number of times each security
> > +		state coefficient, generated by a forensics event, has
> > +		been generated by the security modeling namespace of
> > +		the calling process.
> > +
> > +What:		/sys/kernel/security/tsem/ExternalTMA
> > +Date:		July 2023
> > +Contact:	Greg Wettstein <greg@enjellic.com>
> > +Description:
> > +		The ExternalTMA directory is a container directory
> > +		that hold files that will be used to export the
> > +		security events, and their associated parameters, for
> > +		externally modeled security modeling namespaces.
> > +
> > +		The files created in this directory will be named by
> > +		the base 10 ASCII representation of the id value
> > +		assigned to the security modeling namespace.  See the
> > +		documentation for the /sys/kernel/security/tsem/id
> > +		file in this documentation for more details on this
> > +		value.
> > +
> > +		This file will is a read-only file that can be polled
> > +		by a userspace trust orchestrator implementation to
> > +		process security events that are to be modeled by an
> > +		external Trusted Modeling Agent.
> > +
> > +		Each exported event is a JSON encoded record
> > +		describing the event that is to be processed.
> > +
> > +		Each record will have an 'export' key that has a
> > +		structure associated with it that has a 'type' key in
> > +		it.  The 'type' key has a string value associated with
> > +		it that defines the type of event that is being
> > +		processed.
> > +
> > +		The following export 'type' strings are defined:
> > +
> > +		aggregate:
> > +			The aggregate key has an associated structure
> > +			value that defines a key named 'value' that
> > +			has a string value associated with it that
> > +			represents the hardware aggregate for the
> > +			platform.

> You need to define "hardware aggregate" here, if you can't go into
> detail you need a good summary outlining its security relevant
> properties.

As noted above, will consider how to do this.

> > +			The hardware aggregate string is expressed as
> > +			the ASCII base16 representation of the
> > +			platform hardware aggregate value.  The length
> > +			of the string will be the size of the digest
> > +			produced by the cryptographic hash function
> > +			that has been specified for the security
> > +			modeling namespace of the process generating
> > +			the event.
> > +
> > +		async_event:
> > +			If the type of the export is async_event there
> > +			will be a key named 'event' that has a structure
> > +			value associated with it.
> > +
> > +			The structure associated with the 'event' key
> > +			will be identical to the structure generated
> > +			for the 'event' key that is described below.
> > +
> > +		event:
> > +			If the type of the export is event there will
> > +			be a key named 'event' that has a structure
> > +			value associated with it that contains the
> > +			follow key: value pairs.
> > +
> > +			pid: NNN
> > +				Where the NNN is the ASCII base 10
> > +				value of the id of the process that is
> > +				executing the security event that will
> > +				be modeled.

> Once more, you can't use a PID to safely identify a process.

As suggested previously, this was the subject of our first mail.

> paul-moore.com

Have a good week.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity
              https://github.com/Quixote-Project

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 2/13] Add TSEM specific documentation.
  2024-01-08 11:43     ` Dr. Greg
@ 2024-02-05 16:09       ` Paul Moore
  2024-02-19 11:16         ` Dr. Greg
  0 siblings, 1 reply; 36+ messages in thread
From: Paul Moore @ 2024-02-05 16:09 UTC (permalink / raw)
  To: Dr. Greg; +Cc: linux-security-module, linux-kernel, corbet

On Mon, Jan 8, 2024 at 6:43 AM Dr. Greg <greg@enjellic.com> wrote:
> On Wed, Jan 03, 2024 at 11:00:33PM -0500, Paul Moore wrote:
> > On Jul 10, 2023 "Dr. Greg" <greg@enjellic.com> wrote:
> > >
> > > An entry was added to the ABI testing documentation to document
> > > the files in the TSEM management filesystem.
> > >
> > > The file documenting the kernel command-line parameters was
> > > updated to document the TSEM specific command-line parameters
> > >
> > > The primary TSEM documentation file was added to the LSM
> > > administration guide and the file was linked to the index of LSM
> > > documentation.
> > >
> > > Signed-off-by: Greg Wettstein <greg@enjellic.com>
> > > ---
> > >  Documentation/ABI/testing/tsem                |  828 +++++++++
> > >  Documentation/admin-guide/LSM/index.rst       |    1 +
> > >  Documentation/admin-guide/LSM/tsem.rst        | 1526 +++++++++++++++++
> > >  .../admin-guide/kernel-parameters.txt         |   18 +
> > >  4 files changed, 2373 insertions(+)
> > >  create mode 100644 Documentation/ABI/testing/tsem
> > >  create mode 100644 Documentation/admin-guide/LSM/tsem.rst

...

> > I don't want to assume too much about the TSEM design, but I'm
> > guessing the aggregate is intended to be a deterministic value based
> > on the PCRs and therefore it seems like there is value in providing
> > a clear explanation of how it is calculated.
>
> The aggregate is the linear extension sum over PCR registers 0 through
> 8 using the namespace hash function, we will cook up a generic
> description, although it should be a common enough concept for anyone
> working on trusted system implementations.

The Linux kernel documentation is used by a wide variety of
administrators, users, and developers with varying backgrounds, I
would recommend assuming very little about the documentation's
audience.  This is not to say that you need to explain everything
yourself, referring interested readers to established, publicly
available sources of background information can be acceptable.

> > > +           trusted pid=PID key=HEXID
> > > +                   The trusted keyword is used by a trust
> > > +                   orchestrator to indicate that the process
> > > +                   identified by the PID argument should be
> > > +                   allowed to run in trusted status after the
> > > +                   modeling of a security event.
>
> > I mentioned this quite a few times in my review of the previous
> > patchset, PIDs are not a safe way to identify a process in the
> > system.  PID reuse/recycling is a real danger and you need to
> > account for this risk.
>
> We will defer that discussion to our previous e-mail where we
> discussed how this is addressed.

Adding a secret key/token/etc. may provide some additional
authentication benefits, but it doesn't entirely solve the PID
identification issue, it only reduces the likelihood of a process
misidentification.  We need to do better for new
designs/implementations; look at the pidfd work as an example of work
that has gone into reducing/eliminating the use of PIDs to identify
processes.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 2/13] Add TSEM specific documentation.
  2024-02-05 16:09       ` Paul Moore
@ 2024-02-19 11:16         ` Dr. Greg
  0 siblings, 0 replies; 36+ messages in thread
From: Dr. Greg @ 2024-02-19 11:16 UTC (permalink / raw)
  To: Paul Moore; +Cc: linux-security-module, linux-kernel, corbet

On Mon, Feb 05, 2024 at 11:09:28AM -0500, Paul Moore wrote:

Hi, I hope the week is starting well for everyone.

Sorry for the delay in responding, was involved with a bit of
travel.

> On Mon, Jan 8, 2024 at 6:43AM Dr. Greg <greg@enjellic.com> wrote:
> > On Wed, Jan 03, 2024 at 11:00:33PM -0500, Paul Moore wrote:

> > > > +           trusted pid=PID key=HEXID
> > > > +                   The trusted keyword is used by a trust
> > > > +                   orchestrator to indicate that the process
> > > > +                   identified by the PID argument should be
> > > > +                   allowed to run in trusted status after the
> > > > +                   modeling of a security event.
> >
> > > I mentioned this quite a few times in my review of the previous
> > > patchset, PIDs are not a safe way to identify a process in the
> > > system.  PID reuse/recycling is a real danger and you need to
> > > account for this risk.
> >
> > We will defer that discussion to our previous e-mail where we
> > discussed how this is addressed.

> Adding a secret key/token/etc. may provide some additional
> authentication benefits, but it doesn't entirely solve the PID
> identification issue, it only reduces the likelihood of a process
> misidentification.

We agree with you that PID reuse/recycling is a real danger.  It is
our position that TSEM, for its purposes, properly mitigates this
risk.  

Before doing that, for the benefit of everyone reading along.  The
threat scenario is that a process waiting for model evaluation of an
LSM hook by an external trust orchestrator could be killed and a
process with an identical PID substituted.  This would result in the
trust orchestrator setting the trust status of the wrong process.

Big picture overview:

- A trust orchestrator enforces a security model that has been
  previously established through unit testing as valid.  Substituting
  an alternate process with the same PID would result in that process
  being constrained to only security states that are considered valid.

- Once a process has been designated as untrusted, that status cannot
  be reversed by occupying a known good security state.  Thus a
  process misidentification attack cannot be used to reverse the
  trust state of an untrusted process.

For purposes of further clarification, lets look at the relevant
portions of the TSEM code.

For an externally modeled domain, the process begins with the export
of the security event description by tsem_export_event() in export.c:

---------------------------------------------------------------------------
int tsem_export_event(struct tsem_event *ep)
{
	int retn = 0;
	struct export_event *exp;
	struct tsem_task *task = tsem_task(current);
	struct tsem_context *ctx = task->context;

	exp = allocate_export(ep->locked);
	if (!exp) {
		pr_warn("tsem: domain %llu failed export allocation.\n",
			ctx->id);
		return -ENOMEM;
	}

	exp->type = ep->locked ? EXPORT_ASYNC_EVENT : EXPORT_EVENT;
	exp->u.ep = ep;
	tsem_event_get(ep);

	spin_lock(&ctx->external->export_lock);
	list_add_tail(&exp->list, &ctx->external->export_list);
	spin_unlock(&ctx->external->export_lock);

	if (ctx->external->export_only || ep->locked) {
		trigger_event(ctx);
		return 0;
	}

	task->trust_status |= TSEM_TASK_TRUST_PENDING;
	trigger_event(ctx);

A TSEM modeled task can exist in one of two states: TRUSTED and
UNTRUSTED in combination with TRUST_PENDING.  The process trust status
gets set to TRUST_PENDING to force it to wait until it is released by
the trust orchestrator.  The orchestrator is signaled to indicate that
a security event is in need of evaluation.

The process then waits in the following loop until the trust
orchestrator issues a control plane call to set its trust status and
clear the TRUST_PENDING state.  The PID slot will be maintained and
thus unavailable by virtue of the task maintaining a reference to the
PID slot while it is sleeping.

	while (task->trust_status & TSEM_TASK_TRUST_PENDING) {
		set_current_state(TASK_INTERRUPTIBLE);
		schedule();
		if (fatal_signal_pending(task)) {
			retn = -EPERM;
			task->trust_status = TSEM_TASK_UNTRUSTED;
		}
	}

The only way out of the loop is to either have the TRUST_PENDING
status cleared by the orchestrator or to have a fatal signal queued.
In the event of the latter condition, the process trust state is set
to untrusted for the exit and an error is returned to the trust
orchestrator.

An error return from a control plane call would be considered an
actionable event to shutdown the workload, secondary to it being
considered untrusted by virtue of a failure that should not occur.
The process itself would be considered untrusted during its exit.

Next, lets consider the issues and protections surrounding the
initiation of a fatal signal.

A security modeling namespace serves as a boundary for a kill signal,
unless a cross-model signal generation event has been enabled in the
signal initiating namespace or the initiating process has
CAP_MAC_ADMIN privileges.  Either case admits the notion that such a
signal is being administratively allowed from a security perspective.

Within a security namespace, for a kill signal to be initiated, it
must have a security state coefficient included in the model that is
specific to the TASK_ID of the process initiating the signal.  The
target of the signal must have a specific TASK_ID as well.

This gates successful signaling to two binaries of known provenance.  
Given that the model being enforced is generated from a known good unit
test, no adversarial signals would be allowed from within the modeling
namespace.

That leaves the OOM killer, as has been previously suggested.  An
adversary would need to deplete memory in a manner that caused the OOM
killer to select the process that was sleeping on an evaluation by the
trust orchestrator, rather than the adversarial process or processes
that were consuming memory.

We would also offer the following with respect to the latency
challenges associated with a PID misidentification attack.

As noted previously, threat latencies with respect to substituting an
alternate process with something like the OOM killer would be on the
order of 200-300 micro-seconds.

A sufficient number of processes would have to be forked during the
race window in order to have a process poised to replace the task that
is being held for trust evaluation.  These forks must occur before the
trust orchestrator has a chance to be scheduled and complete
processing of the event, which would have the effect of terminating
the race window.

For purposes of reasoning, here is a sample of average process fork
latencies over 32,768 attempts:

Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz - 8 core - 69.4 micro-seconds

Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz - 4 core - 81.3 micro-seconds

Intel(R) Core(TM) i5-9400 CPU @ 2.90GHz - 1 core - 132.2 micro-seconds

The above timings indicate a requirement for an adversarial process to
be within a window of 2-5 PID 'slots' below the target process for an
attack to be effective.

As noted at the start of this mail, the substituted PID would be
constrained to the security policy that the trust orchestrator is
implementing.  It would thus be limited from initiating any security
relevant events that are inconsistent with the security model being
enforced.

A single failed security event would result in a security state change
for the security modeling namespace, that in turn would result in
failed attestation of the trust status of the workload or platform.

	return retn;
}
---------------------------------------------------------------------------

There are additional quarantees in place that disallow a substituted
process from being acted upon by the trust orchestrator for a security
modeling namespace.

For an externally modeled security event, the process ends with a
request by the trust orchestrator, through the control plane file for
the security modeling namespace.  The file only allows a single open
and that open would have been by the trust orchestrator that created
the security modeling namespace, thereby precluding an adversarial
process from gaining control of the release process.

The trust relationship between an orchestrator and the processes in a
security modeling namespace is established in the allocate_external()
function in namespace.c:

---------------------------------------------------------------------------
static struct tsem_external *allocate_external(u64 context_id,
					       const char *keystr)
{
	int retn = -ENOMEM;
	char bufr[20 + 1];
	struct tsem_external *external;
	struct tsem_task *t_ttask = tsem_task(current);
	struct tsem_task *p_ttask = tsem_task(current->real_parent);

	external = kzalloc(sizeof(*external), GFP_KERNEL);
	if (!external)
		goto done;

	retn = generate_task_key(keystr, context_id, t_ttask, p_ttask);
	if (retn)
		goto done;

The generate_task_key() function is responsible for generating a
random trust orchestrator identifier that is unique across all
currently active security modeling namespaces.  Uniqueness is
guaranteed by all facets of namespace creation being gated by the
context_id_mutex lock held during the critical section of namespace
creation in tsem_ns_create().

Half of the input to the final identifier is provided by the trust
orchestrator, with the other half being a random key is generated and
attempted until a system unique identifier is demonstrated.

The trust orchestrator identifier is copied into the TSEM specific
portion of the task structure of the parent of the task that is
creating the namespace (p_ttask).  This process is the trust
orchestrator that forked the current process that is divesting itself,
and its children, into a new security modeling namespace.

By virtue of this uniqueness gurantee, no other task on the system
will have this identifier.

	spin_lock_init(&external->export_lock);
	INIT_LIST_HEAD(&external->export_list);

	init_waitqueue_head(&external->wq);

	scnprintf(bufr, sizeof(bufr), "%llu", context_id);
	external->dentry = tsem_fs_create_external(bufr);
	if (IS_ERR(external->dentry)) {
		retn = PTR_ERR(external->dentry);
		external->dentry = NULL;
	} else
		retn = 0;

 done:
	if (retn) {
		memset(t_ttask->task_key, '\0', tsem_digestsize());
		memset(p_ttask->task_key, '\0', tsem_digestsize());
		kfree(external);
		remove_task_key(context_id);
		external = ERR_PTR(retn);
	} else
		p_ttask->tma_for_ns = context_id;

In addition to having a system unique orchestration identifier placed
in the trust orchestrator's task structure, the identifier of the
namespace, that is guaranteed to not wrap, is also placed in the task
control structure of the orchestrator.

	return external;
}
---------------------------------------------------------------------------

All of this leads us to the processing of the control plane request by
a trust orchestrator to set the trust status of a process whose
security event is being modeled.  This request is handled by the
control_COE() function in fs.c:

---------------------------------------------------------------------------
static int control_COE(unsigned long cmd, pid_t pid, char *keystr)
{
	bool wakeup = false;
	int retn = -ESRCH;
	u8 event_key[HASH_MAX_DIGESTSIZE];
	struct task_struct *COE;
	struct tsem_task *task;
	struct tsem_task *tma = tsem_task(current);

	rcu_read_lock();
	COE = find_task_by_vpid(pid);

We use the standard kernel infrastructure to find the PID that has
been previously put to sleep in the export code.  If someone was
nefariously attempting to kill PIDs, an actionable error will be
registered with the trust orchestor if the task cannot be located.

Once again, the only way out of the previously described control
section is by either the process receiving a fatal signal or this
function clearing the TRUST_PENDING state bit.

	if (COE != NULL) {
		task = tsem_task(COE);
		if (tsem_context(COE)->id != tma->tma_for_ns) {
			retn = -EINVAL;
			goto done;
		}

Once the candidate task is located, its security modeling namespace
identifier is verified to match that of the trust orchestrator.  This
denies processes from outside of the security modeling namespace
access to this control call.

		retn = tsem_ns_event_key(task->task_key, keystr, event_key);
		if (retn)
			goto done;

The trust orchestrator identifier is generated using half of the key
re-supplied in the control call by the trust orchestrator itself and
the other half that has been re-supplied from the task structure of
the process being evaluated.

This limits the PID substitution domain to the security modeling
namespace that the trust orchestrator holds dominion over.  Once
again, only security relevant events that the namespace has been
tested to are allowed to occur within the namespace.

If a PID substitution attack were to be mounted, it would have to be
by 'known good' code that was admitted for execution into the modeling
namespace.

		if (memcmp(tma->task_key, event_key, tsem_digestsize())) {
			retn = -EINVAL;
			goto done;
		}

The generated key is compared to the key held inside the task control
structure of the trust orchestrator and the control is denied if they
do not match.  Once again, this would be an actionable event to
shutdown the workload as being untrusted.

		if (cmd == TSEM_CONTROL_UNTRUSTED)
			task->trust_status = TSEM_TASK_UNTRUSTED;
		if (cmd == TSEM_CONTROL_TRUSTED) {
			if (tsem_task_trusted(COE))
				task->trust_status = TSEM_TASK_TRUSTED;
		}
		task->trust_status &= ~TSEM_TASK_TRUST_PENDING;

The trust status of the process is set and the TRUST_PENDING state is
cleared.  As the above code section demonstrates, a process that is
untrusted cannot use a PID substitution attack to convert its status
to trusted.

		}
		retn = 0;
		wakeup = true;
	}

 done:
	rcu_read_unlock();

	if (retn == -EINVAL)
		pr_warn("tsem: Invalid process release request.\n");

	if (wakeup)
		wake_up_process(COE);

The process is turned loose from its loop in
export.c:tsem_export_event() with its new trust status.

	return retn;
}
---------------------------------------------------------------------------

> We need to do better for new designs/implementations; look at the
> pidfd work as an example of work that has gone into
> reducing/eliminating the use of PIDs to identify processes.

We have a high degree of familiarity with the pidfd work, in fact we
use pidfd_open() to establish a stable and immutable relationship
between a Quixote trust orchestrator and the lead process in a
security modeling namespace, typically runc in a container
environment.

In TSEM, the issue is that the trust orchestrator may not have a
direct relationship with any number of processes that may be running
in a security modeling namespace.  Processes asynchronously generate
events that need to be identified for the trust orchestrator to act
on.

If we misunderstand pidfd's, or lack understanding of other alternate
infrastructure that could be purposed for our needs, we would
certainly be interested in your thoughts on an alternate
implementation.

Otherwise we would enjoy specific comments on how our implementation
would be security insufficient in the face of a PID substitution or
race attack.

> paul-moore.com

Have a good day.

As always,
Dr. Greg

The Quixote Project - Flailing at the Travails of Cybersecurity
              https://github.com/Quixote-Project

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2024-02-19 11:17 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-10 10:23 [PATCH 00/13] Implement Trusted Security Event Modeling Dr. Greg
2023-07-10 10:23 ` [PATCH 01/13] Update MAINTAINERS file Dr. Greg
2023-07-10 20:00   ` Randy Dunlap
2023-07-15 22:45     ` Dr. Greg
2023-07-10 10:23 ` [PATCH 02/13] Add TSEM specific documentation Dr. Greg
2023-07-11  4:37   ` Randy Dunlap
2023-07-17  0:36     ` Dr. Greg
2023-07-17  1:56       ` Randy Dunlap
2023-08-08 18:48   ` Serge Hallyn
2023-08-11 20:22     ` Dr. Greg
2024-01-04 15:54       ` Paul Moore
2024-01-05  3:54         ` Dr. Greg
2024-01-04  4:00   ` [PATCH 2/13] " Paul Moore
2024-01-05  2:55     ` Dr. Greg
2024-01-08 11:43     ` Dr. Greg
2024-02-05 16:09       ` Paul Moore
2024-02-19 11:16         ` Dr. Greg
2023-07-10 10:23 ` [PATCH 03/13] Implement CAP_TRUST capability Dr. Greg
2023-08-07 20:21   ` Casey Schaufler
2023-08-15 10:19     ` Dr. Greg
2023-08-15 17:15       ` Casey Schaufler
2023-07-10 10:23 ` [PATCH 04/13] Add TSEM master header file Dr. Greg
2023-08-07 20:39   ` Casey Schaufler
2023-08-10  2:57     ` Dr. Greg
2023-08-10 15:03       ` Casey Schaufler
2023-07-10 10:23 ` [PATCH 05/13] Add primary TSEM implementation file Dr. Greg
2023-08-07 21:00   ` Casey Schaufler
2023-08-11  7:21     ` Dr. Greg
2023-07-10 10:23 ` [PATCH 06/13] Add root domain trust implementation Dr. Greg
2023-07-10 10:23 ` [PATCH 07/13] Implement TSEM control plane Dr. Greg
2023-07-10 10:23 ` [PATCH 08/13] Add namespace implementation Dr. Greg
2023-07-10 10:23 ` [PATCH 09/13] Add security event description export facility Dr. Greg
2023-07-10 10:23 ` [PATCH 10/13] Add event description implementation Dr. Greg
2023-07-10 10:23 ` [PATCH 11/13] Implement security event mapping Dr. Greg
2023-07-10 10:23 ` [PATCH 12/13] Implement an internal Trusted Modeling Agent Dr. Greg
2023-07-10 10:23 ` [PATCH 13/13] Activate the configuration and build of the TSEM LSM Dr. Greg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).