From patchwork Thu Oct 5 18:25:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13410598 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 9B1F2E92725 for ; Thu, 5 Oct 2023 18:26:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230501AbjJES0O (ORCPT ); Thu, 5 Oct 2023 14:26:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58712 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229598AbjJES0O (ORCPT ); Thu, 5 Oct 2023 14:26:14 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 6BAC59E for ; Thu, 5 Oct 2023 11:26:12 -0700 (PDT) Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id CDEC620B74C2; Thu, 5 Oct 2023 11:26:11 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com CDEC620B74C2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1696530371; bh=JzbNPfP8rsA3zKDRhrHM4A1C1P+3asNcarWREnGnRqQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BAWgvyqCkGSAPglJFh8N+rB6X3OLX3+25r6mswkyyU3LlPgeqMJULubtEi+XYH080 76C1abZgZuKZACBOL7bLU3RYW7+3pPGptw0qBhAnISnh0XYPzSxQ2U697FoxWQgJ3e LwVe5SpHqYjwZh1BOKApY6djAo8sMhnNbRmRR90k= From: Tushar Sugandhi To: zohar@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, kexec@lists.infradead.org, linux-integrity@vger.kernel.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v2 1/7] ima: refactor ima_dump_measurement_list to move memory allocation to a separate function Date: Thu, 5 Oct 2023 11:25:56 -0700 Message-Id: <20231005182602.634615-2-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231005182602.634615-1-tusharsu@linux.microsoft.com> References: <20231005182602.634615-1-tusharsu@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org IMA allocates memory and dumps the measurement during kexec soft reboot as a single function call ima_dump_measurement_list(). It gets called during kexec 'load' operation. It results in the IMA measurements between the window of kexec 'load' and 'execute' getting dropped when the system boots into the new Kernel. One of the kexec requirements is the segment size cannot change between the 'load' and the 'execute'. Therefore, to address this problem, ima_dump_measurement_list() needs to be refactored to allocate the memory at kexec 'load', and dump the measurements at kexec 'execute'. The function that allocates the memory should handle the scenario where the kexec load is called multiple times. Refactor ima_dump_measurement_list() to move the memory allocation part to a separate function ima_alloc_kexec_buf() to allocate buffer of size 'kexec_segment_size' at kexec 'load'. Make the local variables in function ima_dump_measurement_list() global, so that they can be accessed from ima_alloc_kexec_buf(). Make necessary changes to the function ima_add_kexec_buffer() to call the above two functions. Signed-off-by: Tushar Sugandhi --- security/integrity/ima/ima_kexec.c | 126 +++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 33 deletions(-) diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 419dc405c831..307e07991865 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -15,61 +15,114 @@ #include "ima.h" #ifdef CONFIG_IMA_KEXEC +struct seq_file ima_kexec_file; +struct ima_kexec_hdr ima_khdr; + +void ima_clear_kexec_file(void) +{ + vfree(ima_kexec_file.buf); + ima_kexec_file.buf = NULL; + ima_kexec_file.size = 0; + ima_kexec_file.read_pos = 0; + ima_kexec_file.count = 0; +} + +static int ima_alloc_kexec_buf(size_t kexec_segment_size) +{ + if ((kexec_segment_size == 0) || + (kexec_segment_size == ULONG_MAX) || + ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) { + pr_err("%s: Invalid segment size for kexec: %zu\n", + __func__, kexec_segment_size); + return -EINVAL; + } + + /* + * If kexec load was called before, clear the existing buffer + * before allocating a new one + */ + if (ima_kexec_file.buf) + ima_clear_kexec_file(); + + /* segment size can't change between kexec load and execute */ + ima_kexec_file.buf = vmalloc(kexec_segment_size); + if (!ima_kexec_file.buf) { + pr_err("%s: No memory for ima kexec measurement buffer\n", + __func__); + return -ENOMEM; + } + + ima_kexec_file.size = kexec_segment_size; + ima_kexec_file.read_pos = 0; + ima_kexec_file.count = sizeof(ima_khdr); /* reserved space */ + + memset(&ima_khdr, 0, sizeof(ima_khdr)); + ima_khdr.version = 1; + + return 0; +} + static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, unsigned long segment_size) { struct ima_queue_entry *qe; - struct seq_file file; - struct ima_kexec_hdr khdr; int ret = 0; - /* segment size can't change between kexec load and execute */ - file.buf = vmalloc(segment_size); - if (!file.buf) { - ret = -ENOMEM; - goto out; + if (!ima_kexec_file.buf) { + pr_err("%s: Kexec file buf not allocated\n", + __func__); + return -EINVAL; } - file.size = segment_size; - file.read_pos = 0; - file.count = sizeof(khdr); /* reserved space */ + /* + * Ensure the kexec buffer is large enough to hold ima_khdr + */ + if (ima_kexec_file.size < sizeof(ima_khdr)) { + pr_err("%s: Kexec buffer size too low to hold ima_khdr\n", + __func__); + ima_clear_kexec_file(); + return -ENOMEM; + } - memset(&khdr, 0, sizeof(khdr)); - khdr.version = 1; + /* + * If we reach here, then there is enough memory + * of size kexec_segment_size in ima_kexec_file.buf + * to copy at least partial IMA log. + * Make best effort to copy as many IMA measurements + * as possible. + */ list_for_each_entry_rcu(qe, &ima_measurements, later) { - if (file.count < file.size) { - khdr.count++; - ima_measurements_show(&file, qe); + if (ima_kexec_file.count < ima_kexec_file.size) { + ima_khdr.count++; + ima_measurements_show(&ima_kexec_file, qe); } else { - ret = -EINVAL; + ret = EFBIG; + pr_err("%s: IMA log file is too big for Kexec buf\n", + __func__); break; } } - if (ret < 0) - goto out; - /* * fill in reserved space with some buffer details * (eg. version, buffer size, number of measurements) */ - khdr.buffer_size = file.count; + ima_khdr.buffer_size = ima_kexec_file.count; if (ima_canonical_fmt) { - khdr.version = cpu_to_le16(khdr.version); - khdr.count = cpu_to_le64(khdr.count); - khdr.buffer_size = cpu_to_le64(khdr.buffer_size); + ima_khdr.version = cpu_to_le16(ima_khdr.version); + ima_khdr.count = cpu_to_le64(ima_khdr.count); + ima_khdr.buffer_size = cpu_to_le64(ima_khdr.buffer_size); } - memcpy(file.buf, &khdr, sizeof(khdr)); + memcpy(ima_kexec_file.buf, &ima_khdr, sizeof(ima_khdr)); print_hex_dump_debug("ima dump: ", DUMP_PREFIX_NONE, 16, 1, - file.buf, file.count < 100 ? file.count : 100, + ima_kexec_file.buf, ima_kexec_file.count < 100 ? + ima_kexec_file.count : 100, true); - *buffer_size = file.count; - *buffer = file.buf; -out: - if (ret == -EINVAL) - vfree(file.buf); + *buffer_size = ima_kexec_file.count; + *buffer = ima_kexec_file.buf; + return ret; } @@ -108,13 +161,20 @@ void ima_add_kexec_buffer(struct kimage *image) return; } - ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, - kexec_segment_size); - if (!kexec_buffer) { + ret = ima_alloc_kexec_buf(kexec_segment_size); + if (ret < 0) { pr_err("Not enough memory for the kexec measurement buffer.\n"); return; } + ret = ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, + kexec_segment_size); + if (ret < 0) { + pr_err("%s: Failed to dump IMA measurements. Error:%d.\n", + __func__, ret); + return; + } + kbuf.buffer = kexec_buffer; kbuf.bufsz = kexec_buffer_size; kbuf.memsz = kexec_segment_size; From patchwork Thu Oct 5 18:25:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13410601 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 3D203E92727 for ; Thu, 5 Oct 2023 18:26:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231182AbjJES0P (ORCPT ); Thu, 5 Oct 2023 14:26:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230520AbjJES0O (ORCPT ); Thu, 5 Oct 2023 14:26:14 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 6E0079F for ; Thu, 5 Oct 2023 11:26:13 -0700 (PDT) Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 40C5D20B74C3; Thu, 5 Oct 2023 11:26:12 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 40C5D20B74C3 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1696530372; bh=jTgIKen7lOsEgySVaootVrx/1KoXxKlHIzYHAp+LQX8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IKHGNshri6kq4ulxSHipZH9PjQLTb2G0gVRuVEgo13Amyndbvug3oV9DlxA7IuV36 Sgqvq7nl/l6i9WtZfRCS3zH6JvwkkT9sCdDv2AK46gxEGkVc1RVT7XGzv1Tw2m79Wf LzF+CQFcB4Z/syEzcGfaC62Sn1xBeft+C0kZ0+b8= From: Tushar Sugandhi To: zohar@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, kexec@lists.infradead.org, linux-integrity@vger.kernel.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v2 2/7] ima: move ima_dump_measurement_list call from kexec load to execute Date: Thu, 5 Oct 2023 11:25:57 -0700 Message-Id: <20231005182602.634615-3-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231005182602.634615-1-tusharsu@linux.microsoft.com> References: <20231005182602.634615-1-tusharsu@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org In the current IMA implementation, ima_dump_measurement_list() is called during the kexec 'load' operation. This can result in loss of IMA measurements taken between the 'load' and 'execute' phases when the system goes through Kexec soft reboot to a new Kernel. The call to the function ima_dump_measurement_list() needs to be moved out of the function ima_add_kexec_buffer() and needs to be called during the kexec 'execute' operation. Implement a function ima_update_kexec_buffer() that is called during kexec 'execute', allowing IMA to update the measurement list with the events between kexec 'load' and 'execute'. Move the ima_dump_measurement_list() call from ima_add_kexec_buffer() to ima_update_kexec_buffer(). Make ima_kexec_buffer and kexec_segment_size variables global, so that they can be accessed during both kexec 'load' and 'execute'. Add functions ima_measurements_suspend() and ima_measurements_resume() to set and reset the 'suspend_ima_measurements' variable respectively, to suspend/resume IMA measurements. Use the existing 'ima_extend_list_mutex' to ensure that the operations are thread-safe. These function calls will help maintaining the integrity of the IMA log while it is being copied to the new Kernel's buffer. Add a reboot notifier_block 'update_buffer_nb' to ensure the function ima_update_kexec_buffer() gets called during kexec soft-reboot. Signed-off-by: Tushar Sugandhi --- security/integrity/ima/ima.h | 2 ++ security/integrity/ima/ima_kexec.c | 58 +++++++++++++++++++++++++----- security/integrity/ima/ima_queue.c | 18 ++++++++++ 3 files changed, 69 insertions(+), 9 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index c29db699c996..49a6047dd8eb 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -161,6 +161,8 @@ bool ima_template_has_modsig(const struct ima_template_desc *ima_template); int ima_restore_measurement_entry(struct ima_template_entry *entry); int ima_restore_measurement_list(loff_t bufsize, void *buf); int ima_measurements_show(struct seq_file *m, void *v); +void ima_measurements_suspend(void); +void ima_measurements_resume(void); unsigned long ima_get_binary_runtime_size(void); int ima_init_template(void); void ima_init_template_list(void); diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 307e07991865..2c11bbe6efef 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -17,6 +17,8 @@ #ifdef CONFIG_IMA_KEXEC struct seq_file ima_kexec_file; struct ima_kexec_hdr ima_khdr; +static void *ima_kexec_buffer; +static size_t kexec_segment_size; void ima_clear_kexec_file(void) { @@ -142,7 +144,6 @@ void ima_add_kexec_buffer(struct kimage *image) /* use more understandable variable names than defined in kbuf */ void *kexec_buffer = NULL; size_t kexec_buffer_size; - size_t kexec_segment_size; int ret; /* @@ -167,14 +168,6 @@ void ima_add_kexec_buffer(struct kimage *image) return; } - ret = ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, - kexec_segment_size); - if (ret < 0) { - pr_err("%s: Failed to dump IMA measurements. Error:%d.\n", - __func__, ret); - return; - } - kbuf.buffer = kexec_buffer; kbuf.bufsz = kexec_buffer_size; kbuf.memsz = kexec_segment_size; @@ -192,6 +185,53 @@ void ima_add_kexec_buffer(struct kimage *image) pr_debug("kexec measurement buffer for the loaded kernel at 0x%lx.\n", kbuf.mem); } + +/* + * Called during kexec execute so that IMA can update the measurement list. + */ +static int ima_update_kexec_buffer(struct notifier_block *self, + unsigned long action, void *data) +{ + void *buf = NULL; + size_t buf_size; + bool resume = false; + int ret; + + if (!kexec_in_progress) { + pr_info("%s: No kexec in progress.\n", __func__); + return NOTIFY_OK; + } + + if (!ima_kexec_buffer) { + pr_err("%s: Kexec buffer not set.\n", __func__); + return NOTIFY_OK; + } + + ima_measurements_suspend(); + + buf_size = ima_get_binary_runtime_size(); + ret = ima_dump_measurement_list(&buf_size, &buf, + kexec_segment_size); + + if (!buf || ret < 0) { + pr_err("%s: Dump measurements failed. Error:%d\n", + __func__, ret); + resume = true; + goto out; + } + memcpy(ima_kexec_buffer, buf, buf_size); +out: + ima_kexec_buffer = NULL; + + if (resume) + ima_measurements_resume(); + + return NOTIFY_OK; +} +struct notifier_block update_buffer_nb = { + .notifier_call = ima_update_kexec_buffer, +}; + #endif /* IMA_KEXEC */ /* diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 532da87ce519..9e7d1196006e 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -44,6 +44,11 @@ struct ima_h_table ima_htable = { */ static DEFINE_MUTEX(ima_extend_list_mutex); +/* + * Used internally by the kernel to suspend-resume ima measurements. + */ +static atomic_t suspend_ima_measurements; + /* lookup up the digest value in the hash table, and return the entry */ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, int pcr) @@ -147,6 +152,19 @@ static int ima_pcr_extend(struct tpm_digest *digests_arg, int pcr) pr_err("Error Communicating to TPM chip, result: %d\n", result); return result; } +void ima_measurements_suspend(void) +{ + mutex_lock(&ima_extend_list_mutex); + atomic_set(&suspend_ima_measurements, 1); + mutex_unlock(&ima_extend_list_mutex); +} + +void ima_measurements_resume(void) +{ + mutex_lock(&ima_extend_list_mutex); + atomic_set(&suspend_ima_measurements, 0); + mutex_unlock(&ima_extend_list_mutex); +} /* * Add template entry to the measurement list and hash table, and From patchwork Thu Oct 5 18:25:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13410603 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 30BA1E9272A for ; Thu, 5 Oct 2023 18:26:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230520AbjJES0Q (ORCPT ); Thu, 5 Oct 2023 14:26:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58788 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231201AbjJES0P (ORCPT ); Thu, 5 Oct 2023 14:26:15 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id F0681A6 for ; Thu, 5 Oct 2023 11:26:13 -0700 (PDT) Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id DFC1C20B74C4; Thu, 5 Oct 2023 11:26:12 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com DFC1C20B74C4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1696530373; bh=j+IdX/spgg7Wp+R25BM5nIX45tDvZ4b/lZmw9PEsJCw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cfqWocvHf5ixHq6I905i8+Bg3nWnYv1oIgvbyimnjbEtNYfTp0bT7K7OzElIlywI9 nHMAZJi7bsZ2n/Z7MQeGaz8BR454DuBNWtJhUa/YKqpnF0DK4gC4ot0tIXV2oMHt7D FLZnH6FKEl3AAylwPWAtkeYjGEvBqn+9cWnd5lJU= From: Tushar Sugandhi To: zohar@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, kexec@lists.infradead.org, linux-integrity@vger.kernel.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v2 3/7] ima: kexec: map source pages containing IMA buffer to image post kexec load Date: Thu, 5 Oct 2023 11:25:58 -0700 Message-Id: <20231005182602.634615-4-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231005182602.634615-1-tusharsu@linux.microsoft.com> References: <20231005182602.634615-1-tusharsu@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org Currently, the mechanism to map and unmap segments to the kimage structure is not available to the subsystems outside of kexec. This functionality is needed when IMA is allocating the memory segments during kexec 'load' operation. Implement kimage_map_segment() which takes a kimage pointer, an address, and a size. Ensure that the entire segment is being mapped by comparing the given address and size to each segment in the kimage's segment array. Collect the source pages that correspond to the given address range, allocate an array of pointers to these pages, and map them to a contiguous range of virtual addresses. If the mapping operation is successful, the function returns the start of this range. Otherwise, it frees the page pointer array and returns NULL. Implement kimage_unmap_segment() that takes a pointer to a segment buffer and unmaps it using vunmap(). Implement function ima_kexec_post_load(), to be called by IMA after kexec loads the new Kernel image. ima_kexec_post_load() would map the IMA buffer allocated during kexec 'load' to a segment in the loaded image. Finally, move for_each_kimage_entry() macro from kexec_core.c to kexec.h. Signed-off-by: Tushar Sugandhi --- include/linux/ima.h | 3 ++ include/linux/kexec.h | 13 ++++++ kernel/kexec_core.c | 73 ++++++++++++++++++++++++++++-- security/integrity/ima/ima_kexec.c | 32 +++++++++++++ 4 files changed, 116 insertions(+), 5 deletions(-) diff --git a/include/linux/ima.h b/include/linux/ima.h index 86b57757c7b1..006db20f852d 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -49,6 +49,9 @@ static inline void ima_appraise_parse_cmdline(void) {} #ifdef CONFIG_IMA_KEXEC extern void ima_add_kexec_buffer(struct kimage *image); +extern void ima_kexec_post_load(struct kimage *image); +#else +static inline void ima_kexec_post_load(struct kimage *image) {} #endif #else diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 22b5cd24f581..e00b8101b53b 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -490,6 +490,15 @@ static inline int arch_kexec_post_alloc_pages(void *vaddr, unsigned int pages, g static inline void arch_kexec_pre_free_pages(void *vaddr, unsigned int pages) { } #endif +#define for_each_kimage_entry(image, ptr, entry) \ + for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ + ptr = (entry & IND_INDIRECTION) ? \ + boot_phys_to_virt((entry & PAGE_MASK)) : ptr + 1) + +extern void *kimage_map_segment(struct kimage *image, + unsigned long addr, unsigned long size); +extern void kimage_unmap_segment(void *buffer); + #else /* !CONFIG_KEXEC_CORE */ struct pt_regs; struct task_struct; @@ -497,6 +506,10 @@ static inline void __crash_kexec(struct pt_regs *regs) { } static inline void crash_kexec(struct pt_regs *regs) { } static inline int kexec_should_crash(struct task_struct *p) { return 0; } static inline int kexec_crash_loaded(void) { return 0; } +static inline void *kimage_map_segment(struct kimage *image, + unsigned long addr, unsigned long size) +{ return NULL; } +static inline void kimage_unmap_segment(void *buffer) { } #define kexec_in_progress false #endif /* CONFIG_KEXEC_CORE */ diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 3d578c6fefee..e01156f3c404 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -594,11 +594,6 @@ void kimage_terminate(struct kimage *image) *image->entry = IND_DONE; } -#define for_each_kimage_entry(image, ptr, entry) \ - for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ - ptr = (entry & IND_INDIRECTION) ? \ - boot_phys_to_virt((entry & PAGE_MASK)) : ptr + 1) - static void kimage_free_entry(kimage_entry_t entry) { struct page *page; @@ -921,6 +916,74 @@ int kimage_load_segment(struct kimage *image, return result; } +void *kimage_map_segment(struct kimage *image, + unsigned long addr, unsigned long size) +{ + unsigned long eaddr = addr + size; + unsigned long src_page_addr, dest_page_addr; + struct page **src_pages; + int i, npages; + kimage_entry_t *ptr, entry; + void *vaddr = NULL; + + /* + * Make sure that we are mapping a whole segment. + */ + for (i = 0; i < image->nr_segments; i++) { + if (addr == image->segment[i].mem && + size == image->segment[i].memsz) { + break; + } + } + + if (i == image->nr_segments) { + pr_err("%s: No segment matching [%lx, %lx)\n", __func__, + addr, eaddr); + return NULL; + } + + /* + * Collect the source pages and map them in a contiguous VA range. + */ + npages = PFN_UP(eaddr) - PFN_DOWN(addr); + src_pages = kmalloc(sizeof(*src_pages) * npages, GFP_KERNEL); + if (!src_pages) { + pr_err("%s: Could not allocate ima pages array.\n", __func__); + return NULL; + } + + i = 0; + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_DESTINATION) + dest_page_addr = entry & PAGE_MASK; + else if (entry & IND_SOURCE) { + if (dest_page_addr >= addr && dest_page_addr < eaddr) { + src_page_addr = entry & PAGE_MASK; + src_pages[i++] = + virt_to_page(__va(src_page_addr)); + if (i == npages) + break; + dest_page_addr += PAGE_SIZE; + } + } + } + + /* Sanity check. */ + WARN_ON(i < npages); + + vaddr = vmap(src_pages, npages, VM_MAP, PAGE_KERNEL); + if (!vaddr) { + pr_err("%s: Could not map imap buffer.\n", __func__); + kfree(src_pages); + } + return vaddr; +} + +void kimage_unmap_segment(void *segment_buffer) +{ + vunmap(segment_buffer); +} + struct kexec_load_limit { /* Mutex protects the limit count. */ struct mutex mutex; diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 2c11bbe6efef..13fbbb90319b 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include "ima.h" #ifdef CONFIG_IMA_KEXEC @@ -19,6 +21,7 @@ struct seq_file ima_kexec_file; struct ima_kexec_hdr ima_khdr; static void *ima_kexec_buffer; static size_t kexec_segment_size; +static bool ima_kexec_update_registered; void ima_clear_kexec_file(void) { @@ -221,6 +224,7 @@ static int ima_update_kexec_buffer(struct notifier_block *self, } memcpy(ima_kexec_buffer, buf, buf_size); out: + kimage_unmap_segment(ima_kexec_buffer); ima_kexec_buffer = NULL; if (resume) @@ -232,6 +236,34 @@ struct notifier_block update_buffer_nb = { .notifier_call = ima_update_kexec_buffer, }; +/* + * Create a mapping for the source pages that contain the IMA buffer + * so we can update it later. + */ +void ima_kexec_post_load(struct kimage *image) +{ + if (ima_kexec_buffer) { + kimage_unmap_segment(ima_kexec_buffer); + ima_kexec_buffer = NULL; + } + + if (!image->ima_buffer_addr) + return; + + ima_kexec_buffer = kimage_map_segment(image, + image->ima_buffer_addr, + image->ima_buffer_size); + if (!ima_kexec_buffer) { + pr_err("%s: Could not map measurements buffer.\n", __func__); + return; + } + + if (!ima_kexec_update_registered) { + register_reboot_notifier(&update_buffer_nb); + ima_kexec_update_registered = true; + } +} + #endif /* IMA_KEXEC */ /* From patchwork Thu Oct 5 18:25:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13410600 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 2E41AE92726 for ; Thu, 5 Oct 2023 18:26:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229598AbjJES0P (ORCPT ); Thu, 5 Oct 2023 14:26:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58730 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231179AbjJES0O (ORCPT ); Thu, 5 Oct 2023 14:26:14 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id F0C26AB for ; Thu, 5 Oct 2023 11:26:13 -0700 (PDT) Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 4FD0220B74C5; Thu, 5 Oct 2023 11:26:13 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 4FD0220B74C5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1696530373; bh=Udqv0jaboMhxWHknI6g5+GDLvPqkVFywTKuSTdC2gbc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LqSMC7bERhS0/N9DffbA9GM3BY+SW1tOE0W+Jh2x5uqnVbKTyjgIlB8ngOwdezyxc 05WBHartxAG3n2JcJcb1tcSE44PT/HLgJLdRVwqlRLdkRSonltLyrengvISLxTUMXq GQLsQf09S+iFLhmHqu/NN8s7Dv/zDE6kxL+QPpRI= From: Tushar Sugandhi To: zohar@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, kexec@lists.infradead.org, linux-integrity@vger.kernel.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v2 4/7] kexec: update kexec_file_load syscall to call ima_kexec_post_load Date: Thu, 5 Oct 2023 11:25:59 -0700 Message-Id: <20231005182602.634615-5-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231005182602.634615-1-tusharsu@linux.microsoft.com> References: <20231005182602.634615-1-tusharsu@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org The kexec_file_load() syscall is used to load a new Kernel for kexec. The syscall needs to be updated to call ima_kexec_post_load(), which was implemented in a previous patch. ima_kexec_post_load() should take care of mapping the IMA log buffer segment into the next Kernel. It should also register a reboot notifier which would call a function to dump the IMA measurements into IMA log buffer segment during kexec soft reboot. Modify the kexec_file_load() syscall to call ima_kexec_post_load() after the image has been loaded and prepared for kexec. This ensures that the IMA measurement list will be available to the next Kernel after a kexec soft reboot. This also ensures the measurements taken in the window between kexec 'load' and 'execute' are captured and passed to the next Kernel. Signed-off-by: Tushar Sugandhi --- kernel/kexec_file.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index f989f5f1933b..617dbbb6e46d 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -184,6 +184,11 @@ kimage_validate_signature(struct kimage *image) } #endif +void kimage_file_post_load(struct kimage *image) +{ + ima_kexec_post_load(image); +} + /* * In file mode list of segments is prepared by kernel. Copy relevant * data from user space, do error checking, prepare segment list @@ -399,6 +404,9 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, kimage_terminate(image); + if (!(flags & KEXEC_FILE_ON_CRASH)) + kimage_file_post_load(image); + ret = machine_kexec_post_load(image); if (ret) goto out; From patchwork Thu Oct 5 18:26:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13410599 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 BC861E92728 for ; Thu, 5 Oct 2023 18:26:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231179AbjJES0Q (ORCPT ); Thu, 5 Oct 2023 14:26:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58756 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231186AbjJES0P (ORCPT ); Thu, 5 Oct 2023 14:26:15 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 42FA198 for ; Thu, 5 Oct 2023 11:26:14 -0700 (PDT) Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 8025220B74C6; Thu, 5 Oct 2023 11:26:13 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8025220B74C6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1696530373; bh=VHNJbkXP2Wry2HZE8GFrjvOrwKghhTsyMpLWbzjkl+M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=go0HoJpMCMDS37lqZY/AWEAnteVK7SZ8Pu5nQ+9OUg2hBmxs6KzaThIisRqotOFis RgsehbUgEef832IKkBFEMaGEHRUc1jjwNvC6cawb2MJulGBFhV2tKUamXv7PfMrpQZ SyjCfFxscPStx+asUk7fVKQFrpf+9cEOHgBHDeDs= From: Tushar Sugandhi To: zohar@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, kexec@lists.infradead.org, linux-integrity@vger.kernel.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v2 5/7] ima: suspend measurements while the buffer is being copied during kexec reboot Date: Thu, 5 Oct 2023 11:26:00 -0700 Message-Id: <20231005182602.634615-6-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231005182602.634615-1-tusharsu@linux.microsoft.com> References: <20231005182602.634615-1-tusharsu@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org If the new measurements are added to the IMA log while it is being being copied to the kexec buffer during kexec 'execute', it can miss copying those new measurements to the kexec buffer, and the buffer can go out of sync with TPM PCRs. This could result in breaking the integrity of the measurements after the kexec soft reboot to the new Kernel. Add a check in the ima_add_template_entry() function not to measure events and return from the function early when 'suspend_ima_measurements' flag is set. This ensures the consistency of the IMA measurement list while copying them to the kexec buffer. When the 'suspend_ima_measurements' flag is set, any new measurements will be ignored until the flag is unset. This allows the buffer to be safely copied without worrying about concurrent modifications to the measurement list. This is crucial for maintaining the integrity of the measurements during a kexec soft reboot. Signed-off-by: Tushar Sugandhi --- security/integrity/ima/ima_queue.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 9e7d1196006e..498b6b92f3f0 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -194,6 +194,19 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, } } + /* + * suspend_ima_measurements will be set if the system is + * undergoing kexec soft boot to a new kernel. + * suspending measurements in this short window ensures the + * consistency of the IMA measurement list during copying + * of the kexec buffer. + */ + if (atomic_read(&suspend_ima_measurements)) { + audit_cause = "measurements_suspended"; + audit_info = 0; + goto out; + } + result = ima_add_digest_entry(entry, !IS_ENABLED(CONFIG_IMA_DISABLE_HTABLE)); if (result < 0) { From patchwork Thu Oct 5 18:26:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13410602 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 A9900E92729 for ; Thu, 5 Oct 2023 18:26:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231201AbjJES0Q (ORCPT ); Thu, 5 Oct 2023 14:26:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58770 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231208AbjJES0P (ORCPT ); Thu, 5 Oct 2023 14:26:15 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id A61D69E for ; Thu, 5 Oct 2023 11:26:14 -0700 (PDT) Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 261C320B74C7; Thu, 5 Oct 2023 11:26:13 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 261C320B74C7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1696530374; bh=8DnZqCRLNl2kH912XJt+JUclDDYq4fKWT4+5FgK5Duw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=F2PI4GCwKQxYpriwcXUCTi9/ezNh0cgu0fXOh1iGEhpLBtzp1+sGIc/XItOPZMIPa JscSayHolG3wD/1ah2wKfuhJegtnChjdXsHkk8a81PNU1rjDbCGNCkGQtMHb0522mG gFyoRjBookAHHwQPwok5P3wOrm73/P+dT1G8Xx8s= From: Tushar Sugandhi To: zohar@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, kexec@lists.infradead.org, linux-integrity@vger.kernel.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v2 6/7] ima: make the memory for events between kexec load and exec configurable Date: Thu, 5 Oct 2023 11:26:01 -0700 Message-Id: <20231005182602.634615-7-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231005182602.634615-1-tusharsu@linux.microsoft.com> References: <20231005182602.634615-1-tusharsu@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org IMA currently allocates half a PAGE_SIZE for the extra events that would be measured between kexec 'load' and 'execute'. Depending on the IMA policy and the system state, that memory may not be sufficient to hold the extra IMA events measured after kexec 'load'. The memory requirements vary from system to system and they should be configurable. Define a Kconfig option, IMA_KEXEC_EXTRA_PAGES, to configure the number of extra pages to be allocated for IMA measurements added in the window from kexec 'load' to kexec 'execute'. Update ima_add_kexec_buffer() function to allocate memory based on the Kconfig option value, rather than the currently hardcoded one. Signed-off-by: Tushar Sugandhi --- security/integrity/ima/Kconfig | 9 +++++++++ security/integrity/ima/ima_kexec.c | 13 ++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 60a511c6b583..1b55cd2bcb36 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -338,3 +338,12 @@ config IMA_DISABLE_HTABLE default n help This option disables htable to allow measurement of duplicate records. + +config IMA_KEXEC_EXTRA_PAGES + int + depends on IMA && IMA_KEXEC + default 16 + help + IMA_KEXEC_EXTRA_PAGES determines the number of extra + pages to be allocated for IMA measurements added in the + window from kexec 'load' to kexec 'execute'. diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 13fbbb90319b..6cd5f46a7208 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -150,15 +150,18 @@ void ima_add_kexec_buffer(struct kimage *image) int ret; /* - * Reserve an extra half page of memory for additional measurements - * added during the kexec load. + * Reserve extra memory for measurements added in the window from + * kexec 'load' to kexec 'execute'. */ - binary_runtime_size = ima_get_binary_runtime_size(); + binary_runtime_size = ima_get_binary_runtime_size() + + sizeof(struct ima_kexec_hdr) + + (CONFIG_IMA_KEXEC_EXTRA_PAGES * PAGE_SIZE); + if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE) kexec_segment_size = ULONG_MAX; else - kexec_segment_size = ALIGN(ima_get_binary_runtime_size() + - PAGE_SIZE / 2, PAGE_SIZE); + kexec_segment_size = ALIGN(binary_runtime_size, PAGE_SIZE); + if ((kexec_segment_size == ULONG_MAX) || ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) { pr_err("Binary measurement list too large.\n"); From patchwork Thu Oct 5 18:26:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tushar Sugandhi X-Patchwork-Id: 13410604 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 34B45E9272C for ; Thu, 5 Oct 2023 18:26:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231208AbjJES0R (ORCPT ); Thu, 5 Oct 2023 14:26:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231213AbjJES0Q (ORCPT ); Thu, 5 Oct 2023 14:26:16 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id D8EA1AD for ; Thu, 5 Oct 2023 11:26:14 -0700 (PDT) Received: from tushar-HP-Pavilion-Laptop-15-eg0xxx.lan (unknown [50.46.228.62]) by linux.microsoft.com (Postfix) with ESMTPSA id 56F0320B74C8; Thu, 5 Oct 2023 11:26:14 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 56F0320B74C8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1696530374; bh=ONPFQaah0h6Qnqt+reZDLhqeK6cEMyobvmiL4JTQPwA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=g+RGV187kcOPOb2HX1ww0wYPY37J26ztVbuioeuEk33iG+u0PvGcUg5Wrr+U6DFai b1TXW8XvGSpWFEC6BDw1LzfeWeJOU/rTi8vNryDYwCv3D1QOLkpPUnbnsQG4nZfUUN ijrhjYLOd/u0/gKSOjVCFkCzJSIULCxbjyrlPyoM= From: Tushar Sugandhi To: zohar@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, kexec@lists.infradead.org, linux-integrity@vger.kernel.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v2 7/7] ima: record log size at kexec load and execute Date: Thu, 5 Oct 2023 11:26:02 -0700 Message-Id: <20231005182602.634615-8-tusharsu@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231005182602.634615-1-tusharsu@linux.microsoft.com> References: <20231005182602.634615-1-tusharsu@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org The window between kexec 'load' and 'execute' could be arbitrarily long. Even with the large chunk of memory allocated at kexec 'load', it may run out which would result in missing events in IMA log after the system soft reboots to the new Kernel. This would result in IMA measurements getting out of sync with the TPM PCR quotes which would result in remote attestation failing for that system. There is currently no way for the new Kernel to know if the IMA log TPM PCR quote out of sync problem is because of the missing measurements during kexec. Define two new IMA events, 'kexec_load' and 'kexec_execute', to be measured at kexec 'load' and 'execute' respectively. IMA measures 'boot_aggregate' as the first event when the system boots - either cold boot or kexec soft boot. In case when the system goes through multiple soft reboots, the number of 'boot_aggregate' events in IMA log corresponds to total number of boots (cold boot plus multiple kexec soft reboots). With this change, there would be additional 'kexec_load' and 'kexec_execute' events in between the two 'boot_aggregate' events. In rare cases, when the system runs out of memory during kexec soft reboot, 'kexec_execute' won't be copied since its one of the very last event measured just before kexec soft reboot. The absence of the event 'kexec_execute' in between the two boot_aggregate' events would signal the attestation service that the IMA log on the system is out of sync with TPM PCR quotes and the system needs to be cold booted for the remote attestation to succeed again. Signed-off-by: Tushar Sugandhi --- security/integrity/ima/ima_kexec.c | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 6cd5f46a7208..0f9c424fe808 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -17,6 +17,8 @@ #include "ima.h" #ifdef CONFIG_IMA_KEXEC +#define IMA_KEXEC_EVENT_LEN 128 + struct seq_file ima_kexec_file; struct ima_kexec_hdr ima_khdr; static void *ima_kexec_buffer; @@ -34,6 +36,8 @@ void ima_clear_kexec_file(void) static int ima_alloc_kexec_buf(size_t kexec_segment_size) { + char ima_kexec_event[IMA_KEXEC_EVENT_LEN]; + if ((kexec_segment_size == 0) || (kexec_segment_size == ULONG_MAX) || ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) { @@ -64,6 +68,12 @@ static int ima_alloc_kexec_buf(size_t kexec_segment_size) memset(&ima_khdr, 0, sizeof(ima_khdr)); ima_khdr.version = 1; + scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN, + "kexec_segment_size=%lu;", kexec_segment_size); + + ima_measure_critical_data("ima_kexec", "kexec_load", ima_kexec_event, + strlen(ima_kexec_event), false, NULL, 0); + return 0; } @@ -198,6 +208,7 @@ void ima_add_kexec_buffer(struct kimage *image) static int ima_update_kexec_buffer(struct notifier_block *self, unsigned long action, void *data) { + char ima_kexec_event[IMA_KEXEC_EVENT_LEN]; void *buf = NULL; size_t buf_size; bool resume = false; @@ -213,9 +224,31 @@ static int ima_update_kexec_buffer(struct notifier_block *self, return NOTIFY_OK; } + buf_size = ima_get_binary_runtime_size(); + scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN, + "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;", + kexec_segment_size, buf_size); + + /* + * This is one of the very last events measured by IMA before kexec + * soft rebooting into the new Kernal. + * This event can be used as a marker after the system soft reboots + * to the new Kernel to check if there was sufficient memory allocated + * at kexec 'load' to capture the events measured between the window + * of kexec 'load' and 'execute'. + * This event needs to be present in the IMA log, in between the two + * 'boot_aggregate' events that are logged for the previous boot and + * the current soft reboot. If it is not present after the system soft + * reboots into the new Kernel, it would mean the IMA log is not + * consistent with the TPM PCR quotes, and the system needs to be + * cold-booted for the attestation to succeed again. + */ + ima_measure_critical_data("ima_kexec", "kexec_execute", + ima_kexec_event, strlen(ima_kexec_event), + false, NULL, 0); + ima_measurements_suspend(); - buf_size = ima_get_binary_runtime_size(); ret = ima_dump_measurement_list(&buf_size, &buf, kexec_segment_size);