From nobody Fri Dec 19 20:12:25 2025 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 67F00175D47; Tue, 18 Mar 2025 01:05:19 +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=1742259921; cv=none; b=NiQ0bMku4docgw9dioAMUI2hyfBANBfREpa3NPoaBho0Z+LF/mMljK9uTXdF/jnDRdTviZY8l6B8IHnH+BqTeSgTkiEMzz5XL9frCrdj+HbJNkw2xXVG90c765VrxhogBUxHhnAJzrN7bRLVUvNENgyKdPOBboGG7T55uF/+lNQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742259921; c=relaxed/simple; bh=e5ThrXupcT9ZGfFU5Tk68BqmgfQZq93gt2MnC+AqPzA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=echOpBvmKit30tz7oTp4ubk8GCPj9ElEVe5IzRrz401xceFar6tXFYPSa/sOi8xQQTnvXOZmIU13Jd4hc9NW08sFcSyXo2Ee1+Chxaq9Y7u+Vt9N1uekBJ7bCapvemVb6LNyjaNg3BJnjzXRzz602gNDRyF70W0XAgGd7nsDYxg= 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=EjG4CEZl; 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="EjG4CEZl" Received: from localhost.localdomain (unknown [131.107.147.236]) by linux.microsoft.com (Postfix) with ESMTPSA id E567120DEACE; Mon, 17 Mar 2025 18:05:16 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com E567120DEACE DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1742259919; bh=mI2ZxU7Sw/KQ7e8aWJaQUjOuf7ihC69n+BKL3G34WUQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EjG4CEZlBqfI2j+nkaayFYfsPydslFDDER9nSmJaE/qLKfnScC6BJyYppdt7187VB xqaALSzDsIamP2X2nMUPpe4Ky6UUn0sAtgEviRYFsFhl0rv9yhQqs/JfG/SkGDZ5i1 8bJ1Wf6yDDdowocxJDLdDvSQpfTQxWExL196+ODI= 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 Cc: madvenka@linux.microsoft.com, nramas@linux.microsoft.com, James.Bottomley@HansenPartnership.com, bhe@redhat.com, vgoyal@redhat.com, dyoung@redhat.com Subject: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute Date: Mon, 17 Mar 2025 18:04:44 -0700 Message-ID: <20250318010448.954-7-chenste@linux.microsoft.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250318010448.954-1-chenste@linux.microsoft.com> References: <20250318010448.954-1-chenste@linux.microsoft.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ima_dump_measurement_list() is called during kexec 'load', which may result in loss of IMA measurements during kexec soft reboot. Due to=20 missed measurements that only occurred after kexec 'load', this function=20 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 so that it=20 becomes accessible both during kexec 'load' and 'execute'. - Move ima_dump_measurement_list() call from ima_add_kexec_buffer() to ima_update_kexec_buffer(). - Copy the measurement list as much as possible. - 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' would corrupt the buffer. Signed-off-by: Tushar Sugandhi Cc: Eric Biederman Cc: Baoquan He =20 Cc: Vivek Goyal Cc: Dave Young Signed-off-by: steven chen Reviewed-by: Stefan Berger --- kernel/kexec_file.c | 10 ++++++ security/integrity/ima/ima_kexec.c | 51 ++++++++++++++++++------------ 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 606132253c79..ab449b43aaee 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -201,6 +201,13 @@ kimage_validate_signature(struct kimage *image) } #endif =20 +static void kimage_file_post_load(struct kimage *image) +{ +#ifdef CONFIG_IMA_KEXEC + ima_kexec_post_load(image); +#endif +} + /* * In file mode list of segments is prepared by kernel. Copy relevant * data from user space, do error checking, prepare segment list @@ -428,6 +435,9 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, i= nitrd_fd, =20 kimage_terminate(image); =20 + if (!(flags & KEXEC_FILE_ON_CRASH)) + kimage_file_post_load(image); + ret =3D machine_kexec_post_load(image); if (ret) goto out; diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/im= a_kexec.c index 9336c4f60650..c390c745f882 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -19,6 +19,7 @@ #ifdef CONFIG_IMA_KEXEC static bool ima_kexec_update_registered; static struct seq_file ima_kexec_file; +static size_t kexec_segment_size; static void *ima_kexec_buffer; =20 static void ima_reset_kexec_file(struct seq_file *sf) @@ -67,7 +68,7 @@ static int ima_alloc_kexec_file_buf(size_t segment_size) * if the size of the allocated memory is not less than the size of IMA= measurement list * copy the measurement list to the allocated memory. * else - * return error + * copy the measurement list as much as possible. */ static int ima_dump_measurement_list(unsigned long *buffer_size, void **bu= ffer, unsigned long segment_size) @@ -95,9 +96,6 @@ static int ima_dump_measurement_list(unsigned long *buffe= r_size, void **buffer, } } =20 - if (ret < 0) - goto out; - /* * fill in reserved space with some buffer details * (eg. version, buffer size, number of measurements) @@ -117,7 +115,7 @@ static int ima_dump_measurement_list(unsigned long *buf= fer_size, void **buffer, =20 *buffer_size =3D ima_kexec_file.count; *buffer =3D ima_kexec_file.buf; -out: + return ret; } =20 @@ -135,9 +133,8 @@ void ima_add_kexec_buffer(struct kimage *image) unsigned long binary_runtime_size; =20 /* use more understandable variable names than defined in kbuf */ + size_t kexec_buffer_size =3D 0; void *kexec_buffer =3D NULL; - size_t kexec_buffer_size; - size_t kexec_segment_size; int ret; =20 /* @@ -162,13 +159,6 @@ void ima_add_kexec_buffer(struct kimage *image) return; } =20 - ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, - kexec_segment_size); - if (!kexec_buffer) { - pr_err("Not enough memory for the kexec measurement buffer.\n"); - return; - } - kbuf.buffer =3D kexec_buffer; kbuf.bufsz =3D kexec_buffer_size; kbuf.memsz =3D kexec_segment_size; @@ -186,12 +176,6 @@ void ima_add_kexec_buffer(struct kimage *image) image->ima_segment_index =3D image->nr_segments - 1; image->is_ima_segment_index_set =3D true; =20 - /* - * 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); } @@ -202,7 +186,32 @@ 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; + size_t buf_size =3D 0; + int ret =3D NOTIFY_OK; + void *buf =3D NULL; + + 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 =3D ima_dump_measurement_list(&buf_size, &buf, kexec_segment_size); + + if (ret) + pr_err("Dump measurements failed. Error:%d\n", ret); + + if (buf_size !=3D 0) + memcpy(ima_kexec_buffer, buf, buf_size); + + kimage_unmap_segment(ima_kexec_buffer); + ima_kexec_buffer =3D NULL; + + return ret; } =20 static struct notifier_block update_buffer_nb =3D { --=20 2.25.1