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; +}