From patchwork Sat Feb 4 05:09:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128582 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0BC75C636D3 for ; Sat, 4 Feb 2023 05:32:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232700AbjBDFcl (ORCPT ); Sat, 4 Feb 2023 00:32:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43098 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232601AbjBDFck (ORCPT ); Sat, 4 Feb 2023 00:32:40 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id E77F892EC6 for ; Fri, 3 Feb 2023 21:32:39 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 31459uR6011612; Fri, 3 Feb 2023 23:09:56 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 31459uDr011610; Fri, 3 Feb 2023 23:09:56 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 01/14] Update MAINTAINERS file. Date: Fri, 3 Feb 2023 23:09:41 -0600 Message-Id: <20230204050954.11583-2-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: 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 --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8a5c25c20d00..b939dc482145 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18836,6 +18836,14 @@ F: include/uapi/linux/selinux_netlink.h F: scripts/selinux/ F: security/selinux/ +TSEM SECURITY MODULE +M: Greg Wettstein +S: Supported +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 S: Maintained From patchwork Sat Feb 4 05:09:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128595 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BB36BC636D3 for ; Sat, 4 Feb 2023 05:33:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229987AbjBDFd2 (ORCPT ); Sat, 4 Feb 2023 00:33:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43612 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233357AbjBDFdZ (ORCPT ); Sat, 4 Feb 2023 00:33:25 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 95C481E2BF for ; Fri, 3 Feb 2023 21:33:20 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 31459u6w011617; Fri, 3 Feb 2023 23:09:56 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 31459uwa011615; Fri, 3 Feb 2023 23:09:56 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 02/14] Add TSEM specific documentation. Date: Fri, 3 Feb 2023 23:09:42 -0600 Message-Id: <20230204050954.11583-3-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: 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_mode command-line parameter. 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 --- Documentation/ABI/testing/tsemfs | 576 ++++++++ Documentation/admin-guide/LSM/index.rst | 1 + Documentation/admin-guide/LSM/tsem.rst | 1240 +++++++++++++++++ .../admin-guide/kernel-parameters.txt | 5 + 4 files changed, 1822 insertions(+) create mode 100644 Documentation/ABI/testing/tsemfs create mode 100644 Documentation/admin-guide/LSM/tsem.rst diff --git a/Documentation/ABI/testing/tsemfs b/Documentation/ABI/testing/tsemfs new file mode 100644 index 000000000000..3d326934624c --- /dev/null +++ b/Documentation/ABI/testing/tsemfs @@ -0,0 +1,576 @@ +What: /sys/fs/tsem +Date: November 2022 +Contact: Greg Wettstein +Description: + The /sys/fs/tsem directory contains files and one + directory that implement the control plane for the + Trusted Security Event Modeling (TSEM) LSM. + + The files in this directory, with the exception of the + aggregate file, when read, reflect the values for the + modeling domain/namespace that the process reading the + files is operating in. + +What: /sys/fs/tsem/aggregate +Date: November 2022 +Contact: Greg Wettstein +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 extension measurement of the Trusted + Platform Module PCR registers 0 through 8. + +What: /sys/fs/tsem/forensics +Date: November 2022 +Contact: Greg Wettstein +Description: + The forensics file contains the descriptions of + security events that are inconsistent with the + security model that the domain/namespace is running + under. Forensics events are generated after a + security model is 'sealed' and the events represent + security state points that have not already been + defined in the model. + + The format of lines in this file are identical to the + output generated by the /sys/fs/tsem/trajectory file + that is documented below. + +What: /sys/fs/tsem/id +Date: November 2022 +Contact: Greg Wettstein +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 domain/namespace has a value of zero, with a + non-zero value representing a modeling domain + independent from the root model. + + A domain with a non-zero id value, that is externally + modeled. Each externally modeled domain will have a + file created in the /sys/fs/tsem/ExternalTMA directory + that is documented at the end of this document. + +What: /sys/fs/tsem/measurement +Date: November 2022 +Contact: Greg Wettstein +Description: + The measurement file contains the ASCII base 16 + hexadecimal representation of the 256 bit measurement + value of the security model that the process is + operating in. + + The measurement value is the classic linear extension + measurement of the model. An updated measurement + value is created by extending the current measurement + value with the state coefficient computed for a + security event. + + This measurement value represents a time dependent + measurement of a model and is susceptible to + deviations caused by scheduling differences between + subsequent invocations of a workload. + +What: /sys/fs/tsem/points +Date: November 2022 +Contact: Greg Wettstein +Description: + The points file contains the ASCII base 16 + representation of the 256 bit security state points of + a security domain/model. The number of entries in + this file represent the number of security events that + are represented by the model. + +What: /sys/fs/tsem/state +Date: November 2022 +Contact: Greg Wettstein +Description: + The state file contains the ASCII base 16 + representation of the 256 bit value of the functional + state of a security domain/model. + + The state value is a time independent representation + of the measurement of a model/domain, and unlike the + measurement value, is a time independent + representation of the security state of a workload. + + 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: /sys/fs/tsem/trajectory +Date: November 2022 +Contact: Greg Wettstein +Description: + The trajectory file contains a description of the + security events that have occurred in a security + domain/model. + + Each entry in this file represents a single security + event and consists of brace {} delimited fields that + describe the characteristics of a security event. + Each field has key=value pairs that define + characteristics of the field. + + Each line in a trajectory, or forensics, file will + always have the event{} and COE{} fields. The event + field describes the characteristics of a security + event while the COE field describes the Context Of + Execution that is executing the security event. + + The event{} field consists of the following + characteristic definitions: + + process=COMM + Where COMM is the ASCII representation + of the name of the process executing + the event. + + filename=PATH + If the CELL definition for an event + references a file the filename + characteristic contains a definition + of the path to the file. + + In the case where an event does not + have a file the PATH value is set to a + value of none. + + type=EVENT_TYPE + The value field for a type key is the + name of the security event that is + being modeled. The list of value + 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{} field. + + task_id=TASK_ID + The value of the task_id key will the + ASCII base 16 representation of the + model identity of the task that is + executing the security event. + + The following documentation file: + + Documentation/admin-guide/LSM/TSEM.rst + + Describes how the TASK_ID value is + generated. + + The COE{} field consists of the following + characteristic definitions: + + 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. + + cap=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{} event field 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 the + mmap_file{} event description 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 the + socket_create{} event description will be included + with the following characteristics: + + family=N + Where N is the ASCII base 10 + representation of the family of the + socket that is being created. + + type=N + Where N is the ASCII base 10 + representation of the type of the + socket being created. + + protocol=N + Where N is the ASCII base 10 + representation of the socket protocol. + + kern=N + Where N is an ASCII 0 or 1 that is + used to represent whether or not this + is a kernel base socket. A value of 1 + indicates a kernel based socket. + + If the event type is a socket creation event the + socket_create{} event description will be included + with the following characteristics: + + If the event type is a socket_connect or a socket_bind, + a socket_connect{} or a socket_bind{} field will be + included that will be characterized based on an + encoding of either an IPV4, IPV6 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 | 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 case 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 any other type of + socket the addr value will be the + ASCII base 16 representation of the + SHA256 checksum over the entire length + of the address description. + + 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{} + field will be included 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 | 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 case 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 any other type of + socket the addr value will be the + ASCII base 16 representation of the + SHA256 checksum over the entire length + of the address description. + +What: /sys/fs/tsem/ExternalTMA +Date: November 2022 +Contact: Greg Wettstein +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 domains/namespaces. + + The files created in this directory will be named by + the base 10 ASCII representation of the id value + assigned to the modeling domain/namespace. See the + documentation for the /sys/fs/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 orchestration implementation to + process security events that are to be modeled by + an external Trusted Modeling Agent. + + The type of the exported event is the first keyword of + the line that is output and have the following + values and arguments: + + aggregate HEXID: + Where HEXID is the ASCII base 16 + representation of the 256 bit hardware + platform aggregate value. + + export pid{NNN} COE{} CELL_DEFINITION + Where the NNN in the pid field is the ASCII + base 10 value of the id of the process that is + executing the security event that will be + modeled. + + The COE field has the same format as the field + emitted for a trajectory or forensics event. + + The CELL_DEFINITION are the same field + definitions that are emitted for a trajectory + or forensics event. + + log process{name} event{type} action{type} + The log event is emitted when an untrusted + task attempts to execute a security event. + + The name value of the COE field is the name of + the process (comm value) that is executing the + security event. + + The type value of the event field is the name + of the security event being executed as + defined in the tsem_names array in the + security/tsem/tsem.c file. + + The type value of the action field is the type + of action the LSM enforced in response to + encountering the untrusted process. This + value will be either LOG or EPERM to represent + whether or not the trust violation is being + logged or enforced. + +What: /sys/fs/tsem/control +Date: November 2022 +Contact: Greg Wettstein +Description: + The control file is the only writable file in the + filesystem and is used by the trust orchestrators 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. + + 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 + that does not map into the current set of + allowed state points for the security model + being implemented for the domain/namespace. + + seal: + The seal keyword causes the security model + being implemented for the model to be placed + in sealed state. In this state the current + set of security event points is considered to + be the only set of valid points for the + domain/model. Any subsequent events that map + to a point not in the current model will be + considered a violation of the model. + + trusted PID: + 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. + + untrusted PID: + The untrusted keyword is used by a trust + orchestrator to indicate that the process + identified by the PID argument should be + allowed to run but designated as an untrusted + process. + + state HEXID: + The state keyword is used to indicate that the + security state point identified by the ASCII + base 16 encoded value should be loaded into + the current security model as a valid security + event state. + + pseudonym HEXID + The pseudonym keyword is used to indicate that + the pathname, identified by the 256 bit ASCII + base 16 encoded value HEXID, should be + designated to return a constant digest value + for the contents of the file. + + The HEXID value is computed with the following + function: + + HEXID = SHA256(PATHNAME_LENGTH || PATHNAME) + + base HEXID + The base keyword is used to indicate that the + 256 bit ASCII base 16 encoded value HEXID + should be registered as the value used to + generate model specific security event points. + + 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. 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..f03e5269cd25 --- /dev/null +++ b/Documentation/admin-guide/LSM/tsem.rst @@ -0,0 +1,1240 @@ +==== +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. Conceptually it +can be thought of as an integration of system integrity measurement +and mandatory access controls. + +The design and implementation of TSEM was 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 remotely attestable platforms and/or +workloads. + +To achieve these objectives, TSEM implements the concept of a modeling +domain, nee namespace, that reduces the complexity of a security model +and allows it to be scoped to the level of a single process 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 +modeling domains/namespaces in a known trust state. + +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. Integrity modeling of +extended attributes would require that TSEM be earlier in the LSM call +chain then any LSM's that consume the modeled attributes. + +In addition, 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. + +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 + +The trust orchestrators need to have access to the TSEM management +filesystem, that after boot, can be mounted with the following +command: + +mount -t tsemfs tsemfs /sys/fs/tsem + +For experimentation, or integrating TSEM modeling into a CI +development workflow, modeling can be restricted to subordinate +modeling domains by booting a kernel with the following kernel +command-line option: + +tsem_mode=1 + +The Quixote trust orchestration utilities either need to be built or +the statically compiled demonstration system needs 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 +modeling domain/namespace with the security 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 domain/namespace in a userspace +process rather than in the kernel based 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 process. In these systems, the root or +administrative user has no ability to affect the 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 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 continuous integration testing. + +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 points in an access vector matrix that a process hierarchy +(workload) references. 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 point. These subordinate identities are referred to as the +Context Of Execution (COE) and the CELL, which are conceptually +similar to the subject and objects 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. Different security policies 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 +modeling domain and can be conceptualized as a mandatory access +control or integrity namespace. + +The formation of the security event state points 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 +engine, becomes the bearer's token for the security of the modeling +target, 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 +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 policy 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 domains, enforcing a workload +specific security model. Each trust orchestrator is paired with a +'trusted partner TMA', that implements the workload specific modeling +algorithm. + +The root of trust for a workload modeling domain 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 domains +being referred to as internally or externally modeled. A TMA +implementation run in the kernel is referred to as an internally +modeled domain; TMA's run outside of the kernel are referred to as +externally modeled domains. + +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 event state point. With respect to modeling theory, the +security event state point is a task specific coefficient 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 state points, is driven by the security +model/policy that will be implemented for the workload. It is +assumed, that security model algorithms will embrace various +approximations, and perhaps even stochastic reasoning and machine +learning methods, as new security models are developed in response to +specific workload, platform and device requirements. + +A security model, to be enforced by a trust orchestrator, is +implemented by providing the TMA with a set of security state points +that are to be observed. A TMA processes the characteristics of a +security event and converts the characteristics to a state point that +is evaluated against the state points provided to the TMA as the +reference security behavior of a workload. + +A security event that translates to one of the provided 'good' points, +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 point, results in the trust +orchestrator designating that the process be run 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 trusted security systems +against offline attacks. + +The use of a cryptographic hash function to generate the security +state points 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 +security state point 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 +point 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 +events, that do not map into a known security state point, are to be +considered 'forensic' violations to the security state of the model. +A forensics mapping event does not cause the initiating process to be +placed in untrusted mode; it 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. + +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 a violating process being placed in untrusted status. The +characteristics of the violating event will be registered in the +forensics trajectory for the model for use in subsequent evaluation of +the violating event and/or model refinement. + +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 point. + +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 model domains have the hardware aggregate measurement +included as the first state point in the security model. Externally +modeled domains export the hardware aggregate value to the TMA for +inclusion as the first state point of the model maintained by the TMA. + +The root modeling domain extends each security state point into PCR +11. This allows hardware based TSEM measurements to coexist with IMA +measurement values. This hardware measurement value can be used to +attest to the security execution trajectory that the root model +maintains. + +TSEM operates under the assumption that the root domain will be a +minimum Trusted Computing Base implementation that will only be +running trust orchestrators. Subordinate modeling domains are +designed, deliberately, to be non-hierarchical, so as to decrease +model complexity in the subordinate domains in order to support a +single functional value describing the security state of a security +domain. + +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 domains 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 domains. + +On the theory that security event handlers represent all of the +security relevant 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 points. + +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 domain is created, a designation is made as to +whether the domain is to be internally or externally modeled. + +In an internally modeled domain, 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 domain, 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. + +This model poses a limitation to the ability of TSEM to model some +security events. This is secondary to the fact that some event +handlers (LSM hooks) are called from a non-sleeping context, as a +result the process cannot be scheduled. This is particularly the case +with the task based hooks, since they are typically called with the +tasklist lock held. + +This limitation is also inherent to the root model that extends the +security state points into TPM PCR 11, secondary to the fact that the +process invoking the security event hook will be scheduled away while +the TPM transaction completes. + +Addressing this problem directly requires a consideration of the +context from which the security event handlers are being called. +Subsequent implementations of TSEM will include a mechanism for +asynchronous deferral of model processing, until when and if, a review +of the call context would be considered worthwhile by the LSM +community. + +Event handlers that cannot be directly modeled, still consider, on +entry, whether or not they are being called by an trusted or untrusted +process. As a result, an untrusted process will cause a non-modeled +event to return a permissions violation in enforcing mode, even if the +security event cannot be directly modeled. + +Security event modeling typically traps violations of trust by a COE +with unmodeled characteristics that is attempting to access/execute a +file or map memory as executable; or by a COE with known +characteristics attempting to access or execute a CELL not prescribed +by a model. As a result, the impact of the ability to not directly +model these events is lessened. + +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 point for the event. +The inclusion of the 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 code maturity reasons, some events to +be generically modeled. For these events, in addition to the COE +characteristics and task identity, a default CELL value is used in the +computation of the security state point. + +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. + +In the following ABI document: + +Documentation/ABI/testing/tsemfs + +The /sys/fs/tsem/trajectory entry documents parameters that are +available for modeling by both internally and externally modeled +domains. + +Event modeling +-------------- + +TSEM security event modeling is based on the following functional +definition for a security state point: + +Sp = SHA256(SHA256(EVENT_ID) || TASK_ID || SHA256(COE) || SHA256(CELL)) + + Where: + || = Concatenation operator. + + EVENT_ID = ASCII name of event. + + TASK_ID = 256 bit identity of the process executing + the security event. + + COE = Characteristics of the context of execution + of the event. + + CELL = Characteristics of the object that the + security event is acting on. + +Workload or platform specific security point state definitions are +implemented by a TMA using whatever COE or CELL characteristics that +are considered relevant in determining whether or not a process should +be considered trusted or untrusted. + +The TASK_ID component of the function above is important with respect +to the generation of the security state points. The notion of a task +identity serves to link the concepts of system integrity and mandatory +access control. + +The TASK_ID is defined by the following function: + +TASK_ID = SHA256(SHA256(EVENT) || NULL_ID || SHA256(COE) || SHA256(CELL)) + + Where: + || = Concatenation operator. + + EVENT = The string "bprm_set_creds". + + NULL_ID = A buffer contain 32 null bytes (0x00). + + 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 hook. + +An informed reader will quickly conclude, correctly, that the TASK_ID +function generates an executable specific security state point for the +bprm_creds_for_exec security hook. The function is the same as the +standard security point; with the exception that the task identity is +replaced with a 'null id', one that consists of 32 null bytes. + +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 points. + +The task identity is saved in the TSEM specific task structure and is +used to compute the state points 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 +points results in the points becoming executable specific. This +affords a very 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 point in the model. + +Since the modeling operates at the level of mandatory access controls, +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: + || = Concatenation operator. + + MEASUREMENT = The new measurement value to be maintained + in the register for the system. + + CURRENT = The current measurement value. + + NEW = A new measurement value to be added to + the current measurement. + + HASH = A cryptographic hash function. + +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 domain is the sum +of the security state points generated by the operative security model +being enforced. As previously noted, on systems with a TPM, the root +modeling domain measurement is maintained in PCR 11. + +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 and +standard kernel task scheduling 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 it is security appropriate. + +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 all the set of security model state points 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 point 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 is is implementing, this based 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 state point +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 domain management +and the internal TMA implementation, are controlled by the tsemfs +pseudo-filesystem, that uses the following mount point: + +/sys/fs/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 +and must be mounted in order for orchestrators to create and manage +security modeling domains. + +The following files grouped below by generic functionality, are +presented in the filesystem: + + control + + id + aggregate + + measurement + state + points + trajectory + forensics + +The /sys/fs/tsem directory contains the following sub-directory: + + ExternalTMA + +That is used to hold files that will be used to export security event +descriptions for externally modeled domains. + +The files are process context sensitive. Writing to the control file +or reading from the informational files, will act on or reference the +security domain that the access process is assigned to. + +The TSEM implementation at large is controlled by the only writable +file, which is the 'control' file. + +The following keywords are used by trust orchestrators to create +internally or externally modeled security domains for the writing +process: + + internal + external + +The following keywords are used by trust orchestrators to set the +trust status of a process after processing of a security event by an +external TMA: + + trusted PID + untrusted PID + + Where PID is the process identifier that is provided to the + TMA in the security event description + +By default a modeling domain 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 domain: + + state HEXID + + Where HEXID is the ASCII base 16 representation of a security + state point that is represents a valid security event in the + model. + + After writing a series of state values the trust orchestrator + would write 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. + +The following keyword and argument is used to set a base nonce for the +internal TMA: + + base 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 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 'id' file is used to determine the modeling domain that the +process is running in. The domain id value of 0 is reserved for the +root modeling domain, a non-zero value indicates that the process is +running in a subordinate modeling domain. + +The 'aggregate' file is used by trust orchestrators for internally +modeled domains to obtain the hardware measurement value. A trust +orchestrator for an internally modeled domain needs this value in +order to generate a platform specific security model for subsequent +enforcement. A trust orchestrator for an externally modeled domain +can capture this value since it is exported, through the trust +orchestrator, to the TMA. + +The remaining five files: measurement, state, points, trajectory and +forensics, are used to export the security model characteristics of +internally modeled domains. + +The 'measurement' file outputs the classic measurement value of the +modeling domain that the calling process is running in. This value is +the linear extension sum of the security state points in the model. + +The 'state' file outputs the security state measurement value as +described in the 'Security model functional definitions' section of +this document. + +The 'points' file outputs the set of security state points in the +model. These points represent both valid and invalid state points +generated by the security model implemented for the domain. + +The 'trajectory' file outputs the description of each security event +recorded by the model in time dependent form. + +The 'forensics' file outputs the description of security events that +have occurred when the domain security model is running in a sealed +state. + +The ABI documentation file contains a complete description of the +output that is generated by each of these files. + +A security model for an internally modeled domain is loaded by +writing the valid security points to the 'state' file in 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 point is added to the model. + +Since the state points 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. + +Trust orchestrators +=================== + +In security modeling, the need for a trust orchestrator system 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 modeling domain, the orchestrator is +responsible for executing and monitoring a process that is run in the +context of the domain. The trust orchestrator is also responsible for +providing access to the security model implemented by the TMA. + +Trust orchestrators for externally modeled domains, have an +associated TMA that is responsible for implementing the security model +for a domain. The TMA represents the the root of trust for the +modeled domain. The TMA advises the trust orchestrator as to what the +new trust status for a process should be set to, based on the modeling +of the security event that is 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_TRUST, that only the trust +orchestrators are designed to run with. + +The CAP_TRUST capability is defined as a capability that allows the +ability of it's holder to modify the trust state of the system. The +ability to create the proposed IMA namespaces would also be a +candidate for this capability. + +Trust orchestrators are designed to drop the CAP_TRUST 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 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 initial implementation of a system that embodies the +characteristics described above. While currently under development by +a small team, it provides all off the basic functionality needed to +demonstrate, and use, TSEM based security modeling. + +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 modeled environments. + +The source code for Quixote, and patches to the LTS kernels back to +5.4, 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 pre-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 domains. + +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 +modeling domain. 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 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 definition, 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 points 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 option, will cause the +loaded model to be enforced. Any forensic events will cause a +permission denial to be returned to the caller of the LSM hook. + +The Quixote package also includes a utility, quixote-console, for +interrogating the model state of a TMA. The following command-line +options request output of the following characteristics of the model: + +-E -> The log of denied events. + +-F -> The current forensics execution trajectory. + +-M -> The current security model description. + +-P -> The current security state points. + +-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 forensics + +show points + +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. + +For informative purposes the following security model definition +represents the execution and simple 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 package also contains utilities for generating signed +versions of these security models. In what is a nod to the politics +of trusted systems, the Quixote TMA implementations support +self-signed 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. + +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 is the NRF52840-DONGLE implementation. This is a +'USB fob' form factor board that GOOGLE uses as the basis for its +OpenSK security key implementation. This form factor allows the +development and experimentation with deployable hardware based TMA +implementations. + +The NRF52840-DONGLE architecture was also 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. diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 6cfa6e3996cf..a7dafcd932b4 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -6376,6 +6376,11 @@ with CPUID.16h support and partial CPUID.15h support. Format: + tsem_mode= [TSEM] Set the mode that the Trusted Security Event + Modeling LSM is to run in. + Format: 1 + 1 -- Disable root domain modeling. + tsx= [X86] Control Transactional Synchronization Extensions (TSX) feature in Intel processors that support TSX control. From patchwork Sat Feb 4 05:09:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128581 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F0851C636CD for ; Sat, 4 Feb 2023 05:32:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229657AbjBDFck (ORCPT ); Sat, 4 Feb 2023 00:32:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43092 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232601AbjBDFcj (ORCPT ); Sat, 4 Feb 2023 00:32:39 -0500 X-Greylist: delayed 1349 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Fri, 03 Feb 2023 21:32:38 PST Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9E0A992EED for ; Fri, 3 Feb 2023 21:32:38 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 31459vdj011622; Fri, 3 Feb 2023 23:09:57 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 31459vrE011620; Fri, 3 Feb 2023 23:09:57 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 03/14] Add magic number for tsemfs. Date: Fri, 3 Feb 2023 23:09:43 -0600 Message-Id: <20230204050954.11583-4-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: Signed-off-by: Greg Wettstein --- include/uapi/linux/magic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 6325d1d0e90f..6a6a2b70c529 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -95,6 +95,7 @@ #define BPF_FS_MAGIC 0xcafe4a11 #define AAFS_MAGIC 0x5a3c69f0 #define ZONEFS_MAGIC 0x5a4f4653 +#define TSEMFS_MAGIC 0x11242022 /* Since UDF 2.01 is ISO 13346 based... */ #define UDF_SUPER_MAGIC 0x15013346 From patchwork Sat Feb 4 05:09:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128583 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 793D2C636CD for ; Sat, 4 Feb 2023 05:32:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232929AbjBDFcm (ORCPT ); Sat, 4 Feb 2023 00:32:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232601AbjBDFcm (ORCPT ); Sat, 4 Feb 2023 00:32:42 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 83A9092ED5 for ; Fri, 3 Feb 2023 21:32:41 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 31459wnJ011627; Fri, 3 Feb 2023 23:09:58 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 31459wqT011625; Fri, 3 Feb 2023 23:09:58 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 04/14] Implement CAP_TRUST capability. Date: Fri, 3 Feb 2023 23:09:44 -0600 Message-Id: <20230204050954.11583-5-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: 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 privileged assets on the platform. Introduce the CAP_TRUST capability that is defined as a capability that allows a process to alter the trust status of the platform. In a fully trust orchestrated system only the orchestrators carry this capability bit. In TSEM the CAP_TRUST capability allows the holder to access the control plane of the LSM. This ability allows subordinate modeling domains to be created and managed. Most principally the CAP_TRUST capability allows the holder to designate whether or not a process should be trusted or untrusted. The proposed Integrity Measurement Architecture namespaces would also be a candidate to use the CAP_TRUST capability. Signed-off-by: Greg Wettstein --- 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..af677b534949 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_TRUST 41 + +#define CAP_LAST_CAP CAP_TRUST #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..e8c497c16271 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_TRUST #error New capability defined, please update COMMON_CAP2_PERMS. #endif From patchwork Sat Feb 4 05:09:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128588 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CC109C636D6 for ; Sat, 4 Feb 2023 05:32:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233146AbjBDFc4 (ORCPT ); Sat, 4 Feb 2023 00:32:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43270 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231654AbjBDFcw (ORCPT ); Sat, 4 Feb 2023 00:32:52 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id E6C9693E22 for ; Fri, 3 Feb 2023 21:32:50 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 31459w6C011632; Fri, 3 Feb 2023 23:09:58 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 31459w6r011630; Fri, 3 Feb 2023 23:09:58 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 05/14] Add TSEM master header file. Date: Fri, 3 Feb 2023 23:09:45 -0600 Message-Id: <20230204050954.11583-6-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: 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 the TSEM LSM implementation. Signed-off-by: Greg Wettstein --- security/tsem/tsem.h | 388 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 388 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..2d81a17e655a --- /dev/null +++ b/security/tsem/tsem.h @@ -0,0 +1,388 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * Copyright (C) 2022 Enjellic Systems Development, LLC + * Author: Dr. Greg Wettstein + * + * TSEM specific includes. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define TSEM_CONTROL_CAPABILITY CAP_TRUST + +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 { + TSEM_ACTION_LOG = 0, + TSEM_ACTION_EPERM, + TSEM_ACTION_CNT +}; + +enum tsem_control_type { + TSEM_CONTROL_INTERNAL = 1, + 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_task_trust { + TSEM_TASK_TRUSTED = 1, + TSEM_TASK_UNTRUSTED = 2, + TSEM_TASK_TRUST_PENDING = 4 +}; + +enum tsem_inode_state { + TSEM_INODE_COLLECTING = 1, + TSEM_INODE_COLLECTED +}; + +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; + } capability; +}; + +struct tsem_file { + uid_t uid; + gid_t gid; + umode_t mode; + u32 flags; + + u32 name_length; + u8 name[WP256_DIGEST_SIZE]; + + u32 s_magic; + u8 s_id[32]; + u8 s_uuid[16]; + + u8 digest[WP256_DIGEST_SIZE]; +}; + +struct tsem_event_point { + struct list_head list; + u8 point[WP256_DIGEST_SIZE]; + bool valid; +}; + +struct tsem_mmap_file_args { + struct file *file; + u32 anonymous; + u32 reqprot; + u32 prot; + u32 flags; +}; + +struct tsem_socket_create_args { + int family; + int type; + int protocol; + int kern; +}; + +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; + u8 mapping[WP256_DIGEST_SIZE]; + } u; +}; + +struct tsem_socket_accept_args { + struct tsem_inode *tsip; + u16 family; + u16 type; + __be16 port; + __be32 ipv4; + struct in6_addr ipv6; +}; + +struct tsem_task_kill_args { + u32 cross_model; + u32 signal; + u8 target[WP256_DIGEST_SIZE]; +}; + +struct tsem_event { + struct kref kref; + enum tsem_event_type event; + pid_t pid; + char *pathname; + char comm[TASK_COMM_LEN]; + u8 task_id[WP256_DIGEST_SIZE]; + u8 mapping[WP256_DIGEST_SIZE]; + 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 { + 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_trajectory { + struct list_head list; + struct tsem_event *ep; +}; + +struct tsem_model { + bool have_aggregate; + u8 base[WP256_DIGEST_SIZE]; + u8 measurement[WP256_DIGEST_SIZE]; + u8 state[WP256_DIGEST_SIZE]; + + unsigned int point_count; + struct mutex point_mutex; + struct list_head point_list; + struct list_head state_list; + + unsigned int trajectory_count; + struct mutex trajectory_mutex; + struct list_head trajectory_list; + + unsigned int forensics_count; + unsigned int max_forensics_count; + struct mutex forensics_mutex; + struct list_head forensics_list; + + struct mutex pseudonym_mutex; + struct list_head pseudonym_list; +}; + +struct tsem_external { + char *filename; + struct mutex measurement_mutex; + struct list_head measurement_list; + struct dentry *dentry; + bool have_event; + wait_queue_head_t wq; +}; + +struct tsem_TMA_work { + struct work_struct work; + struct tsem_TMA_context *ctx; +}; + +struct tsem_TMA_context { + struct kref kref; + struct tsem_TMA_work work; + u64 id; + bool sealed; + enum tsem_action_type actions[TSEM_EVENT_CNT]; + struct tsem_model *model; + struct tsem_external *external; +}; + +struct tsem_task { + int trust_status; + u8 task_id[WP256_DIGEST_SIZE]; + struct tsem_TMA_context *context; +}; + +struct tsem_inode { + enum tsem_inode_state status; + u64 version; + u8 digest[WP256_DIGEST_SIZE]; + struct mutex mutex; +}; + +extern struct lsm_blob_sizes tsem_blob_sizes; +extern enum tsem_action_type tsem_root_actions[TSEM_EVENT_CNT]; +extern struct tsem_TMA_context root_TMA_context; +extern const char * const tsem_names[TSEM_EVENT_CNT]; + +extern int tsem_fs_init(void); +extern struct dentry *tsem_fs_create_external(const char *name); +extern void tsem_fs_remove_external(struct dentry *dentry); + +extern struct tsem_model *tsem_model_allocate(void); +extern void tsem_model_free(struct tsem_TMA_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, u8 *mapping); +extern void tsem_model_load_base(u8 *mapping); +extern int tsem_model_add_aggregate(void); +extern void tsem_model_compute_state(void); + +extern int tsem_ns_init(void); +extern int tsem_ns_create(enum tsem_control_type type); +extern void tsem_ns_put(struct tsem_TMA_context *ctx); +extern void tsem_ns_get(struct tsem_TMA_context *ctx); + +extern int tsem_export_show(struct seq_file *m); +extern int tsem_export_event(struct tsem_event *ep); +extern int tsem_export_action(enum tsem_event_type event); +extern int tsem_export_aggregate(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); + +extern struct tsem_event *tsem_event_allocate(enum tsem_event_type event, + struct tsem_event_parameters *params); +extern void tsem_event_put(struct tsem_event *ep); +extern void tsem_event_get(struct tsem_event *ep); +extern int tsem_event_cache_init(void); + +extern u8 *tsem_trust_aggregate(void); +extern int tsem_trust_add_event(u8 *coefficient); + +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_TMA_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; +} From patchwork Sat Feb 4 05:09:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128594 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4E6E5C636CD for ; Sat, 4 Feb 2023 05:33:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232957AbjBDFd1 (ORCPT ); Sat, 4 Feb 2023 00:33:27 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43666 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233025AbjBDFdT (ORCPT ); Sat, 4 Feb 2023 00:33:19 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 60BA883F8 for ; Fri, 3 Feb 2023 21:33:14 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 31459xuA011637; Fri, 3 Feb 2023 23:09:59 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 31459xcc011635; Fri, 3 Feb 2023 23:09:59 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 06/14] Add primary TSEM implementation file. Date: Fri, 3 Feb 2023 23:09:46 -0600 Message-Id: <20230204050954.11583-7-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: The tsem.c file is the 'master' file in the TSEM implementation. It is responsible for initializing the LSM and providing implement of the security event hooks. In addition to initializing the LSM, the set_ready() function implements a secondary initialization that is used to a statically scoped variable that indicates 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 the tsem_mode kernel command-line option. If tsem_mode is set to a value of 1 the TSEM driver does not model any events from the root domain. This is intended to allow development platforms to develop security models without the overhead of full platform modeling. 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 tsemfs filesystem or for export to external trust orchestrators. Signed-off-by: Greg Wettstein --- security/tsem/tsem.c | 1801 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1801 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..fac40c70a474 --- /dev/null +++ b/security/tsem/tsem.c @@ -0,0 +1,1801 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2022 Enjellic Systems Development, LLC + * Author: Dr. Greg Wettstein + * + * TSEM initialization infrastructure. + */ + +#define TRAPPED_MSG_LENGTH 128 + +#include +#include +#include +#include +#include + +#include "tsem.h" + +static int tsem_ready __lsm_ro_after_init; + +static bool no_root_modeling __lsm_ro_after_init; + +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); + +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, + TSEMFS_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_TMA_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; +} + +int return_trapped_task(enum tsem_event_type event, char *msg) +{ + int retn; + struct tsem_TMA_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); + 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) +{ + 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); +} + +static int model_event(struct tsem_event *ep) +{ + int retn; + struct tsem_TMA_context *ctx = tsem_context(current); + + if (!ctx->id && no_root_modeling) + return 0; + + if (!ctx->external) { + retn = tsem_model_event(ep); + if (retn) + return retn; + goto done; + } + + retn = tsem_export_event(ep); + if (retn) + return retn; + + done: + return event_action(ctx, ep->event); +} + +static int model_generic_event(enum tsem_event_type event) +{ + 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; + ep = tsem_map_event(TSEM_GENERIC_EVENT, ¶ms); + if (IS_ERR(ep)) { + retn = PTR_ERR(ep); + goto done; + } + + retn = model_event(ep); + tsem_event_put(ep); + + done: + return retn; +} + +static int model_generic_event_locked(enum tsem_event_type event) +{ + return 0; +} + +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 (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); + } + + 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, ¶ms); + 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 (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); + } + + 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, ¶ms); + 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); + } + + if (bypass_inode(file_inode(file))) + return 0; + + return model_generic_event(TSEM_FILE_IOCTL); +} + +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); + } + + return model_generic_event(TSEM_FILE_LOCK); +} + +static int tsem_file_fcntl(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_FCNTL, msg); + } + + if (bypass_inode(file_inode(file))) + return 0; + + return model_generic_event(TSEM_FILE_FCNTL); +} + +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); + } + + return model_generic_event(TSEM_FILE_RECEIVE); +} + +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; + if (!new_task->context->id) + return 0; + + if (new_task->context->id) + tsem_ns_get(new_task->context); + return 0; +} + +static void tsem_task_free(struct task_struct *task) +{ + struct tsem_TMA_context *ctx = tsem_context(task); + + if (!ctx->id) + return; + if (ctx->id) + tsem_ns_put(ctx); +} + +static int tsem_task_kill(struct task_struct *target, + struct kernel_siginfo *info, int sig, + const struct cred *cred) +{ + int retn = 0; + char msg[TRAPPED_MSG_LENGTH]; + struct tsem_TMA_context *src_ctx = tsem_context(current); + struct tsem_TMA_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); + } + + if (SI_FROMKERNEL(info)) + return retn; + if (capable(CAP_TRUST)) + return retn; + if (has_capability_noaudit(target, CAP_TRUST)) + return -EPERM; + if (src_ctx->id != tgt_ctx->id) + return -EPERM; + if (sig == SIGURG) + return 0; + + return model_generic_event_locked(TSEM_TASK_KILL); +} + +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); + } + + return model_generic_event(TSEM_PTRACE_TRACEME); +} + +/* + * The best that can be done with respect to modeling this security + * event is to trap an attempt by an untrusted task to exercise the + * functionality. This is secondary to the fact that the invocation + * point for this hook holds the global tasklist lock, causing both + * internal and external modeling to deadlock, given that both methods + * can cause current task to be scheduled away. + */ +static int tsem_task_setpgid(struct task_struct *p, pid_t pgid) +{ + char msg[TRAPPED_MSG_LENGTH]; + struct tsem_TMA_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_locked(TSEM_TASK_SETPGID); +} + +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); + } + + return model_generic_event(TSEM_TASK_GETPGID); +} + +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); + } + + return model_generic_event(TSEM_TASK_GETSID); +} + +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); + } + + return model_generic_event(TSEM_TASK_SETNICE); +} + +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); + } + + return model_generic_event(TSEM_TASK_SETIOPRIO); +} + +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); + } + + return model_generic_event(TSEM_TASK_GETIOPRIO); +} + +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); + } + + return model_generic_event_locked(TSEM_TASK_PRLIMIT); +} + +/* + * See the comment above tsem_task_setrlimit for possible issues. + * Currently this security event hook has been tested safe but + * consideration should be given to global tasklist locking. + */ +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); + } + + return model_generic_event_locked(TSEM_TASK_SETRLIMIT); +} + +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); + } + + return model_generic_event_locked(TSEM_TASK_SETSCHEDULER); +} + +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); + } + + return model_generic_event_locked(TSEM_TASK_GETSCHEDULER); +} + +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); + } + + return model_generic_event_locked(TSEM_TASK_PRCTL); +} + +static int tsem_bprm_creds_for_exec(struct linux_binprm *bprm) +{ + struct tsem_task *task = tsem_task(current); + + 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); + return 0; +} + +#ifdef CONFIG_SECURITY_NETWORK +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); + } + + return model_generic_event_locked(TSEM_UNIX_STREAM_CONNECT); +} + +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); + } + + return model_generic_event_locked(TSEM_UNIX_MAY_SEND); +} + +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); + } + + args.family = family; + args.type = type; + args.protocol = protocol; + args.kern = kern; + params.u.socket_create = &args; + + ep = tsem_map_event(TSEM_SOCKET_CREATE, ¶ms); + 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); + } + + 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, ¶ms); + 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); + } + + 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, ¶ms); + 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); + } + + args.tsip = tsem_inode(SOCK_INODE(sock)); + args.family = sk->sk_family; + args.type = sock->type; + args.port = sk->sk_num; + args.ipv4 = sk->sk_rcv_saddr; + ipv6 = inet6_rcv_saddr(sk); + if (ipv6) + args.ipv6 = *ipv6; + params.u.socket_accept = &args; + + ep = tsem_map_event(TSEM_SOCKET_ACCEPT, ¶ms); + 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); + } + + return model_generic_event(TSEM_SOCKET_LISTEN); +} + +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); + } + + return model_generic_event(TSEM_SOCKET_SOCKETPAIR); +} + +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); + } + + return model_generic_event(TSEM_SOCKET_SENDMSG); +} + +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); + } + + return model_generic_event(TSEM_SOCKET_RECVMSG); +} + +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); + } + + return model_generic_event(TSEM_SOCKET_GETSOCKNAME); +} + +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); + } + + return model_generic_event(TSEM_SOCKET_GETPEERNAME); +} + +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); + } + + return model_generic_event(TSEM_SOCKET_SETSOCKOPT); +} + +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); + } + + return model_generic_event(TSEM_SOCKET_SHUTDOWN); +} +#endif + +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); + } + + return model_generic_event(TSEM_KERNEL_MODULE_REQUEST); +} + +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); + } + + return model_generic_event(TSEM_KERNEL_LOAD_DATA); +} + +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); + } + + return model_generic_event(TSEM_KERNEL_READ_FILE); +} + +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); + } + + return model_generic_event(TSEM_SB_MOUNT); +} + +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); + } + + return model_generic_event(TSEM_SB_UMOUNT); +} + +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); + } + + return model_generic_event(TSEM_SB_REMOUNT); +} + +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); + } + + return model_generic_event(TSEM_SB_PIVOTROOT); +} + +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); + } + + return model_generic_event(TSEM_SB_STATFS); +} + +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); + } + + return model_generic_event(TSEM_MOVE_MOUNT); +} + +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); + } + + return model_generic_event(TSEM_SHM_ASSOCIATE); +} + +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); + } + + return model_generic_event(TSEM_SHM_SHMCTL); +} + +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); + } + + return model_generic_event(TSEM_SHM_SHMAT); +} + +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); + } + + return model_generic_event(TSEM_SEM_ASSOCIATE); +} + +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); + } + + return model_generic_event(TSEM_SEM_SEMCTL); +} + +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); + } + + return model_generic_event(TSEM_SEM_SEMOP); +} + +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); + } + + return model_generic_event(TSEM_SYSLOG); +} + +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); + } + + return model_generic_event(TSEM_SETTIME); +} + +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); + } + + return model_generic_event(TSEM_QUOTACTL); +} + +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); + } + + return model_generic_event(TSEM_QUOTA_ON); +} + +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); + } + + return model_generic_event(TSEM_MSG_QUEUE_ASSOCIATE); +} + +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); + } + + return model_generic_event(TSEM_MSG_QUEUE_MSGSND); +} + +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); + } + + return model_generic_event(TSEM_MSG_QUEUE_MSGCTL); +} + +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_MSGSND, msg); + } + + return model_generic_event(TSEM_MSG_QUEUE_MSGSND); +} + +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); + } + + return model_generic_event(TSEM_IPC_PERMISSION); +} + +#ifdef CONFIG_KEYS +static int tsem_key_alloc(struct key *key, const struct cred *cred, + unsigned long flags) +{ + char msg[TRAPPED_MSG_LENGTH]; + + 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); + } + + return model_generic_event(TSEM_KEY_ALLOC); +} + +static int tsem_key_permission(key_ref_t key_ref, const struct cred *cred, + unsigned int perm) +{ + char msg[TRAPPED_MSG_LENGTH]; + + 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); + } + + return model_generic_event_locked(TSEM_KEY_PERMISSION); +} +#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_KEY_PERMISSION, msg); + } + + return model_generic_event(TSEM_KEY_PERMISSION); +} + +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); + } + + if (bypass_inode(dir)) + return 0; + return model_generic_event(TSEM_INODE_CREATE); +} + +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); + } + + if (bypass_inode(dir)) + return 0; + return model_generic_event(TSEM_INODE_LINK); +} + +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); + } + + if (bypass_inode(dir)) + return 0; + return model_generic_event(TSEM_INODE_UNLINK); +} + +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_UNLINK, msg); + } + + if (bypass_inode(dir)) + return 0; + return model_generic_event(TSEM_INODE_UNLINK); +} + +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); + } + + if (bypass_inode(dir)) + return 0; + return model_generic_event(TSEM_INODE_MKDIR); +} + +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); + } + + if (bypass_inode(dir)) + return 0; + return model_generic_event(TSEM_INODE_RMDIR); +} + +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); + } + + if (bypass_inode(old_dir)) + return 0; + return model_generic_event(TSEM_INODE_RENAME); +} + +static int tsem_inode_mknod(struct inode *dir, struct dentry *dentry, + umode_t mode, dev_t dev) +{ + char msg[TRAPPED_MSG_LENGTH]; + + 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); + } + + return model_generic_event(TSEM_INODE_MKNOD); +} + +static int tsem_inode_setattr(struct dentry *dentry, struct iattr *attr) +{ + char msg[TRAPPED_MSG_LENGTH]; + + 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); + } + + return model_generic_event(TSEM_INODE_SETATTR); +} + +static int tsem_inode_getattr(const struct path *path) +{ + char msg[TRAPPED_MSG_LENGTH]; + + if (tsem_task_untrusted(current)) { + scnprintf(msg, sizeof(msg), "name=%s", + path->dentry->d_name.name); + return return_trapped_task(TSEM_INODE_GETATTR, msg); + } + + return model_generic_event(TSEM_INODE_GETATTR); +} + +static int tsem_inode_setxattr(struct user_namespace *mnt_userns, + 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); + } + + return model_generic_event(TSEM_INODE_SETXATTR); +} + +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); + } + + return model_generic_event(TSEM_INODE_GETXATTR); +} + +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); + } + + return model_generic_event(TSEM_INODE_LISTXATTR); +} + +static int tsem_inode_removexattr(struct user_namespace *mnt, + 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); + } + + return model_generic_event(TSEM_INODE_REMOVEXATTR); +} + +static int tsem_inode_killpriv(struct user_namespace *mnt_userns, + 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); + } + + return model_generic_event(TSEM_INODE_KILLPRIV); +} + +static int tsem_tun_dev_create(void) +{ + if (tsem_task_untrusted(current)) + return return_trapped_task(TSEM_TUN_DEV_CREATE, "none"); + + return model_generic_event(TSEM_TUN_DEV_CREATE); +} + +static int tsem_tun_dev_attach_queue(void *security) +{ + if (tsem_task_untrusted(current)) + return return_trapped_task(TSEM_TUN_DEV_ATTACH_QUEUE, "none"); + + return model_generic_event(TSEM_TUN_DEV_ATTACH_QUEUE); +} + +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); + } + + return model_generic_event(TSEM_TUN_DEV_ATTACH); +} + +static int tsem_tun_dev_open(void *security) +{ + if (tsem_task_untrusted(current)) + return return_trapped_task(TSEM_TUN_DEV_OPEN, "none"); + + return model_generic_event(TSEM_TUN_DEV_OPEN); +} + +#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); + } + + return model_generic_event(TSEM_BPF); +} + +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); + } + + return model_generic_event(TSEM_BPF_MAP); +} + +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); + } + + return model_generic_event(TSEM_BPF_PROG); +} +#endif + +static struct security_hook_list tsem_hooks[] __lsm_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(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), + +#ifdef CONFIG_SECURITY_NETWORK + 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), +#endif + + 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 __init set_ready(void) +{ + int retn; + + retn = tsem_model_add_aggregate(); + if (retn) + goto done; + + retn = tsem_fs_init(); + if (retn) + goto done; + + tsem_ready = 1; + + done: + return retn; +} + +fs_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); + + security_add_hooks(tsem_hooks, ARRAY_SIZE(tsem_hooks), "tsem"); + + tsk->context = &root_TMA_context; + memcpy(tsk->context->actions, tsem_root_actions, + sizeof(tsem_root_actions)); + + retn = tsem_event_cache_init(); + if (retn) + return retn; + + retn = tsem_ns_init(); + if (retn) + return retn; + + pr_info("tsem: Initialized %s modeling.\n", + no_root_modeling ? "domain only" : "full"); + tsk->trust_status = TSEM_TASK_TRUSTED; + return 0; +} + +DEFINE_LSM(tsem) = { + .name = "tsem", + .init = tsem_init, + .blobs = &tsem_blob_sizes, +}; From patchwork Sat Feb 4 05:09:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128585 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E24DDC636D3 for ; Sat, 4 Feb 2023 05:32:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232601AbjBDFct (ORCPT ); Sat, 4 Feb 2023 00:32:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43148 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232978AbjBDFcp (ORCPT ); Sat, 4 Feb 2023 00:32:45 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 1343A93AD0 for ; Fri, 3 Feb 2023 21:32:43 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 31459xIQ011642; Fri, 3 Feb 2023 23:09:59 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 31459xb4011640; Fri, 3 Feb 2023 23:09:59 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 07/14] Add root domain trust implementation. Date: Fri, 3 Feb 2023 23:09:47 -0600 Message-Id: <20230204050954.11583-8-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: The trust.c contains the support infrastructure for anchoring the root modeling domain in a hardware TPM implementation if it is available. The security event state points are extended 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 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 event state point injected into a model. Signed-off-by: Greg Wettstein --- security/tsem/trust.c | 134 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 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..77190c07f772 --- /dev/null +++ b/security/tsem/trust.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2022 Enjellic Systems Development, LLC + * Author: Dr. Greg Wettstein + * + * Implements management of a TPM trust root for the in kernel TMA. + */ + +#include +#include + +#include "tsem.h" + +#define TSEM_TRUST_ROOT 11 + +static u8 hardware_aggregate[WP256_DIGEST_SIZE]; + +static struct tpm_chip *tpm; + +static struct tpm_digest *digests; + + +void __init generate_aggregate(struct crypto_shash *tfm) +{ + int retn = 0, lp; + struct tpm_digest pcr; + u8 digest[WP256_DIGEST_SIZE]; + SHASH_DESC_ON_STACK(shash, tfm); + + shash->tfm = tfm; + retn = crypto_shash_init(shash); + if (retn) + 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 < 8; ++lp) { + retn = tpm_pcr_read(tpm, lp, &pcr); + if (retn) + goto done; + memcpy(digest, pcr.digest, sizeof(digest)); + retn = crypto_shash_update(shash, digest, WP256_DIGEST_SIZE); + if (retn) + goto done; + } + if (!retn) + retn = crypto_shash_final(shash, hardware_aggregate); + + done: + if (retn) + pr_info("Unable to generate platform aggregate\n"); +} + +static int __init trust_init(void) +{ + int retn = -EINVAL, lp; + struct crypto_shash *tfm = NULL; + + tpm = tpm_default_chip(); + if (!tpm) { + pr_info("No TPM found for event modeling.\n"); + return retn; + } + + 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; + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) + retn = PTR_ERR(tfm); + else { + generate_aggregate(tfm); + retn = 0; + } + crypto_free_shash(tfm); + + return retn; +} + +/** + * tsem_trust_aggregate() - Return a pointer to the hardware aggregate. + * + * This function returns a pointer to the hardware aggregate that + * is computed at system boot time. + * + * Return: A byte pointer is returned to the statically scoped array + * that contains the hardware aggregate value. + */ +u8 *tsem_trust_aggregate(void) +{ + return hardware_aggregate; +} + +/** + * tsem_trust_add_point() - Add a measurement to the trust root. + * @coefficient: A pointer to the event coefficient to be added. + * + * 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(u8 *coefficient) +{ + int amt, bank; + + if (!tpm) + return 0; + + for (bank = 0; bank < tpm->nr_allocated_banks; bank++) { + if (tpm->allocated_banks[bank].digest_size < WP256_DIGEST_SIZE) + amt = tpm->allocated_banks[bank].digest_size; + else + amt = WP256_DIGEST_SIZE; + memcpy(digests[bank].digest, coefficient, amt); + } + + return tpm_pcr_extend(tpm, TSEM_TRUST_ROOT, digests); +} + +late_initcall(trust_init); From patchwork Sat Feb 4 05:09:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128593 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 548DDC636D3 for ; Sat, 4 Feb 2023 05:33:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229449AbjBDFdR (ORCPT ); Sat, 4 Feb 2023 00:33:17 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43606 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233009AbjBDFdP (ORCPT ); Sat, 4 Feb 2023 00:33:15 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 6611E3C35 for ; Fri, 3 Feb 2023 21:33:09 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 3145A0h8011647; Fri, 3 Feb 2023 23:10:00 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 3145A008011645; Fri, 3 Feb 2023 23:10:00 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 08/14] Implement TSEM control plane. Date: Fri, 3 Feb 2023 23:09:48 -0600 Message-Id: <20230204050954.11583-9-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: The fs.c file contains the implementation of the TSEM control plane that is in the form of a pseudo-filesystem mounted on the following directory: /sys/fs/tsem The following file documents the interface provided by the control plane: Documentation/ABI/testing/tsemfs The pseudo-files act on the modeling context of the process that is acting on the file. For example, reading the 'id' pseudo-file, returns the modeling domain identifier that the process is running in. The ExternalTMA directory is used to segreate 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 '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. Signed-off-by: Greg Wettstein --- security/tsem/fs.c | 894 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 894 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..2898a1cc8c97 --- /dev/null +++ b/security/tsem/fs.c @@ -0,0 +1,894 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2022 Enjellic Systems Development, LLC + * Author: Dr. Greg Wettstein + * + * Implements the sysfs based control plane. + */ + +#include +#include +#include +#include +#include +#include + +#include "tsem.h" + +static int fs_init_context(struct fs_context *context); +static int fs_get_tree(struct fs_context *context); + +static struct file_system_type fs_definition = { + .name = "tsemfs", + .init_fs_context = fs_init_context, + .kill_sb = kill_litter_super +}; + +static struct fs_context_operations fs_operations = { + .get_tree = fs_get_tree +}; + +static struct vfsmount *fs_mount; + +static int fs_mount_cnt; + +static struct dentry *external_dentry; + +struct control_commands { + char *cmd; + enum tsem_control_type type; +}; + +static struct control_commands commands[9] = { + {"internal", TSEM_CONTROL_INTERNAL}, + {"external", TSEM_CONTROL_EXTERNAL}, + {"enforce", TSEM_CONTROL_ENFORCE}, + {"seal", TSEM_CONTROL_SEAL}, + {"trusted ", TSEM_CONTROL_TRUSTED}, + {"untrusted ", TSEM_CONTROL_UNTRUSTED}, + {"state ", TSEM_CONTROL_MAP_STATE}, + {"pseudonym ", TSEM_CONTROL_MAP_PSEUDONYM}, + {"base ", TSEM_CONTROL_MAP_BASE} +}; + +static bool can_access_fs(void) +{ + struct tsem_TMA_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(pid_t pid, unsigned long cmd) +{ + bool wakeup = false; + int retn = -ESRCH; + struct task_struct *COE; + struct tsem_task *task; + + rcu_read_lock(); + COE = find_task_by_vpid(pid); + if (COE != NULL) { + task = tsem_task(COE); + 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; + } + rcu_read_unlock(); + + if (wakeup) + wake_up_process(COE); + + return retn; +} + +static int config_context(unsigned long cmd, char *bufr) +{ + int retn = -EINVAL; + unsigned int lp; + struct tsem_TMA_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, u8 *arg) +{ + int retn = -EINVAL; + u8 mapping[WP256_DIGEST_SIZE]; + + if (*++arg == '\0') + goto done; + if (strlen(arg) != sizeof(mapping) * 2) + goto done; + if (hex2bin(mapping, arg, sizeof(mapping))) + 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 void show_event(struct seq_file *c, struct tsem_event *ep, char *file) +{ + seq_printf(c, "event{process=%s, filename=%s, type=%s, task_id=%*phN}", + ep->comm, file ? file : "none", tsem_names[ep->event], + WP256_DIGEST_SIZE, ep->task_id); + seq_printf(c, " COE{uid=%d, euid=%d, suid=%d, gid=%d, egid=%d, sgid=%d, fsuid=%d, fsgid=%d, cap=0x%llx} ", + ep->COE.uid, ep->COE.euid, ep->COE.suid, ep->COE.gid, + ep->COE.egid, ep->COE.sgid, ep->COE.fsuid, ep->COE.fsgid, + ep->COE.capability.value); +} + +static void show_file(struct seq_file *c, struct tsem_event *ep) +{ + seq_printf(c, "file{flags=%u, uid=%d, gid=%d, mode=0%o, name_length=%u, name=%*phN, s_magic=0x%0x, s_id=%s, s_uuid=%*phN, digest=%*phN}\n", + ep->file.flags, ep->file.uid, ep->file.gid, ep->file.mode, + ep->file.name_length, WP256_DIGEST_SIZE, ep->file.name, + ep->file.s_magic, ep->file.s_id, + (int) sizeof(ep->file.s_uuid), ep->file.s_uuid, + WP256_DIGEST_SIZE, 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, args->file ? ep->pathname : NULL); + seq_printf(c, "%s{type=%u, reqprot=%u, prot=%u, flags=%u} ", + tsem_names[ep->event], args->file == NULL, + args->reqprot, args->prot, args->flags); + + if (!args->file) + seq_puts(c, "\n"); + else + show_file(c, ep); +} + +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, NULL); + seq_printf(c, "%s{family=%u, type=%u, protocol=%u, kern=%u}\n", + tsem_names[ep->event], args->family, args->type, + args->protocol, 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, NULL); + seq_printf(c, "%s{family=%u, ", tsem_names[ep->event], scp->family); + + switch (scp->family) { + case AF_INET: + ipv4 = (struct sockaddr_in *) &scp->u.ipv4; + seq_printf(c, "port=%u, addr=%u}\n", ipv4->sin_port, + ipv4->sin_addr.s_addr); + break; + case AF_INET6: + ipv6 = (struct sockaddr_in6 *) &scp->u.ipv6; + seq_printf(c, "port=%u, flow=%u, scope=%u, addr=%*phN}\n", + ipv6->sin6_port, ipv6->sin6_flowinfo, + ipv6->sin6_scope_id, + (int) sizeof(ipv6->sin6_addr.in6_u.u6_addr8), + ipv6->sin6_addr.in6_u.u6_addr8); + break; + default: + seq_printf(c, "addr=%*phN}\n", WP256_DIGEST_SIZE, + 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, NULL); + seq_printf(c, "%s{family=%u, type=%u, port=%u, addr=", + tsem_names[ep->event], sap->family, sap->type, sap->port); + + switch (sap->family) { + case AF_INET: + seq_printf(c, "%u}\n", sap->ipv4); + break; + case AF_INET6: + seq_printf(c, "%*phN}\n", + (int) sizeof(sap->ipv6.in6_u.u6_addr8), + sap->ipv6.in6_u.u6_addr8); + break; + default: + seq_printf(c, "%*phN}\n", (int) sizeof(sap->tsip->digest), + sap->tsip->digest); + 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, NULL); + seq_printf(c, "%s{cross=%u, signal=%u, target=%*phN}\n", + tsem_names[ep->event], args->cross_model, args->signal, + WP256_DIGEST_SIZE, args->target); +} + +static void show_event_generic(struct seq_file *c, struct tsem_event *ep) +{ + show_event(c, ep, NULL); + seq_printf(c, "%s{type=%s}\n", tsem_names[ep->event], + tsem_names[ep->CELL.event_type]); +} + +static void show_trajectory_event(struct seq_file *c, struct tsem_event *ep) +{ + switch (ep->event) { + case TSEM_FILE_OPEN: + show_event(c, ep, ep->pathname); + 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; + } +} + +static void *trajectory_start(struct seq_file *c, loff_t *pos) +{ + struct tsem_model *model = tsem_model(current); + + mutex_lock(&model->trajectory_mutex); + return seq_list_start(&model->trajectory_list, *pos); +} + +static void *trajectory_next(struct seq_file *c, void *p, loff_t *pos) +{ + struct tsem_model *model = tsem_model(current); + + 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_mutex); +} + +static int trajectory_show(struct seq_file *c, void *trajectory) +{ + struct tsem_trajectory *pt; + struct tsem_event *ep; + + pt = list_entry(trajectory, struct tsem_trajectory, list); + ep = pt->ep; + + show_trajectory_event(c, ep); + + 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 *point_start(struct seq_file *c, loff_t *pos) +{ + struct tsem_model *model = tsem_model(current); + + mutex_lock(&model->point_mutex); + return seq_list_start(&model->point_list, *pos); +} + +static void *point_next(struct seq_file *c, void *p, loff_t *pos) +{ + struct tsem_model *model = tsem_model(current); + + return seq_list_next(p, &model->point_list, pos); +} + +static void point_stop(struct seq_file *c, void *pos) +{ + struct tsem_model *model = tsem_model(current); + + mutex_unlock(&model->point_mutex); +} + +static int point_show(struct seq_file *c, void *point) +{ + struct tsem_event_point *id; + + id = list_entry(point, struct tsem_event_point, list); + seq_printf(c, "%*phN\n", WP256_DIGEST_SIZE, id->point); + return 0; +} + +static const struct seq_operations point_seqops = { + .start = point_start, + .next = point_next, + .stop = point_stop, + .show = point_show +}; + +static int point_open(struct inode *inode, struct file *file) +{ + if (!can_access_fs()) + return -EACCES; + return seq_open(file, &point_seqops); +} + +static const struct file_operations point_ops = { + .open = 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[76]; + unsigned int lp; + ssize_t retn = -EINVAL; + long pid; + 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, ' '); + + for (lp = 0; lp < ARRAY_SIZE(commands); ++lp) { + if (!strncmp(cmdbufr, commands[lp].cmd, + strlen(commands[lp].cmd))) { + type = commands[lp].type; + break; + } + } + + switch (type) { + case TSEM_CONTROL_EXTERNAL: + case TSEM_CONTROL_INTERNAL: + retn = tsem_ns_create(type); + break; + case TSEM_CONTROL_ENFORCE: + case TSEM_CONTROL_SEAL: + retn = config_context(type, cmdbufr); + break; + case TSEM_CONTROL_TRUSTED: + case TSEM_CONTROL_UNTRUSTED: + p = strchr(cmdbufr, ' '); + if (!p) + goto done; + *p++ = '\0'; + if (kstrtol(p, 0, &pid)) + goto done; + retn = control_COE(pid, type); + 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 tsem_model *model = tsem_model(current); + + mutex_lock(&model->forensics_mutex); + return seq_list_start(&model->forensics_list, *pos); +} + +static void *forensics_next(struct seq_file *c, void *p, loff_t *pos) +{ + struct tsem_model *model = tsem_model(current); + + 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_mutex); +} + +static int forensics_show(struct seq_file *c, void *event) +{ + struct tsem_trajectory *pt; + struct tsem_event *ep; + + pt = list_entry(event, struct tsem_trajectory, list); + ep = pt->ep; + + show_trajectory_event(c, ep); + + 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 int measurement_show(struct seq_file *c, void *event) +{ + struct tsem_model *model = tsem_model(current); + + seq_printf(c, "%*phN\n", (int) sizeof(model->measurement), + 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_TMA_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", WP256_DIGEST_SIZE, 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", WP256_DIGEST_SIZE, 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 int export_show(struct seq_file *m, void *v) +{ + return tsem_export_show(m); +} + +static __poll_t export_poll(struct file *file, struct poll_table_struct *wait) +{ + struct tsem_TMA_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, &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, +}; + +static int fs_fill(struct super_block *sb, struct fs_context *fc) +{ + int retn; + + static const struct tree_descr root_files[] = { + [2] = {"control", &control_ops, 0200}, + [3] = {"id", &id_ops, 0400}, + [4] = {"trajectory", &trajectory_ops, 0400}, + [5] = {"forensics", &forensics_ops, 0400}, + [6] = {"points", &point_ops, 0400}, + [7] = {"measurement", &measurement_ops, 0400}, + [8] = {"state", &state_ops, 0400}, + [9] = {"aggregate", &aggregate_ops, 0400}, + {""} + }; + + retn = simple_fill_super(sb, TSEMFS_MAGIC, root_files); + if (retn) + pr_warn("Unable to create TSEM root filesystem.\n"); + + return retn; +} + +static int fs_init_context(struct fs_context *fc) +{ + fc->ops = &fs_operations; + return 0; +} + +static int fs_get_tree(struct fs_context *fc) +{ + return get_tree_single(fc, fs_fill); +} + +static int create_update_directory(void) +{ + int retn = 0; + struct dentry *root, *dentry; + struct inode *root_dir, *inode; + static const char *name = "ExternalTMA"; + + root = fs_mount->mnt_root; + root_dir = d_inode(root); + + inode_lock(root_dir); + dentry = lookup_one_len(name, root, strlen(name)); + if (IS_ERR(dentry)) { + retn = PTR_ERR(dentry); + goto done; + } + + if (d_really_is_positive(dentry)) { + retn = -EEXIST; + goto done_dentry; + } + + inode = new_inode(root_dir->i_sb); + if (!inode) { + retn = -ENOMEM; + goto done_dentry; + } + + inode->i_ino = get_next_ino(); + inode->i_mode = 0755 | S_IFDIR; + inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); + inode->i_private = NULL; + inode->i_fop = &export_ops; + inode->i_op = &simple_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + inc_nlink(inode); + inc_nlink(root_dir); + + d_instantiate(dentry, inode); + dget(dentry); + external_dentry = dentry; + inode_unlock(root_dir); + return 0; + + done_dentry: + dput(dentry); + + done: + inode_unlock(root_dir); + return retn; +} + +/** + * tesm_fs_init() - Initialize the TSEM control filesystem. + * + * This function is called as part of the TSEM LSM initialization + * process. It creates the /sys/fs/tsem mount point and populates + * the filesystem to be mounted there with the control plane file and + * internal TMA model information files. + * + * Return: If filesystem initialization is successful a return code of 0 + * is returned. A negative return value is returned if an error + * is encoutnered. + */ +int __init tsem_fs_init(void) +{ + int retn; + + retn = sysfs_create_mount_point(fs_kobj, "tsem"); + if (retn) { + pr_warn("Unable to create TSEM filesystem mount point.\n"); + return retn; + } + + retn = register_filesystem(&fs_definition); + if (retn) { + pr_warn("Unable to register TSEM filesystem.\n"); + goto done; + } + + fs_mount = kern_mount(&fs_definition); + if (IS_ERR(fs_mount)) { + pr_warn("Unable to mount TSEM filesystem.\n"); + retn = PTR_ERR(fs_mount); + fs_mount = NULL; + } + + retn = create_update_directory(); + + done: + if (retn) + sysfs_remove_mount_point(fs_kobj, "tsem"); + return retn; +} + +/** + * tesm_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/fs/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 + * an error code is encoded in the pointer. + */ +struct dentry *tsem_fs_create_external(const char *name) +{ + int retn = 0; + struct dentry *dentry; + struct inode *root_dir, *inode; + + retn = simple_pin_fs(&fs_definition, &fs_mount, &fs_mount_cnt); + if (retn) + return ERR_PTR(retn); + + root_dir = d_inode(external_dentry); + inode_lock(root_dir); + + dentry = lookup_one_len(name, external_dentry, strlen(name)); + if (IS_ERR(dentry)) { + retn = PTR_ERR(dentry); + goto done; + } + if (d_really_is_positive(dentry)) { + WARN_ON_ONCE(1); + retn = -EEXIST; + goto done_dentry; + } + + inode = new_inode(root_dir->i_sb); + if (!inode) { + retn = -ENOMEM; + goto done_dentry; + } + + inode->i_ino = get_next_ino(); + inode->i_mode = 0400 | S_IFREG; + inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); + inode->i_private = NULL; + inode->i_fop = &export_ops; + + d_instantiate(dentry, inode); + dget(dentry); + inode_unlock(root_dir); + return dentry; + + done_dentry: + dput(dentry); + + done: + inode_unlock(root_dir); + simple_release_fs(&fs_mount, &fs_mount_cnt); + if (retn) + dentry = ERR_PTR(retn); + return dentry; +} + +/** + * tesm_fs_remove_external() - Remove an external modeling update file. + * @dentry: A pointer to the dentry of the file to be removed. + * + * This function is used to remove the update file for an externally + * modeled security domain. + */ +void tsem_fs_remove_external(struct dentry *dentry) +{ + struct inode *root_dir; + + if (!dentry || IS_ERR(dentry)) { + WARN_ON_ONCE(1); + return; + } + + root_dir = d_inode(dentry->d_parent); + + inode_lock(root_dir); + if (simple_positive(dentry)) { + simple_unlink(root_dir, dentry); + dput(dentry); + } + inode_unlock(root_dir); + + simple_release_fs(&fs_mount, &fs_mount_cnt); +} From patchwork Sat Feb 4 05:09:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128587 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 53BDDC636D3 for ; Sat, 4 Feb 2023 05:32:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232978AbjBDFc4 (ORCPT ); Sat, 4 Feb 2023 00:32:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43214 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233010AbjBDFcu (ORCPT ); Sat, 4 Feb 2023 00:32:50 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 2B19693AEC for ; Fri, 3 Feb 2023 21:32:47 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 3145A1k0011661; Fri, 3 Feb 2023 23:10:01 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 3145A1tj011659; Fri, 3 Feb 2023 23:10:01 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 09/14] Add namespace implementation. Date: Fri, 3 Feb 2023 23:09:49 -0600 Message-Id: <20230204050954.11583-10-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: The TSEM LSM has its own 'namespace' implementation for security modeling domains that is independent of other resource namespaces but which is designed to act in much the same manner. The sysfs control plane is used to signal that a process should leave its current modeling domain/namespace and institute a new domain. Additional processes that derive from this process inherit the modeling domain. Each modeling domain 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 modeling domain. Each modeling domain is designated as either internally or externally modeled. An internally modeled domain has its security model implemented by a Trusted Modeling Agent (TMA) implementation that is run in the context of the kernel. Externally modeled domains have a description of the security event exported to an trust orchestrator running in userspace. That trust orchestrator has an associated Trusted Modeling Agent run in a context that implements the root of trust for the security model. A process that exports a security event description is scheduled away into an interruptible sleep state. The trust orchestrator that created the external modeling domain 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 process that carries the CAP_TRUST 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. Only processes that carry the CAP_TRUST capability are allowed to create subordinate modeling domains. The modeling domains are independent entities whose trust state is designed to be managed exclusively by its associated TMA. Signed-off-by: Greg Wettstein --- security/tsem/namespace.c | 226 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 226 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..632d5d4d967c --- /dev/null +++ b/security/tsem/namespace.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2022 Enjellic Systems Development, LLC + * Author: Dr. Greg Wettstein + * + * This file implements TSEM namespaces. + */ + +#include "tsem.h" + +static u64 context_id; + +static struct workqueue_struct *release_wq; + +struct lsm_blob_sizes tsem_blob_sizes __lsm_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. */ +}; + +struct tsem_model root_model = { + .point_mutex = __MUTEX_INITIALIZER(root_model.point_mutex), + .point_list = LIST_HEAD_INIT(root_model.point_list), + .state_list = LIST_HEAD_INIT(root_model.state_list), + + .trajectory_mutex = __MUTEX_INITIALIZER(root_model.trajectory_mutex), + .trajectory_list = LIST_HEAD_INIT(root_model.trajectory_list), + + .max_forensics_count = 100, + .forensics_mutex = __MUTEX_INITIALIZER(root_model.forensics_mutex), + .forensics_list = LIST_HEAD_INIT(root_model.forensics_list), + + .pseudonym_mutex = __MUTEX_INITIALIZER(root_model.pseudonym_mutex), + .pseudonym_list = LIST_HEAD_INIT(root_model.pseudonym_list) +}; + +struct tsem_TMA_context root_TMA_context = { + .kref = KREF_INIT(2), + .id = 0, + .external = false, + .model = &root_model +}; + +static struct tsem_external *allocate_external(void) +{ + int retn = -ENOMEM; + struct tsem_external *external; + char bufr[20 + 1]; + + external = kzalloc(sizeof(struct tsem_external), GFP_KERNEL); + if (!external) + return NULL; + + mutex_init(&external->measurement_mutex); + INIT_LIST_HEAD(&external->measurement_list); + + init_waitqueue_head(&external->wq); + + scnprintf(bufr, sizeof(bufr), "%llu", context_id + 1); + external->dentry = tsem_fs_create_external(bufr); + if (IS_ERR(external->dentry)) { + retn = PTR_ERR(external->dentry); + external->dentry = NULL; + } else + retn = 0; + + if (retn) { + kfree(external); + external = NULL; + } + + return external; +} + +/** + * tsem_ns_free() - Releases the namespace model infrastructure. + * @kref: A pointer to the reference counting structure for the namespace. + * + * This function is called when the last reference to a kernel + * based TMA model structure is released. + */ +void tsem_ns_free(struct kref *kref) +{ + struct tsem_TMA_context *ctx; + + ctx = container_of(kref, struct tsem_TMA_context, kref); + + if (ctx->external) { + tsem_fs_remove_external(ctx->external->dentry); + kfree(ctx->external); + } else + tsem_model_free(ctx); + + kfree(ctx); +} + +static void wq_put(struct work_struct *work) +{ + struct tsem_TMA_work *tsem_work; + struct tsem_TMA_context *ctx; + + tsem_work = container_of(work, struct tsem_TMA_work, work); + ctx = tsem_work->ctx; + kref_put(&ctx->kref, tsem_ns_free); +} + +/** + * tsem_ns_get() - Obtain a reference on a TSEM TMA namespace. + * @ctx: A pointer to the TMA modeling context for which a reference is + * to be released. + * + * This function is called to release a reference to a TMA modeling + * domain. + */ +void tsem_ns_put(struct tsem_TMA_context *ctx) +{ + if (kref_read(&ctx->kref) > 1) { + kref_put(&ctx->kref, tsem_ns_free); + return; + } + + INIT_WORK(&ctx->work.work, wq_put); + ctx->work.ctx = ctx; + if (!queue_work(release_wq, &ctx->work.work)) + WARN_ON_ONCE(1); +} + +/** + * tsem_ns_put() - Obtain a reference on a TSEM TMA namespace. + * @ctx: A pointer to the TMA modeling context for which a reference is + * to be acquired. + * + * This function is called on each invocation of the tsem_task_alloc + * event to obtain a reference against the current modeling domain. + */ +void tsem_ns_get(struct tsem_TMA_context *ctx) +{ + kref_get(&ctx->kref); +} + +/** + * tsem_ns_namespace() - Create a TSEM modeling namespace. + * @event: The numeric identifer of the control message that is to + * be processed. + * + * This function is used to create either an internally or externally + * modeled TSEM namespace. The boolean argument to this function + * selects the type of namespace that is being created. Specification + * of an internal namespace causes the ->model pointer to be initialized + * with a tsem_model structure. + * + * Return: This function returns 0 if the namespace was created and + * a negative error value on error. + */ +int tsem_ns_create(enum tsem_control_type event) +{ + int retn = -ENOMEM; + struct tsem_task *tsk = tsem_task(current); + struct tsem_TMA_context *new_ctx; + struct tsem_model *model = NULL; + + new_ctx = kzalloc(sizeof(struct tsem_TMA_context), GFP_KERNEL); + if (!new_ctx) + goto done; + + if (event == TSEM_CONTROL_INTERNAL) { + model = tsem_model_allocate(); + if (!model) + goto done; + new_ctx->model = model; + } + if (event == TSEM_CONTROL_EXTERNAL) { + new_ctx->external = allocate_external(); + if (!new_ctx->external) + goto done; + } + + kref_init(&new_ctx->kref); + new_ctx->id = ++context_id; + memcpy(new_ctx->actions, tsk->context->actions, + sizeof(new_ctx->actions)); + retn = 0; + + done: + if (retn) { + kfree(new_ctx->external); + kfree(new_ctx); + kfree(model); + } else { + tsk->context = new_ctx; + if (event == TSEM_CONTROL_EXTERNAL) + retn = tsem_export_aggregate(); + else + retn = tsem_model_add_aggregate(); + } + + return retn; +} + +/** + * tsem_ns_init() - Initialize TSEM namespace processing. + * + * This function is called as part of the TSEM LSM initialization + * process. It initializes the workqueue that will be used to + * conduct the asynchronous release of modeling contexts. The + * deferral of the namespace clean is needed in order to address + * the fact that the /sys/fs/tsem pseudo-files cannot be done + * in atomic context. + * + * Return: If the initialization succeeds a return code of 0 is returned. + * A negative return value is returned on failure. + */ +int __init tsem_ns_init(void) +{ + int retn = 0; + + release_wq = create_workqueue("tsem_ns_release"); + if (IS_ERR(release_wq)) + retn = PTR_ERR(release_wq); + + return retn; +} From patchwork Sat Feb 4 05:09:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128589 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D406C636D3 for ; Sat, 4 Feb 2023 05:33:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233325AbjBDFdA (ORCPT ); Sat, 4 Feb 2023 00:33:00 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43206 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233341AbjBDFc4 (ORCPT ); Sat, 4 Feb 2023 00:32:56 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id C7E1892EFA for ; Fri, 3 Feb 2023 21:32:52 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 3145A3Mh011666; Fri, 3 Feb 2023 23:10:03 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 3145A2L3011664; Fri, 3 Feb 2023 23:10:02 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 10/14] Add security event description export facility. Date: Fri, 3 Feb 2023 23:09:50 -0600 Message-Id: <20230204050954.11583-11-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: The functionality for surfacing security model events to an external modeling domain is implemented in the export.c file. ASCII descriptions of the events are presented to a userspace trust orchestrator through the following pseudo-files: /sys/fs/tsem/ExternalTMA/N Where N is replaced with security model domain identifier. 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 point 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/fs/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 tsemfs control plane to wake the process that exported the event and set its status to either trusted or untrusted. Signed-off-by: Greg Wettstein --- security/tsem/export.c | 388 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 388 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..84c71fb96153 --- /dev/null +++ b/security/tsem/export.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2022 Enjellic Systems Development, LLC + * Author: Dr. Greg Wettstein + * + * Implements updates to an external modeling engine. + */ + +#include + +#include "tsem.h" + +enum export_events_type { + AGGREGATE_EVENT = 1, + EXPORT_EVENT, + LOG_EVENT +}; + +struct action_description { + enum tsem_event_type type; + enum tsem_action_type action; + char comm[TASK_COMM_LEN]; +}; + +struct export_event { + struct list_head list; + enum export_events_type type; + union { + u8 *aggregate[WP256_DIGEST_SIZE]; + struct tsem_event *ep; + struct action_description action; + } u; +}; + +static const char * const tsem_actions[TSEM_ACTION_CNT] = { + "LOG", + "DENY" +}; + +static void trigger_event(struct tsem_TMA_context *ctx) +{ + ctx->external->have_event = true; + wake_up_interruptible(&ctx->external->wq); +} + +static void show_event_coe(struct tsem_event *ep, struct seq_file *page) +{ + seq_printf(page, "export pid{%u} ", ep->pid); + + seq_printf(page, "event{process=%s, filename=%s, ", ep->comm, + ep->pathname == NULL ? "none" : ep->pathname); + seq_printf(page, "type=%s, task_id=%*phN} ", tsem_names[ep->event], + WP256_DIGEST_SIZE, ep->task_id); + + seq_printf(page, "COE{uid=%d, euid=%d, suid=%d, gid=%d, ", ep->COE.uid, + ep->COE.euid, ep->COE.suid, ep->COE.gid); + seq_printf(page, "egid=%d, sgid=%d, fsuid=%d, fsgid=%d, ", + ep->COE.egid, ep->COE.sgid, ep->COE.fsuid, ep->COE.fsgid); + seq_printf(page, "cap=0x%llx} ", ep->COE.capability.value); +} + +static void show_file(struct tsem_event *ep, struct seq_file *page) +{ + seq_printf(page, "file{flags=%u, uid=%d, gid=%d, mode=0%o, ", + ep->file.flags, ep->file.uid, ep->file.gid, ep->file.mode); + seq_printf(page, "name_length=%u, name=%*phN, s_magic=0x%0x, ", + ep->file.name_length, WP256_DIGEST_SIZE, ep->file.name, + ep->file.s_magic); + seq_printf(page, "s_id=%s, s_uuid=%*phN, digest=%*phN}\n", + ep->file.s_id, (int) sizeof(ep->file.s_uuid), + ep->file.s_uuid, WP256_DIGEST_SIZE, ep->file.digest); +} + +static void show_mmap_file(struct tsem_event *ep, struct seq_file *page) +{ + show_event_coe(ep, page); + + seq_printf(page, "%s{type=%u, reqprot=%u, ", tsem_names[ep->event], + ep->CELL.mmap_file.anonymous, ep->CELL.mmap_file.reqprot); + seq_printf(page, "prot=%u, flags=%u}", ep->CELL.mmap_file.prot, + ep->CELL.mmap_file.flags); + + if (!ep->CELL.mmap_file.anonymous) { + seq_puts(page, " "); + show_file(ep, page); + } else + seq_puts(page, "\n"); +} + +static void show_ipv4_socket(struct tsem_event *ep, struct seq_file *page) +{ + struct sockaddr_in *ipv4 = &ep->CELL.socket_connect.u.ipv4; + + show_event_coe(ep, page); + seq_printf(page, "%s{family=%u, port=%u, addr=%u}\n", + tsem_names[ep->event], ipv4->sin_family, ipv4->sin_port, + ipv4->sin_addr.s_addr); +} + +static void show_ipv6_socket(struct tsem_event *ep, struct seq_file *page) +{ + struct sockaddr_in6 *ipv6 = &ep->CELL.socket_connect.u.ipv6; + + show_event_coe(ep, page); + + seq_printf(page, "%s{family=%u, port=%u, flow=%u, ", + tsem_names[ep->event], ipv6->sin6_family, + ipv6->sin6_port, ipv6->sin6_flowinfo); + seq_printf(page, "scope=%u, addr=%*phN}\n", ipv6->sin6_scope_id, + (int) sizeof(ipv6->sin6_addr.in6_u.u6_addr8), + ipv6->sin6_addr.in6_u.u6_addr8); +} + +static void show_socket(struct tsem_event *ep, struct seq_file *page) +{ + struct tsem_socket_connect_args *scp = &ep->CELL.socket_connect; + + show_event_coe(ep, page); + + seq_printf(page, "%s{family=%u, addr=%*phN}\n", tsem_names[ep->event], + scp->family, WP256_DIGEST_SIZE, scp->u.mapping); +} + +static void show_socket_create(struct tsem_event *ep, struct seq_file *page) +{ + show_event_coe(ep, page); + + seq_printf(page, "%s{family=%u, type=%u, ", tsem_names[ep->event], + ep->CELL.socket_create.family, ep->CELL.socket_create.type); + seq_printf(page, "protocol=%u, kern=%u}\n", + ep->CELL.socket_create.protocol, + ep->CELL.socket_create.kern); +} + +static void show_socket_accept(struct tsem_event *ep, struct seq_file *page) +{ + u8 *p; + int size; + struct tsem_socket_accept_args *sap = &ep->CELL.socket_accept; + + show_event_coe(ep, page); + + seq_printf(page, "%s{family=%u, type=%u, port=%u, addr=", + tsem_names[ep->event], sap->family, sap->type, sap->port); + + if (sap->family == AF_INET) { + seq_printf(page, "%u}\n", sap->ipv4); + return; + } + + if (sap->family == AF_INET6) { + p = sap->ipv6.in6_u.u6_addr8; + size = sizeof(sap->ipv6.in6_u.u6_addr8); + } else { + p = sap->tsip->digest; + size = sizeof(sap->tsip->digest); + } + seq_printf(page, "%*phN}\n", size, p); +} + +static void show_socket_events(struct tsem_event *ep, struct seq_file *page) +{ + switch (ep->event) { + case TSEM_SOCKET_CREATE: + show_socket_create(ep, page); + break; + + case TSEM_SOCKET_CONNECT: + case TSEM_SOCKET_BIND: + switch (ep->CELL.socket_connect.family) { + case AF_INET: + show_ipv4_socket(ep, page); + break; + case AF_INET6: + show_ipv6_socket(ep, page); + break; + default: + show_socket(ep, page); + break; + } + break; + + case TSEM_SOCKET_ACCEPT: + show_socket_accept(ep, page); + break; + + default: + break; + } +} + +static void show_task_kill(struct tsem_event *ep, struct seq_file *page) +{ + struct tsem_task_kill_args *args = &ep->CELL.task_kill; + + show_event_coe(ep, page); + + seq_printf(page, "%s{cross=%u, signal=%u, target=%*phN}\n", + tsem_names[ep->event], args->cross_model, + args->signal, WP256_DIGEST_SIZE, args->target); +} + +static void show_event_generic(struct tsem_event *ep, struct seq_file *page) +{ + show_event_coe(ep, page); + + seq_printf(page, "%s{type=%s}\n", tsem_names[ep->event], + tsem_names[ep->CELL.event_type]); +} + +int tsem_export_show(struct seq_file *page) +{ + ssize_t retn = -ENODATA; + struct export_event *mp; + struct tsem_event *ep; + struct tsem_TMA_context *ctx = tsem_context(current); + + if (!ctx->id) + return -EPERM; + + mutex_lock(&ctx->external->measurement_mutex); + if (list_empty(&ctx->external->measurement_list)) + goto done; + mp = list_first_entry(&ctx->external->measurement_list, + struct export_event, list); + + switch (mp->type) { + case AGGREGATE_EVENT: + seq_printf(page, "aggregate %*phN\n", WP256_DIGEST_SIZE, + mp->u.aggregate); + break; + + case EXPORT_EVENT: + ep = mp->u.ep; + switch (ep->event) { + case TSEM_FILE_OPEN: + show_event_coe(ep, page); + show_file(ep, page); + break; + + case TSEM_MMAP_FILE: + show_mmap_file(ep, page); + break; + + case TSEM_SOCKET_CREATE: + case TSEM_SOCKET_CONNECT: + case TSEM_SOCKET_BIND: + case TSEM_SOCKET_ACCEPT: + show_socket_events(ep, page); + break; + + case TSEM_TASK_KILL: + show_task_kill(ep, page); + break; + + case TSEM_GENERIC_EVENT: + show_event_generic(ep, page); + break; + + default: + break; + } + tsem_event_put(ep); + break; + + case LOG_EVENT: + seq_printf(page, "log process{%s} event{%s} action{%s}\n", + mp->u.action.comm, tsem_names[mp->u.action.type], + tsem_actions[mp->u.action.action]); + break; + } + + list_del(&mp->list); + kfree(mp); + retn = 0; + + done: + mutex_unlock(&ctx->external->measurement_mutex); + return retn; +} + +int tsem_export_event(struct tsem_event *ep) +{ + int retn = 0; + struct tsem_task *task = tsem_task(current); + struct tsem_TMA_context *ctx = task->context; + struct export_event *mp; + + if (!ctx->external) + return 0; + + mp = kzalloc(sizeof(struct export_event), GFP_KERNEL); + if (!mp) { + retn = -ENOMEM; + goto done; + } + mp->type = EXPORT_EVENT; + mp->u.ep = ep; + tsem_event_get(ep); + + mutex_lock(&ctx->external->measurement_mutex); + list_add_tail(&mp->list, &ctx->external->measurement_list); + mutex_unlock(&ctx->external->measurement_mutex); + + 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(¤t->pending.signal, SIGKILL) || + sigismember(¤t->signal->shared_pending.signal, + SIGKILL)) + task->trust_status = TSEM_TASK_UNTRUSTED; + } + } + + done: + 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. + * + * 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) +{ + struct tsem_TMA_context *ctx = tsem_context(current); + struct export_event *exp; + + exp = kzalloc(sizeof(struct export_event), GFP_KERNEL); + if (!exp) + 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); + + mutex_lock(&ctx->external->measurement_mutex); + list_add_tail(&exp->list, &ctx->external->measurement_list); + mutex_unlock(&ctx->external->measurement_mutex); + + 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_TMA_context *ctx = tsem_context(current); + struct export_event *exp; + + exp = kzalloc(sizeof(struct export_event), GFP_KERNEL); + if (!exp) + return -ENOMEM; + + exp->type = AGGREGATE_EVENT; + memcpy(exp->u.aggregate, tsem_trust_aggregate(), + sizeof(exp->u.aggregate)); + + mutex_lock(&ctx->external->measurement_mutex); + list_add_tail(&exp->list, &ctx->external->measurement_list); + mutex_unlock(&ctx->external->measurement_mutex); + + trigger_event(ctx); + + return 0; +} From patchwork Sat Feb 4 05:09:51 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128591 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CF107C636CD for ; Sat, 4 Feb 2023 05:33:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232470AbjBDFdJ (ORCPT ); Sat, 4 Feb 2023 00:33:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43484 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233338AbjBDFdF (ORCPT ); Sat, 4 Feb 2023 00:33:05 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 2A8DD30EC for ; Fri, 3 Feb 2023 21:33:00 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 3145A3vv011671; Fri, 3 Feb 2023 23:10:03 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 3145A3Hl011669; Fri, 3 Feb 2023 23:10:03 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 11/14] Add event description implementation. Date: Fri, 3 Feb 2023 23:09:51 -0600 Message-Id: <20230204050954.11583-12-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: The event.c file implements support for packaging the description of an event into its Context Of Execution (COE) and CELL components for subsequent modeling by an internal Trusted Modeling Agent or export to a trust orchestrator. 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 domains 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 domain 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.o 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 SHA256 cryptographic hashing function. 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 allocates 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 --- security/tsem/event.c | 474 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 474 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..a6162caf2d81 --- /dev/null +++ b/security/tsem/event.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2022 Enjellic Systems Development, LLC + * Author: Dr. Greg Wettstein + * + * This file manages the data structures used to define a security event. + */ + +#define ZERO_FILE "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + +#include +#include + +#include "tsem.h" +#include "../integrity/integrity.h" + +static struct kmem_cache *event_cachep; + +static void get_COE(struct tsem_COE *COE) + +{ + kernel_cap_t eff, per, inh; + + COE->uid = from_kuid(&init_user_ns, current_uid()); + COE->euid = from_kuid(&init_user_ns, current_euid()); + COE->suid = from_kuid(&init_user_ns, current_suid()); + + COE->gid = from_kgid(&init_user_ns, current_gid()); + COE->egid = from_kgid(&init_user_ns, current_egid()); + COE->sgid = from_kgid(&init_user_ns, current_sgid()); + + COE->fsuid = from_kuid(&init_user_ns, current_fsuid()); + COE->fsgid = from_kgid(&init_user_ns, current_fsgid()); + + if (security_capget(current, &eff, &inh, &per) != 0) + eff = CAP_FULL_SET; + COE->capability.mask = eff; +} + +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 crypto_shash *tfm, struct tsem_event *ep) +{ + int retn; + SHASH_DESC_ON_STACK(shash, tfm); + + shash->tfm = tfm; + 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 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 crypto_shash *tfm, 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 = tfm; + 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; +} + +int add_file_digest(struct file *file, struct tsem_file *tfp) +{ + int retn = 0; + loff_t size; + struct inode *inode = NULL; + struct tsem_inode *tsip; + u8 measurement[WP256_DIGEST_SIZE]; + struct tsem_TMA_context *ctx = tsem_context(current); + struct crypto_shash *tfm; + + memset(measurement, '\0', sizeof(measurement)); + inode = file_inode(file); + tsip = tsem_inode(inode); + + mutex_lock(&tsip->mutex); + if (!ctx->external) { + retn = tsem_model_has_pseudonym(tsip, tfp, measurement); + if (retn < 0) + goto done; + if (retn) { + memcpy(tfp->digest, measurement, sizeof(tfp->digest)); + retn = 0; + goto done; + } + } + + size = i_size_read(inode); + if (!size) { + if (!hex2bin(measurement, ZERO_FILE, sizeof(measurement))) + memcpy(tfp->digest, measurement, sizeof(tfp->digest)); + else + memset(tfp->digest, '\0', sizeof(tfp->digest)); + goto done; + } + + if (inode_eq_iversion(inode, tsip->version) && + tsip->status == TSEM_INODE_COLLECTED) { + memcpy(tfp->digest, tsip->digest, sizeof(tfp->digest)); + goto done; + } + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) { + retn = PTR_ERR(tfm); + goto done; + } + + tsip->status = TSEM_INODE_COLLECTING; + retn = get_file_digest(tfm, file, inode, size, measurement); + if (retn) + tsip->status = 0; + else { + memcpy(tfp->digest, measurement, sizeof(tfp->digest)); + memcpy(tsip->digest, measurement, sizeof(tsip->digest)); + tsip->status = TSEM_INODE_COLLECTED; + tsip->version = inode_query_iversion(inode); + } + + done: + mutex_unlock(&tsip->mutex); + return retn; +} + +static int get_file_cell(struct file *file, struct tsem_event *ep) +{ + int retn = 1; + struct crypto_shash *tfm; + struct inode *inode; + + inode = file_inode(file); + inode_lock(inode); + + ep->pathname = get_path(file); + if (IS_ERR(ep->pathname)) { + retn = PTR_ERR(ep->pathname); + goto done; + } + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) { + retn = PTR_ERR(tfm); + goto done; + } + + retn = add_file_name(tfm, ep); + if (retn) + goto done; + + retn = add_file_digest(file, &ep->file); + if (retn) + goto done; + + ep->file.flags = file->f_flags; + + ep->file.uid = from_kuid(&init_user_ns, inode->i_uid); + ep->file.gid = from_kgid(&init_user_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); + crypto_free_shash(tfm); + return retn; +} + +static int get_socket_mapping(struct crypto_shash *tfm, + struct tsem_socket_connect_args *scp) +{ + int retn, size; + u8 *p; + SHASH_DESC_ON_STACK(shash, tfm); + + shash->tfm = tfm; + retn = crypto_shash_init(shash); + if (retn) + goto done; + + switch (scp->family) { + case AF_UNIX: + p = (u8 *) scp->addr->sa_data; + size = strlen(p); + retn = crypto_shash_finup(shash, p, size, scp->u.mapping); + break; + default: + p = (u8 *) scp->addr->sa_data; + size = sizeof(scp->addr) - offsetof(struct sockaddr, sa_data); + retn = crypto_shash_finup(shash, p, size, scp->u.mapping); + break; + } + memcpy(scp->tsip->digest, scp->u.mapping, sizeof(scp->tsip->digest)); + + done: + return retn; +} + +static int get_socket_cell(struct tsem_event *ep) + +{ + int retn = 0; + struct crypto_shash *tfm = NULL; + 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; + default: + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) { + retn = PTR_ERR(tfm); + tfm = NULL; + goto done; + } + retn = get_socket_mapping(tfm, scp); + break; + } + + done: + crypto_free_shash(tfm); + return retn; +} + +/** + * tsem_event_allocate() - Allocate a security event description structure. + * @event: The security event number for which the structure is being + * allocated. + * @params: A pointer to the aggregation structure used to hold the + * parameters that describe the function. + * + * This function is responsible for allocating 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_allocate(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 = kmem_cache_zalloc(event_cachep, GFP_KERNEL); + if (!ep) { + retn = -ENOMEM; + goto done; + } + + ep->event = event; + ep->pid = task_pid_nr(current); + memcpy(ep->comm, current->comm, sizeof(ep->comm)); + memcpy(ep->task_id, task->task_id, sizeof(ep->task_id)); + + 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; + 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; + } + + done: + if (retn) { + kfree(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_COE_cell() 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_cache_init() - Initialize the TSEM event cache. + * + * This function is called by the TSEM initialization function and sets + * up the cache that will hold 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; +} From patchwork Sat Feb 4 05:09:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128590 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 09B5CC636D3 for ; Sat, 4 Feb 2023 05:33:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231654AbjBDFdH (ORCPT ); Sat, 4 Feb 2023 00:33:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43216 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229449AbjBDFdA (ORCPT ); Sat, 4 Feb 2023 00:33:00 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7EFF092EEA for ; Fri, 3 Feb 2023 21:32:56 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 3145A4kQ011676; Fri, 3 Feb 2023 23:10:04 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 3145A4hU011674; Fri, 3 Feb 2023 23:10:04 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 12/14] Implement security event mapping. Date: Fri, 3 Feb 2023 23:09:52 -0600 Message-Id: <20230204050954.11583-13-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: The map.c file is responsible for implenting the description of a security event into a security event state point. 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 for the introduction of 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 point mapping is as follows: Sp = SHA256(SHA256(EVENT_ID) || TASK_ID || SHA256(COE) || SHA256(CELL)) This function is fully described in the previously noted documentation file. The TASK_ID is the security state point 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 point mapping but substitutes a TASK_ID that consists of 32 null bytes. Since a generically modeled event does not have a format CELL definition this file contains a default CELL digest value that is used in the generation for a security state point for these events. A generic value is currently supplied with a roadmap that would allow trust orchestrators to set this value in order to avoid a kernel ABI dependency on this value. Signed-off-by: Greg Wettstein --- security/tsem/map.c | 497 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 497 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..04108dd36c1e --- /dev/null +++ b/security/tsem/map.c @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2022 Enjellic Systems Development, LLC + * Author: Dr. Greg Wettstein + * + * This file implements mapping of events into security event points. + */ + +#include + +#include "tsem.h" + +const u8 generic_cell[WP256_DIGEST_SIZE] = { + 0x61, 0x87, 0x8a, 0xe5, 0x8a, 0x7c, 0x22, 0xb4, + 0xea, 0xb9, 0x32, 0xed, 0x3f, 0xdf, 0x34, 0x54, + 0x39, 0x9b, 0xeb, 0x48, 0xd7, 0x44, 0xa7, 0x0e, + 0xab, 0x80, 0xc1, 0xd1, 0x99, 0xd8, 0x69, 0xc8 +}; + +static int get_COE_mapping(struct crypto_shash *tfm, struct tsem_event *ep, + u8 *mapping) +{ + int retn = 0, size; + u8 *p; + SHASH_DESC_ON_STACK(shash, tfm); + + shash->tfm = tfm; + 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.capability; + size = sizeof(ep->COE.capability); + retn = crypto_shash_finup(shash, p, size, mapping); + + done: + return retn; +} + +static int get_cell_mapping(struct crypto_shash *tfm, 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 = tfm; + 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 = sizeof(ep->file.name); + 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 = sizeof(ep->file.digest); + 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; + + default: + p = (u8 *) scp->u.mapping; + size = sizeof(scp->u.mapping); + 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->ipv4; + size = sizeof(sap->ipv4); + retn = crypto_shash_finup(shash, p, size, mapping); + if (retn) + goto done; + break; + + case AF_INET6: + p = (u8 *) sap->ipv6.in6_u.u6_addr8; + size = sizeof(sap->ipv6.in6_u.u6_addr8); + retn = crypto_shash_finup(shash, p, size, mapping); + if (retn) + goto done; + break; + + default: + p = sap->tsip->digest; + size = sizeof(sap->tsip->digest); + 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 = (u8 *) generic_cell; + size = sizeof(generic_cell); + retn = crypto_shash_finup(shash, p, size, mapping); + if (retn) + goto done; + break; + + default: + break; + } + + done: + return retn; +} + +static int get_event_mapping(struct crypto_shash *tfm, 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 = tfm; + 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, WP256_DIGEST_SIZE); + if (retn) + goto done; + } + retn = crypto_shash_update(shash, COE_id, WP256_DIGEST_SIZE); + if (retn) + goto done; + retn = crypto_shash_finup(shash, cell_id, WP256_DIGEST_SIZE, 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[WP256_DIGEST_SIZE]; + u8 cell_mapping[WP256_DIGEST_SIZE]; + struct crypto_shash *tfm = NULL; + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) { + retn = PTR_ERR(tfm); + tfm = NULL; + goto done; + } + + retn = get_COE_mapping(tfm, ep, COE_mapping); + if (retn) + goto done; + + retn = get_cell_mapping(tfm, ep, cell_mapping); + if (retn) + goto done; + + retn = get_event_mapping(tfm, event, task_id, COE_mapping, + cell_mapping, event_mapping); + done: + crypto_free_shash(tfm); + 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[WP256_DIGEST_SIZE]; + struct tsem_event *ep; + struct tsem_event_parameters params; + + params.u.file = file; + ep = tsem_event_allocate(TSEM_BPRM_SET_CREDS, ¶ms); + if (IS_ERR(ep)) { + retn = PTR_ERR(ep); + ep = NULL; + goto done; + } + + memset(null_taskid, '\0', sizeof(null_taskid)); + 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. + * @file: A pointer to the structure containing the event description + * parameters. + * + * This function creates the tsem_event structure that describes + * a security event. + * + * 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_allocate(event, params); + 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; +} From patchwork Sat Feb 4 05:09:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128592 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A0608C636CD for ; Sat, 4 Feb 2023 05:33:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233333AbjBDFdQ (ORCPT ); Sat, 4 Feb 2023 00:33:16 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43526 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232999AbjBDFdJ (ORCPT ); Sat, 4 Feb 2023 00:33:09 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 39636E041 for ; Fri, 3 Feb 2023 21:33:05 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 3145A5Vn011681; Fri, 3 Feb 2023 23:10:05 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 3145A5aN011679; Fri, 3 Feb 2023 23:10:05 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 13/14] Implement an internal Trusted Modeling Agent. Date: Fri, 3 Feb 2023 23:09:53 -0600 Message-Id: <20230204050954.11583-14-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: 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 point. The sum of these state points is considered to be the functional value of the security model implemented for the modeling domain. 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 event state point, as generated by the tsem_map_event() function, and determines whether or not this point is a valid coefficient in the implemented model. If it is a valid point 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 point is registered as a valid point 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 state points 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 = SHA256(PATH_LENGTH || PATHNAME) If a file pseudonym is detected the file digest value used for the CELL definition is set to a default value that is the SHA256 value of a zero length file. The model.c file implementing the in kernel modeling agent defines this value. The pseudonym value is model specific. A separate modeling domain, with a pseudonym definition, will use the actual computed digest of the file. The TMA implementation also supports the definition of 'base' point that is a 32 byte nonce that can be used to extend each security event state point before it is added to the model. This allows a verifying partner to specify a random value 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 points 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 points in the model in big-endian (natural hash byte order) format and then computing the extension sum over this sorted vector of points. Signed-off-by: Greg Wettstein --- security/tsem/model.c | 598 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 598 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..e2fb7307c1b0 --- /dev/null +++ b/security/tsem/model.c @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (C) 2022 Enjellic Systems Development, LLC + * Author: Dr. Greg Wettstein + * + * Implements the an kernel modeling agent. + */ + +#include +#include + +#include "tsem.h" + +const u8 pseudonym_digest[WP256_DIGEST_SIZE] = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 +}; + +struct state_point { + struct list_head list; + struct tsem_event_point *point; +}; + +struct pseudonym { + struct list_head list; + u8 mapping[WP256_DIGEST_SIZE]; +}; + +static int generate_pseudonym(struct crypto_shash *tfm, struct tsem_file *ep, + u8 *pseudonym) +{ + int retn = 0; + SHASH_DESC_ON_STACK(shash, tfm); + + shash->tfm = tfm; + + 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, WP256_DIGEST_SIZE, + pseudonym); + done: + return retn; +} + +static int have_point(u8 *point) +{ + int retn = 0; + struct tsem_event_point *entry; + struct tsem_model *model = tsem_model(current); + + mutex_lock(&model->point_mutex); + list_for_each_entry(entry, &model->point_list, list) { + if (memcmp(entry->point, point, WP256_DIGEST_SIZE) == 0) { + if (entry->valid) + retn = 1; + else + retn = -EPERM; + goto done; + } + } + + done: + mutex_unlock(&model->point_mutex); + return retn; +} + +static int add_event_point(u8 *point, bool valid) +{ + int retn = 1; + struct tsem_event_point *entry; + struct state_point *state; + struct tsem_model *model = tsem_model(current); + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + goto done; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + goto done; + state->point = entry; + + mutex_lock(&model->point_mutex); + memcpy(entry->point, point, WP256_DIGEST_SIZE); + entry->valid = valid; + list_add_tail(&entry->list, &model->point_list); + list_add_tail(&state->list, &model->state_list); + ++model->point_count; + mutex_unlock(&model->point_mutex); + retn = 0; + + done: + return retn; +} + +static int add_trajectory_point(struct tsem_event *ep) +{ + struct tsem_trajectory *entry; + struct tsem_model *model = tsem_model(current); + + entry = kzalloc(sizeof(struct tsem_trajectory), GFP_KERNEL); + if (!entry) + return -ENOMEM; + entry->ep = ep; + tsem_event_get(ep); + + mutex_lock(&model->trajectory_mutex); + list_add_tail(&entry->list, &model->trajectory_list); + ++model->trajectory_count; + mutex_unlock(&model->trajectory_mutex); + + return 0; +} + +static int add_forensic_point(struct tsem_event *ep) +{ + struct tsem_trajectory *entry; + struct tsem_model *model = tsem_model(current); + + if (model->forensics_count == model->max_forensics_count) + return -E2BIG; + + entry = kzalloc(sizeof(struct tsem_trajectory), GFP_KERNEL); + if (!entry) + return -ENOMEM; + entry->ep = ep; + tsem_event_get(ep); + + mutex_lock(&model->forensics_mutex); + list_add_tail(&entry->list, &model->forensics_list); + ++model->forensics_count; + mutex_unlock(&model->forensics_mutex); + + return 0; +} + +static int get_host_measurement(struct crypto_shash *tfm, u8 *id, + size_t idlength, u8 *digest) +{ + int retn; + SHASH_DESC_ON_STACK(shash, tfm); + struct tsem_model *model = tsem_model(current); + + shash->tfm = tfm; + retn = crypto_shash_init(shash); + if (retn) + goto done; + retn = crypto_shash_update(shash, model->base, WP256_DIGEST_SIZE); + if (retn) + goto done; + retn = crypto_shash_finup(shash, id, idlength, digest); + + done: + return retn; +} + +static int update_events_measurement(struct crypto_shash *tfm, u8 *id) +{ + int retn; + u8 digest[WP256_DIGEST_SIZE]; + struct tsem_model *model = tsem_model(current); + SHASH_DESC_ON_STACK(shash, tfm); + + retn = get_host_measurement(tfm, id, WP256_DIGEST_SIZE, digest); + if (retn) + goto done; + + shash->tfm = tfm; + retn = crypto_shash_init(shash); + if (retn) + goto done; + + retn = crypto_shash_update(shash, model->measurement, + WP256_DIGEST_SIZE); + if (retn) + goto done; + + retn = crypto_shash_finup(shash, digest, sizeof(digest), + model->measurement); + if (retn) + goto done; + + if (!tsem_context(current)->id) + retn = tsem_trust_add_event(digest); + + done: + return retn; +} + +static int state_sort(void *priv, const struct list_head *a, + const struct list_head *b) +{ + unsigned int lp, retn; + struct state_point *ap = container_of(a, struct state_point, list); + struct state_point *bp = container_of(b, struct state_point, list); + + for (lp = 0; lp < WP256_DIGEST_SIZE - 1; ++lp) { + if (ap->point->point[lp] == bp->point->point[lp]) + continue; + retn = ap->point->point[lp] > bp->point->point[lp]; + goto done; + } + retn = ap->point->point[lp] > bp->point->point[lp]; + + done: + return retn; +} + +/** + * tesm_model_compute_state() - Calculate a security model state value. + * + * This value is used to trigger the computation of the security + * state description value for a modeling domain. + */ +void tsem_model_compute_state(void) +{ + u8 state[WP256_DIGEST_SIZE]; + struct state_point *entry; + struct tsem_model *model = tsem_model(current); + struct crypto_shash *sha256 = NULL; + SHASH_DESC_ON_STACK(shash, tfm); + + sha256 = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(sha256)) + return; + + shash->tfm = sha256; + if (crypto_shash_init(shash)) + goto done; + + memset(state, '\0', sizeof(state)); + if (crypto_shash_update(shash, state, WP256_DIGEST_SIZE)) + goto done; + + if (get_host_measurement(sha256, tsem_trust_aggregate(), + WP256_DIGEST_SIZE, state)) + goto done; + + if (crypto_shash_finup(shash, state, sizeof(state), state)) + goto done; + + mutex_lock(&model->point_mutex); + list_sort(NULL, &model->state_list, state_sort); + + memcpy(model->state, state, sizeof(model->state)); + list_for_each_entry(entry, &model->state_list, list) { + if (get_host_measurement(sha256, entry->point->point, + WP256_DIGEST_SIZE, state)) + goto unlock_done; + + if (crypto_shash_init(shash)) + goto unlock_done; + if (crypto_shash_update(shash, model->state, + WP256_DIGEST_SIZE)) + goto unlock_done; + if (crypto_shash_finup(shash, state, WP256_DIGEST_SIZE, + model->state)) + goto unlock_done; + } + + unlock_done: + mutex_unlock(&model->point_mutex); + done: + if (sha256) + crypto_free_shash(sha256); +} + +/** + * 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. + * @mapping: A byte array into which the pseudonym state is + * to be copied. + * + * This function is used to test whether a pseudonym has been + * declared for a modeling domain. The pseudonym state point is + * made available via the array pointed to by the mapping variable. + * + * 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 + * psuedonym had been defined and the mapping variable contains + * the pseudonym state point. + */ +int tsem_model_has_pseudonym(struct tsem_inode *tsip, struct tsem_file *ep, + u8 *mapping) +{ + int retn = 0; + u8 pseudo_mapping[WP256_DIGEST_SIZE]; + struct tsem_model *model = tsem_model(current); + struct crypto_shash *tfm; + struct pseudonym *entry; + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) { + retn = PTR_ERR(tfm); + goto done; + } + retn = generate_pseudonym(tfm, 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, + sizeof(entry->mapping))) { + retn = 1; + goto done; + } + } + retn = 0; + + done: + if (retn) + memcpy(mapping, pseudonym_digest, WP256_DIGEST_SIZE); + + mutex_unlock(&model->pseudonym_mutex); + crypto_free_shash(tfm); + 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 crypto_shash *sha256 = NULL; + struct tsem_task *task = tsem_task(current); + struct tsem_TMA_context *ctx = task->context; + + sha256 = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(sha256)) + return PTR_ERR(sha256); + + retn = have_point(ep->mapping); + if (retn) { + if (retn != 1) + task->trust_status = TSEM_TASK_UNTRUSTED; + return 0; + } + + retn = update_events_measurement(sha256, ep->mapping); + if (retn) + goto done; + + if (ctx->sealed) { + retn = add_event_point(ep->mapping, false); + if (!retn) + retn = add_forensic_point(ep); + task->trust_status = TSEM_TASK_UNTRUSTED; + } else { + retn = add_event_point(ep->mapping, true); + if (!retn) + retn = add_trajectory_point(ep); + } + if (retn) + retn = -EPERM; + + done: + crypto_free_shash(sha256); + 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) +{ + ssize_t retn = 0; + struct crypto_shash *tfmsha256 = NULL; + struct tsem_TMA_context *ctx = tsem_context(current); + + if (have_point(point)) + goto done; + if (add_event_point(point, true)) { + retn = -ENOMEM; + goto done; + } + + tfmsha256 = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfmsha256)) { + retn = PTR_ERR(tfmsha256); + goto done; + } + + if (!ctx->model->have_aggregate) { + ctx->model->have_aggregate = true; + retn = update_events_measurement(tfmsha256, + tsem_trust_aggregate()); + if (retn) + goto done; + } + + retn = update_events_measurement(tfmsha256, point); + +done: + if (tfmsha256) + crypto_free_shash(tfmsha256); + 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(struct pseudonym), GFP_KERNEL); + if (!psp) + return -ENOMEM; + memcpy(psp->mapping, mapping, sizeof(psp->mapping)); + + 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, sizeof(model->base)); +} + +/** + * 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; + struct crypto_shash *tfm = NULL; + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); + + retn = update_events_measurement(tfm, tsem_trust_aggregate()); + crypto_free_shash(tfm); + return retn; +} + +/** + * tsem_model_allocate() - Allocates a kernel TMA modeling structure. + * + * 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(void) +{ + struct tsem_model *model = NULL; + + model = kzalloc(sizeof(struct tsem_model), GFP_KERNEL); + if (!model) + return NULL; + + mutex_init(&model->point_mutex); + INIT_LIST_HEAD(&model->point_list); + INIT_LIST_HEAD(&model->state_list); + + mutex_init(&model->trajectory_mutex); + INIT_LIST_HEAD(&model->trajectory_list); + + model->max_forensics_count = 100; + mutex_init(&model->forensics_mutex); + INIT_LIST_HEAD(&model->forensics_list); + + mutex_init(&model->pseudonym_mutex); + INIT_LIST_HEAD(&model->pseudonym_list); + + 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_TMA_context *ctx) +{ + unsigned int cnt; + struct tsem_event_point *centry, *tmp_centry; + struct state_point *state, *tmp_state; + struct tsem_trajectory *tentry, *tmp_tentry; + struct pseudonym *sentry, *tmp_sentry; + struct tsem_model *model = ctx->model; + + cnt = 0; + list_for_each_entry_safe(centry, tmp_centry, &model->point_list, + list) { + list_del(¢ry->list); + kfree(centry); + ++cnt; + } + + cnt = 0; + list_for_each_entry_safe(state, tmp_state, &model->state_list, + list) { + list_del(&state->list); + kfree(state); + ++cnt; + } + + cnt = 0; + list_for_each_entry_safe(tentry, tmp_tentry, &model->trajectory_list, + list) { + list_del(&tentry->list); + tsem_event_put(tentry->ep); + ++cnt; + } + + cnt = 0; + list_for_each_entry_safe(sentry, tmp_sentry, &model->pseudonym_list, + list) { + list_del(&sentry->list); + kfree(sentry); + ++cnt; + } + + if (ctx->sealed) { + cnt = 0; + list_for_each_entry_safe(tentry, tmp_tentry, + &model->forensics_list, list) { + list_del(&tentry->list); + tsem_event_put(tentry->ep); + ++cnt; + } + } + + kfree(model); +} From patchwork Sat Feb 4 05:09:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. Greg" X-Patchwork-Id: 13128584 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0FAF5C636D3 for ; Sat, 4 Feb 2023 05:32:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233319AbjBDFco (ORCPT ); Sat, 4 Feb 2023 00:32:44 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43130 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232601AbjBDFcn (ORCPT ); Sat, 4 Feb 2023 00:32:43 -0500 Received: from blizzard.enjellic.com (wind.enjellic.com [76.10.64.91]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id B191A93AEC for ; Fri, 3 Feb 2023 21:32:42 -0800 (PST) Received: from blizzard.enjellic.com (localhost [127.0.0.1]) by blizzard.enjellic.com (8.15.2/8.15.2) with ESMTP id 3145A6Iq011686; Fri, 3 Feb 2023 23:10:06 -0600 Received: (from greg@localhost) by blizzard.enjellic.com (8.15.2/8.15.2/Submit) id 3145A6I5011684; Fri, 3 Feb 2023 23:10:06 -0600 X-Authentication-Warning: blizzard.enjellic.com: greg set sender to greg@enjellic.com using -f From: "Dr. Greg" To: linux-security-module@vger.kernel.org Subject: [PATCH 14/14] Activate the configuration and build of the TSEM LSM. Date: Fri, 3 Feb 2023 23:09:54 -0600 Message-Id: <20230204050954.11583-15-greg@enjellic.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230204050954.11583-1-greg@enjellic.com> References: <20230204050954.11583-1-greg@enjellic.com> MIME-Version: 1.0 Precedence: bulk List-ID: Complete the implementation by integrating the LSM into the configuration and kernel build infrastructure. Signed-off-by: Greg Wettstein --- security/Kconfig | 11 ++++++----- security/Makefile | 1 + security/tsem/Kconfig | 22 ++++++++++++++++++++++ security/tsem/Makefile | 2 ++ 4 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 security/tsem/Kconfig create mode 100644 security/tsem/Makefile diff --git a/security/Kconfig b/security/Kconfig index e6db09a779b7..98c538ad6790 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -207,6 +207,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" @@ -246,11 +247,11 @@ endchoice config LSM string "Ordered list of enabled LSMs" - default "landlock,lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK - default "landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR - default "landlock,lockdown,yama,loadpin,safesetid,integrity,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO - default "landlock,lockdown,yama,loadpin,safesetid,integrity,bpf" if DEFAULT_SECURITY_DAC - default "landlock,lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf" + default "landlock,lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf,tsem" if DEFAULT_SECURITY_SMACK + default "landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf,tsem" if DEFAULT_SECURITY_APPARMOR + default "landlock,lockdown,yama,loadpin,safesetid,integrity,tomoyo,bpf,tsem" if DEFAULT_SECURITY_TOMOYO + default "landlock,lockdown,yama,loadpin,safesetid,integrity,bpf,tsem" if DEFAULT_SECURITY_DAC + default "landlock,lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf,tsem" help A comma-separated list of LSMs, in initialization order. Any LSMs left off this list will be ignored. This can be 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..f9199686844a --- /dev/null +++ b/security/tsem/Kconfig @@ -0,0 +1,22 @@ +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. 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