From patchwork Mon Feb 3 23:20:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: steven chen X-Patchwork-Id: 13958392 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5F2011FFC71; Mon, 3 Feb 2025 23:20:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624843; cv=none; b=YPljE3hLqOJurbJU7Cz+pOGthpdOlV7suUeGRkPWu8Ql1LDbLX2eTe05wL2DGHfxuziT3fE2dNk/nb8YvmPE7SAp4c7/PN8+Y8B1vo5EWAO5GjYQAA4Z3QM1k9CkhMQx834EBLV7jQtQoCExlZJzip36+Yj2y/vFrW/b8iecioU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624843; c=relaxed/simple; bh=Ckw2SdcMshoLK5M1DqU4ul3lnClo0tYVfVa1/aedS14=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=LK2/UsKSYdBgnz5udGepqxcshzeZoFHGHTbKOp9f99ej+9hKJojbgsXuaMfqAFEsOS+6IUY9kS2zGfX9wUZwy19PUEtH1EgKBRgkFjX5feoHW4xe4eXj+k/xgYee4umfyquGPyc30yJi8Bg8Zl6wFCykzW0L42ZFzY/nfge5RJE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=qOV6M7LV; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="qOV6M7LV" Received: from localhost.localdomain (unknown [167.220.59.4]) by linux.microsoft.com (Postfix) with ESMTPSA id C72F1205493C; Mon, 3 Feb 2025 15:20:40 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com C72F1205493C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1738624840; bh=DwTIiVhUQSRukvrNOWSPzDC+an9T5YM/JpQkQduIjo4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qOV6M7LV3usmDdcfVH31Xsy4vXRWWGzXIXuqnjXpRN2EoFMPVBGZl7FUF5fTSQZDA fe2U8+rvrB4fvkG5/K7Gb3fp09moW3ffMZLF1niZcgirn/tkXAX9s9SIhQLjJ7dd/6 QBe2vs0AnWMvhizFwPR6tEIbjoXjjHvOsHOb0ZwI= From: steven chen To: zohar@linux.ibm.com, stefanb@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, ebiederm@xmission.com, paul@paul-moore.com, code@tyhicks.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, chenste@linux.microsoft.com Cc: madvenka@linux.microsoft.com, nramas@linux.microsoft.com, James.Bottomley@HansenPartnership.com Subject: [PATCH v7 1/7] ima: define and call ima_alloc_kexec_file_buf Date: Mon, 3 Feb 2025 15:20:26 -0800 Message-Id: <20250203232033.64123-2-chenste@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250203232033.64123-1-chenste@linux.microsoft.com> References: <20250203232033.64123-1-chenste@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Carrying the IMA measurement list across kexec requires allocating a buffer and copying the measurement records. Separate allocating the buffer and copying the measurement records into separate functions in order to allocate the buffer at kexec 'load' and copy the measurements at kexec 'execute'. This patch includes the following changes: - Refactor ima_dump_measurement_list() to move the memory allocation to a separate function ima_alloc_kexec_file_buf() which allocates buffer of size 'kexec_segment_size' at kexec 'load'. - Make the local variable ima_kexec_file in ima_dump_measurement_list() a local static to the file, so that it can be accessed from ima_alloc_kexec_file_buf(). Compare actual memory required to ensure there is enough memory for the entire measurement record. - Copy as many measurement events as possible. - Make necessary changes to the function ima_add_kexec_buffer() to call the above two functions. - Compared the memory size allocated with memory size of the entire measurement record. If there is not enough memory, it will copy as many IMA measurement records as possible, and this situation will result in a failure of remote attestation. Author: Tushar Sugandhi Reviewed-by: Stefan Berger Suggested-by: Mimi Zohar Signed-off-by: Tushar Sugandhi Signed-off-by: steven chen --- security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_kexec.c | 105 +++++++++++++++++++++-------- security/integrity/ima/ima_queue.c | 4 +- 3 files changed, 80 insertions(+), 30 deletions(-) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 3c323ca213d4..447a6eb07c2d 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -274,6 +274,7 @@ 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); +int ima_get_binary_runtime_entry_size(struct ima_template_entry *entry); 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 52e00332defe..b60a902460e2 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -15,62 +15,99 @@ #include "ima.h" #ifdef CONFIG_IMA_KEXEC +static struct seq_file ima_kexec_file; + +static void ima_reset_kexec_file(struct seq_file *sf) +{ + sf->buf = NULL; + sf->size = 0; + sf->read_pos = 0; + sf->count = 0; +} + +static void ima_free_kexec_file_buf(struct seq_file *sf) +{ + vfree(sf->buf); + ima_reset_kexec_file(sf); +} + +static int ima_alloc_kexec_file_buf(size_t segment_size) +{ + /* + * kexec 'load' may be called multiple times. + * Free and realloc the buffer only if the segment_size is + * changed from the previous kexec 'load' call. + */ + if (ima_kexec_file.buf && + (ima_kexec_file.size == segment_size)) { + goto out; + } + + ima_free_kexec_file_buf(&ima_kexec_file); + + /* segment size can't change between kexec load and execute */ + ima_kexec_file.buf = vmalloc(segment_size); + if (!ima_kexec_file.buf) + return -ENOMEM; + + ima_kexec_file.size = segment_size; + +out: + ima_kexec_file.read_pos = 0; + ima_kexec_file.count = sizeof(struct ima_kexec_hdr); /* reserved space */ + + 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; + size_t entry_size = 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("Kexec file buf not allocated\n"); + return -EINVAL; } - file.file = NULL; - file.size = segment_size; - file.read_pos = 0; - file.count = sizeof(khdr); /* reserved space */ - memset(&khdr, 0, sizeof(khdr)); khdr.version = 1; + + /* Copy as many IMA measurements list records as possible */ list_for_each_entry_rcu(qe, &ima_measurements, later) { - if (file.count < file.size) { + entry_size += ima_get_binary_runtime_entry_size(qe->entry); + if (entry_size <= segment_size) { khdr.count++; - ima_measurements_show(&file, qe); + ima_measurements_show(&ima_kexec_file, qe); } else { ret = -EINVAL; + pr_err("IMA log file is too big for Kexec buf\n"); 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; + 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); } - memcpy(file.buf, &khdr, sizeof(khdr)); + memcpy(ima_kexec_file.buf, &khdr, sizeof(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; } @@ -89,7 +126,7 @@ 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_buffer_size = 0; size_t kexec_segment_size; int ret; @@ -109,13 +146,19 @@ 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_file_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("Failed to dump IMA measurements. Error:%d.\n", ret); + return; + } + kbuf.buffer = kexec_buffer; kbuf.bufsz = kexec_buffer_size; kbuf.memsz = kexec_segment_size; @@ -130,6 +173,12 @@ void ima_add_kexec_buffer(struct kimage *image) image->ima_buffer_size = kexec_segment_size; image->ima_buffer = kexec_buffer; + /* + * kexec owns kexec_buffer after kexec_add_buffer() is called + * and it will vfree() that buffer. + */ + ima_reset_kexec_file(&ima_kexec_file); + kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", kbuf.mem); } diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 532da87ce519..a3559bae251f 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -71,7 +71,7 @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, * binary_runtime_measurement list entry, which contains a * couple of variable length fields (e.g template name and data). */ -static int get_binary_runtime_size(struct ima_template_entry *entry) +int ima_get_binary_runtime_entry_size(struct ima_template_entry *entry) { int size = 0; @@ -115,7 +115,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry, if (binary_runtime_size != ULONG_MAX) { int size; - size = get_binary_runtime_size(entry); + size = ima_get_binary_runtime_entry_size(entry); binary_runtime_size = (binary_runtime_size < ULONG_MAX - size) ? binary_runtime_size + size : ULONG_MAX; } From patchwork Mon Feb 3 23:20:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: steven chen X-Patchwork-Id: 13958393 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8CCD31FFC7D; Mon, 3 Feb 2025 23:20:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624844; cv=none; b=CwEDEj7If0eq6ArkUGcx1Xrso8a2q+7pwKdsED34bF7Voe8bmUvbVVpO4QvqGD+ZRWwtOhTG70rZ8sB8YmFMEl4Y6MGrnBmoN/CM1iqCsolm0HM0K6vCeCYvkmlwdyJcwXPC25ArJ+fwFr68wAnHEXSzOS47xWIrLMqVLbGELp4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624844; c=relaxed/simple; bh=t4XqqrYhwscr6FS7U4bhL3N2YVK27fxTi1qasHS8jzw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=AXdLjaUuRNR1NO8q+wHT8x6wFI8JexWz0JTQXYuy8hcp5zOlC06P0X6NLHjhbpHLFagmXOScTp4LXD51i3u8qBxDFS0iGUnLSLu0Bkb3PxvLpJeK9sMWxp/I8JS9Bfwt9bV8o44Ul/zPn2ESx0O0scxhKOANaod5PczNT34WIe4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=ULwXqrOf; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="ULwXqrOf" Received: from localhost.localdomain (unknown [167.220.59.4]) by linux.microsoft.com (Postfix) with ESMTPSA id 05A15205493D; Mon, 3 Feb 2025 15:20:41 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 05A15205493D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1738624841; bh=l74eF+4+r695BFOwyov/kRxEW4Z5jvFKpT/pUDEgh3Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ULwXqrOfgp1zYKYh4Exup3t18SWRsiZMNqCnSVnpMbcW3u7Zd5B1j/OfcVVjnc++p aWxC55xsR3T3ilUYk+LRWe/Bng2K2mJn+Xku1A0C3elFmRmVeN1P6k5VNJxXcsyBco q6iLDFcXPwRssB5mUndbk/poABTXShTdXnNMfRhc= From: steven chen To: zohar@linux.ibm.com, stefanb@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, ebiederm@xmission.com, paul@paul-moore.com, code@tyhicks.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, chenste@linux.microsoft.com Cc: madvenka@linux.microsoft.com, nramas@linux.microsoft.com, James.Bottomley@HansenPartnership.com Subject: [PATCH v7 2/7] kexec: define functions to map and unmap segments Date: Mon, 3 Feb 2025 15:20:27 -0800 Message-Id: <20250203232033.64123-3-chenste@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250203232033.64123-1-chenste@linux.microsoft.com> References: <20250203232033.64123-1-chenste@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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 functions to map and unmap segments to kimage. Implement kimage_map_segment() to enable mapping of IMA buffer source pages to the kimage structure post kexec 'load'. This function, accepting a kimage pointer, an address, and a size, will gather the source pages within the specified address range, create an array of page pointers, and map these to a contiguous virtual address range. The function returns the start of this range if successful, or NULL if unsuccessful. Implement kimage_unmap_segment() for unmapping segments using vunmap(). From: Tushar Sugandhi Author: Tushar Sugandhi Reviewed-by: Stefan Berger Reviewed-by: Mimi Zohar Signed-off-by: Tushar Sugandhi Signed-off-by: steven chen --- include/linux/kexec.h | 7 ++++++ kernel/kexec_core.c | 54 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index f0e9f8eda7a3..f8413ea5c8c8 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -467,6 +467,9 @@ extern bool kexec_file_dbg_print; #define kexec_dprintk(fmt, arg...) \ do { if (kexec_file_dbg_print) pr_info(fmt, ##arg); } while (0) +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; @@ -474,6 +477,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 c0caa14880c3..4029df8f6860 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -867,6 +867,60 @@ 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; + unsigned int npages; + struct page **src_pages; + int i; + kimage_entry_t *ptr, entry; + void *vaddr = NULL; + + /* + * Collect the source pages and map them in a contiguous VA range. + */ + npages = PFN_UP(eaddr) - PFN_DOWN(addr); + src_pages = kmalloc_array(npages, sizeof(*src_pages), GFP_KERNEL); + if (!src_pages) { + pr_err("Could not allocate ima pages array.\n"); + 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); + kfree(src_pages); + + if (!vaddr) + pr_err("Could not map ima buffer.\n"); + + return vaddr; +} + +void kimage_unmap_segment(void *segment_buffer) +{ + vunmap(segment_buffer); +} + struct kexec_load_limit { /* Mutex protects the limit count. */ struct mutex mutex; From patchwork Mon Feb 3 23:20:28 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: steven chen X-Patchwork-Id: 13958390 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id DB425201267; Mon, 3 Feb 2025 23:20:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624843; cv=none; b=jsgTiX0uGi/ABEiPSZlkatZb0/hE1qP3HofwbaiKRUQFHG+fHKduaPtAGfDXiuoHlQpsDcXU+Z/wgWdZ2fSgAtxXjJnQzkVjqwTw7uQ3IS6cG6I4p3U/u43HdRceb1eOtokkEdJ6bkUgdYa2JdlqZ2+34wnpzS0L2yxsb+1tt1Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624843; c=relaxed/simple; bh=Jf5yLF0QA77l3vRMWJUEaa8p/xUOR3jCWV62rrEDc6Y=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=bmM1iSO/VHzTLK06ZjWNHz0aL96GhVNWiXFBa0L4WW7QI5+MssO9hhL6nGAijAZwwMf79M3b7UYKDi7duHqqQgect5Z7UkcW8hJ7egWWoDu5qv0+D7Gg6LCkBJIY0PVRzC5gBVlCMCTggcRA7PvD7eIhCH8M0N9n6ObLDtIVPko= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=KRGm4uKa; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="KRGm4uKa" Received: from localhost.localdomain (unknown [167.220.59.4]) by linux.microsoft.com (Postfix) with ESMTPSA id 391DE205493E; Mon, 3 Feb 2025 15:20:41 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 391DE205493E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1738624841; bh=0pLOnkZ3BBhZrWSrqRS0hKDrePzR0/4CteyR8x89gQk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KRGm4uKa6uwqYp++gYLVkz+w0G7XRLKWZaiSa9r29oDDeni8lIRGaUO621/GkcQqz f4DvTtm91iRY4M/PLDUtRvf74WyB/q92NbJ5YXcU86f8KDZAoOOGX9f9yAU2MBPzAu UUF/xF5N5b0aCSP4671roPFX9K8P9odm+R1FPLSk= From: steven chen To: zohar@linux.ibm.com, stefanb@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, ebiederm@xmission.com, paul@paul-moore.com, code@tyhicks.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, chenste@linux.microsoft.com Cc: madvenka@linux.microsoft.com, nramas@linux.microsoft.com, James.Bottomley@HansenPartnership.com Subject: [PATCH v7 3/7] ima: kexec: skip IMA segment validation after kexec soft reboot Date: Mon, 3 Feb 2025 15:20:28 -0800 Message-Id: <20250203232033.64123-4-chenste@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250203232033.64123-1-chenste@linux.microsoft.com> References: <20250203232033.64123-1-chenste@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 kexec_calculate_store_digests() calculates and stores the digest of the segment at kexec_file_load syscall where the IMA segment is also allocated. With this series, the IMA segment will be updated with the measurement log at kexec excute stage when soft reboot is initiated. Therefore, it may fail digest verification in verify_sha256_digest() after kexec soft reboot into the new kernel. Therefore, the digest calculation/verification of the IMA segment needs to be skipped. Skip IMA segment from calculating and storing digest in function kexec_calculate_store_digests() so that it is not added to the 'purgatory_sha_regions'. Since verify_sha256_digest() only verifies 'purgatory_sha_regions', no change is needed in verify_sha256_digest() in this context. With this change, the IMA segment is not included in the digest calculation, storage, and verification. Author: Tushar Sugandhi Signed-off-by: Tushar Sugandhi Signed-off-by: steven chen Reviewed-by: Stefan Berger --- include/linux/kexec.h | 3 +++ kernel/kexec_file.c | 23 +++++++++++++++++++++++ security/integrity/ima/ima_kexec.c | 3 +++ 3 files changed, 29 insertions(+) diff --git a/include/linux/kexec.h b/include/linux/kexec.h index f8413ea5c8c8..f3246e881ac8 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -362,6 +362,9 @@ struct kimage { phys_addr_t ima_buffer_addr; size_t ima_buffer_size; + + unsigned long ima_segment_index; + bool is_ima_segment_index_set; #endif /* Core ELF header buffer */ diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 3eedb8c226ad..a3370a0dce20 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -38,6 +38,22 @@ void set_kexec_sig_enforced(void) } #endif +#ifdef CONFIG_IMA_KEXEC +static bool check_ima_segment_index(struct kimage *image, int i) +{ + if (image->is_ima_segment_index_set && + i == image->ima_segment_index) + return true; + else + return false; +} +#else +static bool check_ima_segment_index(struct kimage *image, int i) +{ + return false; +} +#endif + static int kexec_calculate_store_digests(struct kimage *image); /* Maximum size in bytes for kernel/initrd files. */ @@ -764,6 +780,13 @@ static int kexec_calculate_store_digests(struct kimage *image) if (ksegment->kbuf == pi->purgatory_buf) continue; + /* + * Skip the segment if ima_segment_index is set and matches + * the current index + */ + if (check_ima_segment_index(image, i)) + continue; + ret = crypto_shash_update(desc, ksegment->kbuf, ksegment->bufsz); if (ret) diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index b60a902460e2..283860d20521 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -162,6 +162,7 @@ void ima_add_kexec_buffer(struct kimage *image) kbuf.buffer = kexec_buffer; kbuf.bufsz = kexec_buffer_size; kbuf.memsz = kexec_segment_size; + image->is_ima_segment_index_set = false; ret = kexec_add_buffer(&kbuf); if (ret) { pr_err("Error passing over kexec measurement buffer.\n"); @@ -172,6 +173,8 @@ void ima_add_kexec_buffer(struct kimage *image) image->ima_buffer_addr = kbuf.mem; image->ima_buffer_size = kexec_segment_size; image->ima_buffer = kexec_buffer; + image->ima_segment_index = image->nr_segments - 1; + image->is_ima_segment_index_set = true; /* * kexec owns kexec_buffer after kexec_add_buffer() is called From patchwork Mon Feb 3 23:20:29 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: steven chen X-Patchwork-Id: 13958391 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E5B9C201269; Mon, 3 Feb 2025 23:20:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624843; cv=none; b=XN+qnUfVXLQdclSOcyEbaNNlcogQlA/3YDX9gYEWW/Ja0WOFu7172ACJzWcRa4uevl+KNbeUH5H4nZR+dgTYWGrTIAvjwUlko3NGhOegVEuc4/GA37ZplHjOyIlAf70VoSkgY0BnPty4wl76z+mX7qGpAiWE4MevQCZVpzqlJCw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624843; c=relaxed/simple; bh=EGSzYZ/wUc8bEEIuGyf1CrDl3ntDab0/DRlAcjZi9fE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=fBGsl3khRp7falu1YpSp8cTOj8X43KVlwjhCV7XOLf1MmQz9P1tqlCoLfbfiuGrDIbTTflsDWHfPZ9SOAEB7GpbIumKrLApvnMRGc+g04t2rHcuOrFwCqdcAH4B5fDKyB17c0J7LxNd2LnMrBh8T4whdlMf0H9O+wiozeytwtyU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=rNnUZOTP; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="rNnUZOTP" Received: from localhost.localdomain (unknown [167.220.59.4]) by linux.microsoft.com (Postfix) with ESMTPSA id 6B3D3205493F; Mon, 3 Feb 2025 15:20:41 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 6B3D3205493F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1738624841; bh=VwNfvVLfL00S8Xn+X+PulIftmjpln6BGP2uOmQnQBPE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rNnUZOTP5koN12g6mRjPgI3kW9PhzR7tllDMcyTm1gPdSl5Yasi38scCiK7tmzEmT 8a+pjvMzt8vqFO7qaMYRRlzQkqBjAKubtMAU98HC+NnsKj7yJdjeVFPAj5n2eAektR Zv845WMmEkj1W/zASNbE008JmayCXNDudn2/2ed8= From: steven chen To: zohar@linux.ibm.com, stefanb@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, ebiederm@xmission.com, paul@paul-moore.com, code@tyhicks.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, chenste@linux.microsoft.com Cc: madvenka@linux.microsoft.com, nramas@linux.microsoft.com, James.Bottomley@HansenPartnership.com Subject: [PATCH v7 4/7] ima: kexec: define functions to copy IMA log at soft boot Date: Mon, 3 Feb 2025 15:20:29 -0800 Message-Id: <20250203232033.64123-5-chenste@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250203232033.64123-1-chenste@linux.microsoft.com> References: <20250203232033.64123-1-chenste@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 IMA log is copied to the new Kernel during kexec 'load' using ima_dump_measurement_list(). The log copy at kexec 'load' may result in loss of IMA measurements during kexec soft reboot. It needs to be copied over during kexec 'execute'. Setup the needed infrastructure to move the IMA log copy from kexec 'load' to 'execute'. Define a new IMA hook ima_update_kexec_buffer() as a stub function. It will be used to call ima_dump_measurement_list() during kexec 'execute'. Implement ima_kexec_post_load() function to be invoked after the new Kernel image has been loaded for kexec. ima_kexec_post_load() maps the IMA buffer to a segment in the newly loaded Kernel. It also registers the reboot notifier_block to trigger ima_update_kexec_buffer() at exec 'execute'. Author: Tushar Sugandhi Reviewed-by: Stefan Berger Suggested-by: Mimi Zohar Reviewed-by: "Petr Tesařík" Signed-off-by: Tushar Sugandhi Signed-off-by: steven chen --- include/linux/ima.h | 3 ++ security/integrity/ima/ima_kexec.c | 46 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/include/linux/ima.h b/include/linux/ima.h index 0bae61a15b60..8e29cb4e6a01 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -32,6 +32,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/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 283860d20521..854b90d34e2d 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -12,10 +12,14 @@ #include #include #include +#include +#include #include "ima.h" #ifdef CONFIG_IMA_KEXEC static struct seq_file ima_kexec_file; +static void *ima_kexec_buffer; +static bool ima_kexec_update_registered; static void ima_reset_kexec_file(struct seq_file *sf) { @@ -185,6 +189,48 @@ void ima_add_kexec_buffer(struct kimage *image) kexec_dprintk("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) +{ + return NOTIFY_OK; +} + +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("Could not map measurements buffer.\n"); + return; + } + + if (!ima_kexec_update_registered) { + register_reboot_notifier(&update_buffer_nb); + ima_kexec_update_registered = true; + } +} + #endif /* IMA_KEXEC */ /* From patchwork Mon Feb 3 23:20:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: steven chen X-Patchwork-Id: 13958394 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 72396211461; Mon, 3 Feb 2025 23:20:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624845; cv=none; b=KaUs4rtTgrT3yOmJlJNvfIrpuAFNOV39xos9xMrAHLuYW3rn6MoxUDCvTxHomXSQJQ8aohdPT8GWMq0BNEHL/qR1pXFObjZLQmX+rbAqBsykZNJPWXmdYkEJRYaYtakva8MIkU/VY3PAH7E7sgI+AdedQXlZHEcHVCm2HrkoTL4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624845; c=relaxed/simple; bh=CPQHCx+9vXNfu44FLP2T4w1zlwSgsUg+xcw5WGl7sgo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=HTrVBOU75dWo9rMq9Gws9u+JVMGX1q5sYdvkjuAjQ0xlpx3WY6DHG/EGKWAwpx/5lvNaNVMRoRQHcaeey+UkxEU24fuRxqwChqV+wWSEXbKdFyS9CzBwX4GqVx4dPy/6SqfHxv06VAZLAyrJ5tL2rVFM8k/bgPNQc8foWFHAh8I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=AJudZl8P; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="AJudZl8P" Received: from localhost.localdomain (unknown [167.220.59.4]) by linux.microsoft.com (Postfix) with ESMTPSA id CF8C720BCAF2; Mon, 3 Feb 2025 15:20:41 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com CF8C720BCAF2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1738624841; bh=842zmq7II7peAIQB44phcmR7CRWWIlAqh7HOqyXvZx8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AJudZl8PsKuB6X5xWIc6BBG8dcVEhVVZr8Z67olbwHLQaqsDZwtFAIdaiqBKJ1oA7 vB3e+2KtTygieJNsdAZjY6LmkiXoz4bMFo2Gu98u59KA6VrL1lbW+IdvYiQhduKupM Ae6IU/C0gq4iAo47bnHREtHmFYYzyXmCX7h8D7zA= From: steven chen To: zohar@linux.ibm.com, stefanb@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, ebiederm@xmission.com, paul@paul-moore.com, code@tyhicks.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, chenste@linux.microsoft.com Cc: madvenka@linux.microsoft.com, nramas@linux.microsoft.com, James.Bottomley@HansenPartnership.com Subject: [PATCH v7 5/7] ima: kexec: move IMA log copy from kexec load to execute Date: Mon, 3 Feb 2025 15:20:31 -0800 Message-Id: <20250203232033.64123-7-chenste@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250203232033.64123-1-chenste@linux.microsoft.com> References: <20250203232033.64123-1-chenste@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 ima_dump_measurement_list() is called during kexec 'load', which may result in loss of IMA measurements during kexec soft reboot. It needs to be called during kexec 'execute'. This patch includes the following changes: - Implement kimage_file_post_load() function to be invoked after the new Kernel image has been loaded for kexec. - Call kimage_file_post_load() from kexec_file_load() syscall only for kexec soft reboot scenarios and not for KEXEC_FILE_ON_CRASH. It will map the IMA segment, and register reboot notifier for the function ima_update_kexec_buffer() which would copy the IMA log at kexec soft reboot. - Make kexec_segment_size variable local static to the file, for it to be accessible both during kexec 'load' and 'execute'. - Move ima_dump_measurement_list() call from ima_add_kexec_buffer() to ima_update_kexec_buffer(). - Remove ima_reset_kexec_file() call from ima_add_kexec_buffer(), now that the buffer is being copied at kexec 'execute', and resetting the file at kexec 'load' will corrupt the buffer. Author: Tushar Sugandhi Reviewed-by: Tyler Hicks Signed-off-by: Tushar Sugandhi Signed-off-by: steven chen --- kernel/kexec_file.c | 8 ++++++ security/integrity/ima/ima_kexec.c | 43 +++++++++++++++++++----------- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index a3370a0dce20..a523cd209bfc 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -202,6 +202,11 @@ kimage_validate_signature(struct kimage *image) } #endif +static 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 @@ -429,6 +434,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; diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 854b90d34e2d..d5f004cfeaec 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -19,6 +19,7 @@ #ifdef CONFIG_IMA_KEXEC static struct seq_file ima_kexec_file; static void *ima_kexec_buffer; +static size_t kexec_segment_size; static bool ima_kexec_update_registered; static void ima_reset_kexec_file(struct seq_file *sf) @@ -131,7 +132,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 = 0; - size_t kexec_segment_size; int ret; /* @@ -156,13 +156,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("Failed to dump IMA measurements. Error:%d.\n", ret); - return; - } - kbuf.buffer = kexec_buffer; kbuf.bufsz = kexec_buffer_size; kbuf.memsz = kexec_segment_size; @@ -180,12 +173,6 @@ void ima_add_kexec_buffer(struct kimage *image) image->ima_segment_index = image->nr_segments - 1; image->is_ima_segment_index_set = true; - /* - * kexec owns kexec_buffer after kexec_add_buffer() is called - * and it will vfree() that buffer. - */ - ima_reset_kexec_file(&ima_kexec_file); - kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", kbuf.mem); } @@ -196,7 +183,33 @@ void ima_add_kexec_buffer(struct kimage *image) static int ima_update_kexec_buffer(struct notifier_block *self, unsigned long action, void *data) { - return NOTIFY_OK; + void *buf = NULL; + size_t buf_size = 0; + int ret = NOTIFY_OK; + + if (!kexec_in_progress) { + pr_info("No kexec in progress.\n"); + return ret; + } + + if (!ima_kexec_buffer) { + pr_err("Kexec buffer not set.\n"); + return ret; + } + + ret = ima_dump_measurement_list(&buf_size, &buf, + kexec_segment_size); + + if (ret) + pr_err("Dump measurements failed. Error:%d\n", ret); + + if (buf_size != 0) + memcpy(ima_kexec_buffer, buf, buf_size); + + kimage_unmap_segment(ima_kexec_buffer); + ima_kexec_buffer = NULL; + + return ret; } struct notifier_block update_buffer_nb = { From patchwork Mon Feb 3 23:20:32 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: steven chen X-Patchwork-Id: 13958396 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9E893211466; Mon, 3 Feb 2025 23:20:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624845; cv=none; b=tPDThacgeQUPOmb6klwo9t/nksRNeRps0rofEyMTbSJ5Ms3bEfuBDmvQQZ2p08zqBS0M6NPXlTTNcXyhkxjjJKRVjTSGeAAXt4jWLe+Hd/i04soUgW2B9zJwoi6Dwsb/OWJoIWKVjmIiY6JudFV2HcgB3mCnaUIPwiCt5D0GN9w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624845; c=relaxed/simple; bh=ZV4vYEbQIpjD72/RY85S+Dgnqd0a77LyHi+94XZNKi0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=LJKRM8+xzwlbWBeoRZbpUjcTBlPcGiByF219zUiKa5gR0Q2T3kiVMVm06atXfzFu0V0uLG/OJMXZaEZ+DaxFSZHH4oskr0aW3mY34/0uoIBFXvIQNa6mKEucU2G1n6egL46OvIA4ehlDwHXT8tCFihzg7F1p+m51vbKkf5M9Ag8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=dzJquoh1; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="dzJquoh1" Received: from localhost.localdomain (unknown [167.220.59.4]) by linux.microsoft.com (Postfix) with ESMTPSA id 0E46D2066C1F; Mon, 3 Feb 2025 15:20:42 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 0E46D2066C1F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1738624842; bh=KbbzVWtcOJ7Gt1QLNcb0WLEL7b64gQxfibl1JZ8EMTM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dzJquoh1xo4hF2BQMuoyyh0g3jgmKq8/F2dKYmAw5OAfnIpf09LicgugSFzVRkupH b5TKFUHE7XX7zvahIL1cWkBSDkSqjaKmZxd2vzJd9wCM0LzS1v9i0qyvXzeLRwoDYj tMibo88Kz4mBhLYwo2BA/O8G9tXJD5BZouD65wwQ= From: steven chen To: zohar@linux.ibm.com, stefanb@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, ebiederm@xmission.com, paul@paul-moore.com, code@tyhicks.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, chenste@linux.microsoft.com Cc: madvenka@linux.microsoft.com, nramas@linux.microsoft.com, James.Bottomley@HansenPartnership.com Subject: [PATCH v7 6/7] ima: make the kexec extra memory configurable Date: Mon, 3 Feb 2025 15:20:32 -0800 Message-Id: <20250203232033.64123-8-chenste@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250203232033.64123-1-chenste@linux.microsoft.com> References: <20250203232033.64123-1-chenste@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The extra memory allocated for carrying the IMA measurement list across kexec is hard-coded as half a PAGE. Make it configurable. Define a Kconfig option, IMA_KEXEC_EXTRA_MEMORY_KB, to configure the extra memory (in kb) to be allocated for IMA measurements added during kexec soft reboot. Ensure the default value of the option is set such that extra half a page of memory for additional measurements is allocated for the additional measurements. Update ima_add_kexec_buffer() function to allocate memory based on the Kconfig option value, rather than the currently hard-coded one. From: Tushar Sugandhi Author: Tushar Sugandhi Suggested-by: Stefan Berger Signed-off-by: Tushar Sugandhi Signed-off-by: steven chen --- security/integrity/ima/Kconfig | 10 ++++++++++ security/integrity/ima/ima_kexec.c | 16 ++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 475c32615006..54b145ae6096 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -321,4 +321,14 @@ config IMA_DISABLE_HTABLE help This option disables htable to allow measurement of duplicate records. +config IMA_KEXEC_EXTRA_MEMORY_KB + int "Extra memory for IMA measurements added during kexec soft reboot" + depends on IMA_KEXEC + default 0 + help + IMA_KEXEC_EXTRA_MEMORY_KB determines the extra memory to be + allocated (in kb) for IMA measurements added during kexec soft reboot. + If set to the default value, an extra half a page of memory for those + additional measurements will be allocated. + endif diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index d5f004cfeaec..c9c916f69ca7 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -128,22 +128,26 @@ void ima_add_kexec_buffer(struct kimage *image) .buf_min = 0, .buf_max = ULONG_MAX, .top_down = true }; unsigned long binary_runtime_size; - + unsigned long extra_size; /* use more understandable variable names than defined in kbuf */ void *kexec_buffer = NULL; size_t kexec_buffer_size = 0; int ret; /* - * Reserve an extra half page of memory for additional measurements - * added during the kexec load. + * Reserve extra memory for measurements added during kexec. */ - binary_runtime_size = ima_get_binary_runtime_size(); + if (CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB <= 0) + extra_size = PAGE_SIZE / 2; + else + extra_size = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024; + binary_runtime_size = ima_get_binary_runtime_size() + extra_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 Mon Feb 3 23:20:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: steven chen X-Patchwork-Id: 13958395 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9E80C211464; Mon, 3 Feb 2025 23:20:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=13.77.154.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624845; cv=none; b=ilCjabFr4L9elR7Qsn7vTU+hQQKYNy1Wngxdq2VbkSxkgglxjgq7GX/H1rHb1ClyWrOrXP5f9FejiTLsjzB6OO76FO9XSK1TJ4fZCmOX/E1t+Kol7vCerAQcn3qCQHPyHEF3Z7Vm2yXjigoPP3Ee9XlDr2/GB1VNJyvvko9Yom4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1738624845; c=relaxed/simple; bh=JMiCI7oEWpaNyaUwMo7rDIzjwYonTLm5E0qBtBtW4bU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=g+zOOS20uFbfRtkLwtD2kAWUHP5uS4nVRKVwT9Z84H6ygI37GHx24jb8+cQvTzrqPwLHvQXDI6Cd/mFvsnsM/dfegETW8z15A6Roqa4PyYRl8YmS4N8fBjPdOyodIyfrrVPzOy4eIKkvaGoiPT/LQtOhlIhq0pQ6MVP4nhtVSdo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com; spf=pass smtp.mailfrom=linux.microsoft.com; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b=aIMrI5P5; arc=none smtp.client-ip=13.77.154.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.microsoft.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="aIMrI5P5" Received: from localhost.localdomain (unknown [167.220.59.4]) by linux.microsoft.com (Postfix) with ESMTPSA id 3F1E3206AB6B; Mon, 3 Feb 2025 15:20:42 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 3F1E3206AB6B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1738624842; bh=0df9k6YmLXTRB5Kdzk0atr6aQfh11G9ejUhwNmP0edM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aIMrI5P5jQFp3SkWuLFZoU4xQssnDnYZMmGVGLK5Y6MwYdla9BBM1z2oTeboFqy04 zux3/HPx6IuzMy0AIBkJJ83Pc+5gqMCW5vLyIUwBJDXXo397B8JPb/2fq9Wtkq8Pa+ srXK1Ps8JsG8cE//Axb8kd195BfPqDuZLNyyHLiU= From: steven chen To: zohar@linux.ibm.com, stefanb@linux.ibm.com, roberto.sassu@huaweicloud.com, roberto.sassu@huawei.com, eric.snowberg@oracle.com, ebiederm@xmission.com, paul@paul-moore.com, code@tyhicks.com, bauermann@kolabnow.com, linux-integrity@vger.kernel.org, kexec@lists.infradead.org, linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, chenste@linux.microsoft.com Cc: madvenka@linux.microsoft.com, nramas@linux.microsoft.com, James.Bottomley@HansenPartnership.com Subject: [PATCH v7 7/7] ima: measure kexec load and exec events as critical data Date: Mon, 3 Feb 2025 15:20:33 -0800 Message-Id: <20250203232033.64123-9-chenste@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250203232033.64123-1-chenste@linux.microsoft.com> References: <20250203232033.64123-1-chenste@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The amount of memory allocated at kexec load, even with the extra memory allocated, might not be large enough for the entire measurement list. The indeterminate interval between kexec 'load' and 'execute' could exacerbate this problem. Define two new IMA events, 'kexec_load' and 'kexec_execute', to be measured as critical data at kexec 'load' and 'execute' respectively. Report the allocated kexec segment size, IMA binary log size and the runtime measurements count as part of those events. These events, and the values reported through them, serve as markers in the IMA log to verify the IMA events are captured during kexec soft reboot. The presence of a 'kexec_load' event in between the last two 'boot_aggregate' events in the IMA log implies this is a kexec soft reboot, and not a cold-boot. And the absence of 'kexec_execute' event after kexec soft reboot implies missing events in that window which results in inconsistency with TPM PCR quotes, necessitating a cold boot for a successful remote attestation. Reviewed-by: Stefan Berger Author: Tushar Sugandhi Signed-off-by: Tushar Sugandhi Signed-off-by: steven chen --- security/integrity/ima/ima_kexec.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index c9c916f69ca7..0342ddfa9342 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 256 + static struct seq_file ima_kexec_file; static void *ima_kexec_buffer; static size_t kexec_segment_size; @@ -36,6 +38,24 @@ static void ima_free_kexec_file_buf(struct seq_file *sf) ima_reset_kexec_file(sf); } +static void ima_measure_kexec_event(const char *event_name) +{ + char ima_kexec_event[IMA_KEXEC_EVENT_LEN]; + size_t buf_size = 0; + long len; + + buf_size = ima_get_binary_runtime_size(); + len = atomic_long_read(&ima_htable.len); + + scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN, + "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;" + "ima_runtime_measurements_count=%ld;", + kexec_segment_size, buf_size, len); + + ima_measure_critical_data("ima_kexec", event_name, ima_kexec_event, + strlen(ima_kexec_event), false, NULL, 0); +} + static int ima_alloc_kexec_file_buf(size_t segment_size) { /* @@ -60,6 +80,7 @@ static int ima_alloc_kexec_file_buf(size_t segment_size) out: ima_kexec_file.read_pos = 0; ima_kexec_file.count = sizeof(struct ima_kexec_hdr); /* reserved space */ + ima_measure_kexec_event("kexec_load"); return 0; } @@ -201,6 +222,8 @@ static int ima_update_kexec_buffer(struct notifier_block *self, return ret; } + ima_measure_kexec_event("kexec_execute"); + ret = ima_dump_measurement_list(&buf_size, &buf, kexec_segment_size);