diff mbox series

[12/14] Implement security event mapping.

Message ID 20230204050954.11583-13-greg@enjellic.com (mailing list archive)
State Changes Requested
Delegated to: Paul Moore
Headers show
Series Implement Trusted Security Event Modeling. | expand

Commit Message

Dr. Greg Feb. 4, 2023, 5:09 a.m. UTC
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 <greg@enjellic.com>
---
 security/tsem/map.c | 497 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 497 insertions(+)
 create mode 100644 security/tsem/map.c
diff mbox series

Patch

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 <greg@enjellic.com>
+ *
+ * This file implements mapping of events into security event points.
+ */
+
+#include <crypto/hash.h>
+
+#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, &params);
+	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;
+}