[PATCH 06/10] ima: update buffer at kexec execute with ima measurements

Tushar Sugandhi tusharsu at linux.microsoft.com
Mon Jul 3 14:57:05 PDT 2023


In the current implementation, the measurement list is not updated in the
buffer during the window between kexec load and execute.  This leads to
measurement loss in the buffer when transitioning from the old to the new
kernel.  This patch provides a way to update the measurement list in the
buffer during a kexec execution.  Suspending the measurements during the
buffer update ensures the buffer doesn't get corrupted, or goes out of
sync with TPM PCRs. Thus it ensures the integrity of measurements is
maintained across kernel transitions during a kexec.

Introduce a new variable ima_kexec_buffer that is used to hold the address
of the IMA kexec buffer.

Implement a function ima_update_kexec_buffer() that is called during
kexec execute, allowing the IMA to update the measurement list with the
events between kexec load and execute.  First check if a kexec is in
progress and if the IMA kexec buffer is initialized.  If these conditions
are met, suspend IMA measurements and check if the new buffer size obtained
from ima_get_binary_runtime_size() is larger than the current buffer size.
If the new buffer size is too large, output an error message, and resume
the measurements.

If the new buffer size fits, populate the new buffer with the current
measurements using ima_populate_buf_at_kexec_execute() and copy it into
ima_kexec_buffer.

Unmap ima_kexec_buffer segment from the image.  Resuming the measurements
is not needed in case of successful measurements since the control is being
passed to the new kernel anyways through kexec execute.  However, the
measurements should be resumed if there are any errors flagged in the
function.

Signed-off-by: Tushar Sugandhi <tusharsu at linux.microsoft.com>
---
 security/integrity/ima/ima_kexec.c | 50 ++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
index 7deb8df31485..224d88ccfe85 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -18,6 +18,7 @@
 struct seq_file ima_kexec_file;
 struct ima_kexec_hdr ima_khdr;
 static size_t kexec_segment_size;
+static void *ima_kexec_buffer;
 
 void ima_clear_kexec_file(void)
 {
@@ -230,6 +231,55 @@ 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 *new_buffer = NULL;
+	size_t new_buffer_size, cur_buffer_size;
+	bool resume = false;
+
+	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();
+
+	cur_buffer_size = kexec_segment_size - sizeof(struct ima_kexec_hdr);
+	new_buffer_size = ima_get_binary_runtime_size();
+	if (new_buffer_size > cur_buffer_size) {
+		pr_err("%s: Measurement list grew too large.\n", __func__);
+		resume = true;
+		goto out;
+	}
+
+	ima_populate_buf_at_kexec_execute(&new_buffer_size, &new_buffer);
+
+	if (!new_buffer) {
+		pr_err("%s: Dump measurements failed.\n", __func__);
+		resume = true;
+		goto out;
+	}
+	memcpy(ima_kexec_buffer, new_buffer, new_buffer_size);
+out:
+	kimage_unmap_segment(ima_kexec_buffer);
+	ima_kexec_buffer = NULL;
+
+	if (resume)
+		ima_measurements_resume();
+
+	return NOTIFY_OK;
+}
+
 #endif /* IMA_KEXEC */
 
 /*
-- 
2.25.1




More information about the kexec mailing list