* [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute
@ 2025-03-18 1:04 steven chen
2025-03-18 1:04 ` [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file" steven chen
` (7 more replies)
0 siblings, 8 replies; 34+ messages in thread
From: steven chen @ 2025-03-18 1:04 UTC (permalink / raw)
To: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
The current kernel behavior is IMA measurements snapshot is taken at
kexec 'load' and not at kexec 'execute'. IMA log is then carried
over to the new kernel after kexec 'execute'.
Currently, the kernel behavior during kexec load is to fetch the IMA
measurements log from TPM PCRs and store it in a buffer. When a kexec
reboot is triggered, this stored log buffer is carried over to the second
kernel. However, the time gap between kexec load and kexec reboot can be
very long. During this time window, new events extended into TPM PCRs miss
the chance to be carried over to the second kernel. This results in
mismatch between TPM PCR quotes and the actual IMA measurements list after
kexec soft reboot, which in turn results in remote attestation failure.
To solve this problem -
- allocate the necessary buffer at kexec 'load' time,
- populate the buffer with the IMA measurements at kexec 'execute' time,
- and measure two new IMA events 'kexec_load' and 'kexec_execute' as
critical data to help detect missing events after kexec soft reboot.
The solution details include:
- refactoring the existing code to allocate a buffer to hold IMA
measurements at kexec 'load', and dump the measurements at kexec
'execute'
- kexec functionality for mapping the segments from the current kernel
to the subsequent one,
- necessary changes to the kexec_file_load syscall, enabling it to call
the ima functions,
- registering a reboot notifier which gets called during kexec 'execute',
- introducing a new Kconfig option to configure the extra memory to be
allocated for passing IMA log from the current Kernel to the next,
- introducing two new events to be measured by IMA during kexec, to
help diagnose if the IMA log was copied fully or partially, from the
current Kernel to the next,
- excluding IMA segment while calculating and storing digest in function
kexec_calculate_store_digests(), since IMA segment can be modified
after the digest is computed during kexec 'load'. This will ensure
that the segment is not added to the 'purgatory_sha_regions', and thus
not verified by verify_sha256_digest().
The changes proposed in this series ensure the integrity of the IMA
measurements is preserved across kexec soft reboots, thus significantly
improving the security of the kernel post kexec soft reboots.
There were previous attempts to fix this issue [1], [2], [3]. But they
were not merged into the mainline kernel.
We took inspiration from the past work [1] and [2] while working on this
patch series.
V4 of this series is available here[6] for reference.
V5 of this series is available here[7] for reference.
V6 of this series is available here[8] for reference.
V7 of this series is available here[9] for reference.
V8 of this series is available here[10] for reference.
V9 of this series is available here[11] for reference.
References:
-----------
[1] [PATHC v2 5/9] ima: on soft reboot, save the measurement list
https://lore.kernel.org/lkml/1472596811-9596-6-git-send-email-zohar@linux.vnet.ibm.com/
[2] PATCH v2 4/6] kexec_file: Add mechanism to update kexec segments.
https://lkml.org/lkml/2016/8/16/577
[3] [PATCH 1/6] kexec_file: Add buffer hand-over support
https://lore.kernel.org/linuxppc-dev/1466473476-10104-6-git-send-email-bauerman@linux.vnet.ibm.com/T/
[4] [PATCH v2 0/7] ima: kexec: measure events between kexec load and execute
https://lore.kernel.org/all/20231005182602.634615-1-tusharsu@linux.microsoft.com/
[5] [PATCH v3 0/7] ima: kexec: measure events between kexec load and execute
https://lore.kernel.org/all/20231216010729.2904751-1-tusharsu@linux.microsoft.com/
[6] [PATCH v4 0/7] ima: kexec: measure events between kexec load and execute
https://lore.kernel.org/all/20240122183804.3293904-1-tusharsu@linux.microsoft.com/
[7] [PATCH v5 0/8] ima: kexec: measure events between kexec load and execute
https://lore.kernel.org/all/20240214153827.1087657-1-tusharsu@linux.microsoft.com/
[8] [PATCH v6 0/7] ima: kexec: measure events between kexec load and execute
https://lore.kernel.org/all/20250124225547.22684-1-chenste@linux.microsoft.com/
[9] [PATCH v7 0/7] ima: kexec: measure events between kexec load and execute
https://lore.kernel.org/all/20250203232033.64123-1-chenste@linux.microsoft.com/
[10] [PATCH v8 0/7] ima: kexec: measure events between kexec load and execute
https://lore.kernel.org/all/20250218225502.747963-1-chenste@linux.microsoft.com/
[11] [PATCH v9 0/7] ima: kexec: measure events between kexec load and execute
https://lore.kernel.org/all/20250304190351.96975-1-chenste@linux.microsoft.com/
Change Log v10:
- Incorporated feedback from the community (Mimi Zohar, Baoquan He, and
kernel test robot) on v9 of this series[11].
- [PATCH V9 1/7] was splited into two [PATCH V10 1/8] and [PATCH V10 2/8].
Per Mimi comment on [PATCH V9 1/7].
- Verified all the patches are bisect-safe by booting into each
patch and verifying multiple kexec 'load' operations work,
and also verifying kexec soft reboot works, and IMA log gets
carried over for each patch.
Change Log v9:
- Incorporated feedback from the community (Stefan Berger, Mimi Zohar,
and kernel test robot) on v8 of this series[10].
- Rebased the patch series to mainline 6.14.0-rc3.
- Verified all the patches are bisect-safe by booting into each
patch and verifying multiple kexec 'load' operations work,
and also verifying kexec soft reboot works, and IMA log gets
carried over for each patch.
Change Log v8:
- Incorporated feedback from the community (Stefan Berger, Mimi Zohar)
on v7 of this series[9].
- Rebased the patch series to mainline 6.14.0-rc1.
- Verified all the patches are bisect-safe by booting into each
patch and verifying multiple kexec 'load' operations work,
and also verifying kexec soft reboot works, and IMA log gets
carried over for each patch.
Change Log v7:
- Incorporated feedback from the community (Stefan Berger, Tyler Hicks)
on v6 of this series[8].
- Verified all the patches are bisect-safe by booting into each
patch and verifying multiple kexec 'load' operations work,
and also verifying kexec soft reboot works, and IMA log gets
carried over for each patch.
Change Log v6:
- Incorporated feedback from the community (Stefan Berger, Mimi Zohar,
and Petr Tesařík) on v5 of this series[7].
- Rebased the patch series to mainline 6.12.0.
- Verified all the patches are bisect-safe by booting into each
patch and verifying multiple kexec 'load' operations work,
and also verifying kexec soft reboot works, and IMA log gets
carried over for each patch.
- 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.
- [PATCH V5 6/8] was removed. Per petr comment on [PATCH V5 6/8], during
the handover, other CPUs are taken offline (look for
migrate_to_reboot_cpu() in kernel/kexec_core.c) and even the reboot CPU
will be sufficiently shut down as not to be able to add any more
measurements.
Change Log v5:
- Incorporated feedback from the community (Stefan Berger and
Mimi Zohar) on v4 of this series[6].
- Rebased the patch series to mainline 6.8.0-rc1.
- Verified all the patches are bisect-safe by booting into each
patch and verifying multiple kexec 'load' operations work,
and also verifying kexec soft reboot works, and IMA log gets
carried over for each patch.
- Divided the patch #4 in the v4 of the series[6] into two separate
patches. One to setup the infrastructure/stub functions to prepare
the IMA log copy from Kexec 'load' to 'execute', and another one
to actually copy the log.
- Updated the config description for IMA_KEXEC_EXTRA_MEMORY_KB
to remove unnecessary references related to backwards compatibility.
- Fixed a typo in log message/removed an extra line etc.
- Updated patch descriptions as necessary.
Change Log v4:
- Incorporated feedback from the community (Stefan Berger and
Mimi Zohar) on v3 of this series[5].
- Rearranged patches so that they remain bisect-safe i.e. the
system can go through kexec soft reboot, and IMA log is carried
over after each patch.
- Verified all the patches are bisect-safe by booting into each
patch and verifying kexec soft reboot works, and IMA log gets
carried over.
- Suspend-resume measurements is now a separate patch (patch #5)
and all the relevant code is part of the same patch.
- Excluding IMA segment from segment digest verification is now a
separate patch. (patch #3).
- Registering reboot notifier and functions related to move ima
log copy from kexec load to execute are now part of the same
patch (patch #4) to protect bisect-safeness of the series.
- Updated the title of patch #6 as per the feedback.
- The default value of kexec extra memory for IMA measurements
is set to half the PAGESIZE to maintain backwards compatibility.
- Added number of IMA measurement records as part of 'kexec_load'
and 'kexec_execute' IMA critical data events.
- Updated patch descriptions as necessary.
Change Log v3:
- Incorporated feedback from the community (Stefan Berger and
Mimi Zohar) on v2 of this series[4].
- Renamed functions and removed extraneous checks and code comments.
- Updated patch descriptions and titles as necessary.
- Updated kexec_calculate_store_digests() in patch 2/7 to exclude ima
segment from calculating and storing digest.
- Updated patch 3/7 to use kmalloc_array instead of kmalloc and freed
memory early to avoid potential memory leak.
- Updated patch 6/7 to change Kconfig option IMA_KEXEC_EXTRA_PAGES to
IMA_KEXEC_EXTRA_MEMORY_KB to allocate the memory in kb rather than
in number of pages.
- Optimized patch 7/7 not to free and alloc memory if the buffer size
hasn't changed during multiple kexec 'load' operations.
- Fixed a bug in patch 7/7 to measure multiple 'kexec_load' events even
if buffer size hasn't changed.
- Verified the patches are bisect-safe by compiling and booting into
each patch individually.
Change Log v2:
- Incorporated feedback from the community on v1 series.
- Refactored the existing ima_dump_measurement_list to move buffer
allocation functionality to ima_alloc_kexec_buf() function.
- Introduced a new Kconfig option to configure the memory.
- Updated the logic to copy the IMA log only in case of kexec soft
reboot, and not on kexec crash.
- Updated the logic to copy as many IMA events as possible in case of
memory constraint, rather than just bailing out.
- Introduced two new events to be measured by IMA during kexec, to
help diagnose if the IMA log was copied fully or partially from the
current Kernel to the next.
- Refactored patches to ensure no warnings during individual patch
compilation.
- Used virt_to_page instead of phys_to_page.
- Updated patch descriptions as necessary.
steven chen (8):
ima: rename variable the ser_file "file" to "ima_kexec_file"
ima: define and call ima_alloc_kexec_file_buf()
kexec: define functions to map and unmap segments
ima: kexec: skip IMA segment validation after kexec soft reboot
ima: kexec: define functions to copy IMA log at soft boot
ima: kexec: move IMA log copy from kexec load to execute
ima: make the kexec extra memory configurable
ima: measure kexec load and exec events as critical data
include/linux/ima.h | 3 +
include/linux/kexec.h | 9 ++
kernel/kexec_core.c | 54 ++++++++
kernel/kexec_file.c | 32 +++++
security/integrity/ima/Kconfig | 10 ++
security/integrity/ima/ima.h | 6 +
security/integrity/ima/ima_kexec.c | 206 ++++++++++++++++++++++++-----
security/integrity/ima/ima_queue.c | 5 +
8 files changed, 292 insertions(+), 33 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file"
2025-03-18 1:04 [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute steven chen
@ 2025-03-18 1:04 ` steven chen
2025-03-18 15:10 ` Stefan Berger
2025-03-19 13:42 ` Mimi Zohar
2025-03-18 1:04 ` [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf() steven chen
` (6 subsequent siblings)
7 siblings, 2 replies; 34+ messages in thread
From: steven chen @ 2025-03-18 1:04 UTC (permalink / raw)
To: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
The name of the local variable "file" of type seq_file defined in the
ima_dump_measurement_list function is too generic. To better reflect the
purpose of the variable, rename it to "ima_kexec_file". This change will
help improve code readability and maintainability by making the variable's
role more explicit.
The variable ima_kexec_file is indeed the memory allocated for copying IMA
measurement records. The ima_dump_measurement_list function calculates the
actual memory occupied by the IMA logs and compares it with the allocated
memory. If there is enough memory, it copies all IMA measurement records;
otherwise, it does not copy any records, which would result in a failure
of remote attestation.
Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
Signed-off-by: steven chen <chenste@linux.microsoft.com>
---
security/integrity/ima/ima_kexec.c | 39 ++++++++++++++++++------------
1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
index 9d45f4d26f73..8567619889d1 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -15,33 +15,41 @@
#include "ima.h"
#ifdef CONFIG_IMA_KEXEC
+/*
+ * Copy the measurement list to the allocated memory
+ * compare the size of IMA measurement list with the size of the allocated memory
+ * 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
+ */
static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
unsigned long segment_size)
{
+ struct seq_file ima_kexec_file;
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) {
+ ima_kexec_file.buf = vmalloc(segment_size);
+ if (!ima_kexec_file.buf) {
ret = -ENOMEM;
goto out;
}
- file.file = NULL;
- file.size = segment_size;
- file.read_pos = 0;
- file.count = sizeof(khdr); /* reserved space */
+ ima_kexec_file.file = NULL;
+ ima_kexec_file.size = segment_size;
+ ima_kexec_file.read_pos = 0;
+ ima_kexec_file.count = sizeof(khdr); /* reserved space */
memset(&khdr, 0, sizeof(khdr));
khdr.version = 1;
/* This is an append-only list, no need to hold the RCU read lock */
list_for_each_entry_rcu(qe, &ima_measurements, later, true) {
- if (file.count < file.size) {
+ if (ima_kexec_file.count < ima_kexec_file.size) {
khdr.count++;
- ima_measurements_show(&file, qe);
+ ima_measurements_show(&ima_kexec_file, qe);
} else {
ret = -EINVAL;
break;
@@ -55,23 +63,24 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
* 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;
+ *buffer_size = ima_kexec_file.count;
+ *buffer = ima_kexec_file.buf;
out:
if (ret == -EINVAL)
- vfree(file.buf);
+ vfree(ima_kexec_file.buf);
return ret;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf()
2025-03-18 1:04 [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute steven chen
2025-03-18 1:04 ` [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file" steven chen
@ 2025-03-18 1:04 ` steven chen
2025-03-19 8:09 ` Baoquan He
2025-03-18 1:04 ` [PATCH v10 3/8] kexec: define functions to map and unmap segments steven chen
` (5 subsequent siblings)
7 siblings, 1 reply; 34+ messages in thread
From: steven chen @ 2025-03-18 1:04 UTC (permalink / raw)
To: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
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().
- Make necessary changes to the function ima_add_kexec_buffer() to call
the above two functions.
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
Signed-off-by: steven chen <chenste@linux.microsoft.com>
---
security/integrity/ima/ima_kexec.c | 67 +++++++++++++++++++++++++-----
1 file changed, 56 insertions(+), 11 deletions(-)
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
index 8567619889d1..45170e283272 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -15,6 +15,48 @@
#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;
+}
+
/*
* Copy the measurement list to the allocated memory
* compare the size of IMA measurement list with the size of the allocated memory
@@ -26,23 +68,16 @@
static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
unsigned long segment_size)
{
- struct seq_file ima_kexec_file;
struct ima_queue_entry *qe;
struct ima_kexec_hdr khdr;
int ret = 0;
/* segment size can't change between kexec load and execute */
- ima_kexec_file.buf = vmalloc(segment_size);
if (!ima_kexec_file.buf) {
- ret = -ENOMEM;
- goto out;
+ pr_err("Kexec file buf not allocated\n");
+ return -EINVAL;
}
- ima_kexec_file.file = NULL;
- ima_kexec_file.size = segment_size;
- ima_kexec_file.read_pos = 0;
- ima_kexec_file.count = sizeof(khdr); /* reserved space */
-
memset(&khdr, 0, sizeof(khdr));
khdr.version = 1;
/* This is an append-only list, no need to hold the RCU read lock */
@@ -79,8 +114,6 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
*buffer_size = ima_kexec_file.count;
*buffer = ima_kexec_file.buf;
out:
- if (ret == -EINVAL)
- vfree(ima_kexec_file.buf);
return ret;
}
@@ -119,6 +152,12 @@ void ima_add_kexec_buffer(struct kimage *image)
return;
}
+ ret = ima_alloc_kexec_file_buf(kexec_segment_size);
+ if (ret < 0) {
+ pr_err("Not enough memory for the kexec measurement buffer.\n");
+ return;
+ }
+
ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
kexec_segment_size);
if (!kexec_buffer) {
@@ -140,6 +179,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);
}
--
2.25.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v10 3/8] kexec: define functions to map and unmap segments
2025-03-18 1:04 [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute steven chen
2025-03-18 1:04 ` [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file" steven chen
2025-03-18 1:04 ` [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf() steven chen
@ 2025-03-18 1:04 ` steven chen
2025-03-19 10:12 ` Baoquan He
2025-03-18 1:04 ` [PATCH v10 4/8] ima: kexec: skip IMA segment validation after kexec soft reboot steven chen
` (4 subsequent siblings)
7 siblings, 1 reply; 34+ messages in thread
From: steven chen @ 2025-03-18 1:04 UTC (permalink / raw)
To: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
Currently, the kernel behavior during kexec load is to fetch the IMA
measurements log from TPM PCRs and store it in a buffer. When a kexec
reboot is triggered, this stored log buffer is carried over to the second
kernel. However, the time gap between kexec load and kexec reboot can be
very long. During this time window, new events extended into TPM PCRs miss
the chance to be carried over to the second kernel. This results in a
mismatch between TPM PCR quotes and the actual IMA measurements list after
kexec reboot, leading to remote attestation failure.
To solve this problem, the new design defers reading TPM PCRs content into
the kexec buffer to the kexec reboot phase, while still allocating the
necessary buffer at kexec load time because it is not appropriate to
allocate memory at the kexec reboot moment.
The content of memory segments carried over to the new kernel during the
kexec system call can be changed at the kexec 'execute' stage, but the size
of the memory segments cannot be changed at the kexec 'execute' stage.
To copy IMA measurement logs during the kexec operation, IMA allocates
memory at the kexec 'load' stage and map the segments to the kimage
structure. The mapped address will then be used to copy IMA measurements
during the kexec 'execute' stage.
Currently, the mechanism to map and unmap segments to the kimage structure
is not available to subsystems outside of kexec.
Implement kimage_map_segment() to enable IMA to map the measurement log
list to the kimage structure during the kexec 'load' stage. This function
takes a kimage pointer, a memory address, and a size, then gathers the
source pages within the specified address range, creates an array of page
pointers, and maps these to a contiguous virtual address range. The
function returns the start virtual address of this range if successful,
or NULL on failure.
Implement kimage_unmap_segment() for unmapping segments using vunmap().
From: Tushar Sugandhi <tusharsu@linux.microsoft.com>
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: steven chen <chenste@linux.microsoft.com>
---
include/linux/kexec.h | 6 +++++
kernel/kexec_core.c | 54 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 60 insertions(+)
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index f0e9f8eda7a3..7d6b12f8b8d0 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -467,13 +467,19 @@ 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;
+struct kimage;
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 c0bdc1686154..a5e378e1dc7f 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 src_page_addr, dest_page_addr = 0;
+ unsigned long eaddr = addr + size;
+ kimage_entry_t *ptr, entry;
+ struct page **src_pages;
+ unsigned int npages;
+ void *vaddr = NULL;
+ int i;
+
+ /*
+ * 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;
--
2.25.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v10 4/8] ima: kexec: skip IMA segment validation after kexec soft reboot
2025-03-18 1:04 [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute steven chen
` (2 preceding siblings ...)
2025-03-18 1:04 ` [PATCH v10 3/8] kexec: define functions to map and unmap segments steven chen
@ 2025-03-18 1:04 ` steven chen
2025-03-19 10:16 ` Baoquan He
2025-03-18 1:04 ` [PATCH v10 5/8] ima: kexec: define functions to copy IMA log at soft boot steven chen
` (3 subsequent siblings)
7 siblings, 1 reply; 34+ messages in thread
From: steven chen @ 2025-03-18 1:04 UTC (permalink / raw)
To: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
With this series, the IMA segment will be updated with the measurement
log at the kexec execute stage when a soft reboot is initiated.
Therefore, the digests should be updated for the IMA segment in the
normal case.
The content of memory segments carried over to the new kernel during the
kexec systemcall can be changed at kexec 'execute' stage, but the size
and the location of the memory segments cannot be changed at kexec
'execute' stage.
However, during the kexec execute stage, if kexec_calculate_store_digests()
API is called to update the digest, it does not reuse the same memory
segment allocated during the kexec 'load' stage and the new memory segment
required cannot be transferred/mapped to the new kernel.
As a result, digest verification will fail in verify_sha256_digest()
after a kexec soft reboot into the new kernel. Therefore, the digest
calculation/verification of the IMA segment needs to be skipped.
To address this, skip the calculation and storage of the digest for the
IMA segment in 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.
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: steven chen <chenste@linux.microsoft.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
include/linux/kexec.h | 3 +++
kernel/kexec_file.c | 22 ++++++++++++++++++++++
security/integrity/ima/ima_kexec.c | 3 +++
3 files changed, 28 insertions(+)
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 7d6b12f8b8d0..107e726f2ef3 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..606132253c79 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -38,6 +38,21 @@ 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 +779,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 45170e283272..34020b1513b0 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -168,6 +168,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");
@@ -178,6 +179,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
--
2.25.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v10 5/8] ima: kexec: define functions to copy IMA log at soft boot
2025-03-18 1:04 [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute steven chen
` (3 preceding siblings ...)
2025-03-18 1:04 ` [PATCH v10 4/8] ima: kexec: skip IMA segment validation after kexec soft reboot steven chen
@ 2025-03-18 1:04 ` steven chen
2025-03-18 1:04 ` [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute steven chen
` (2 subsequent siblings)
7 siblings, 0 replies; 34+ messages in thread
From: steven chen @ 2025-03-18 1:04 UTC (permalink / raw)
To: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
The IMA log is currently copied to the new kernel during kexec 'load'
using ima_dump_measurement_list(). However, the log copied at kexec
'load' may result in loss of IMA measurements that only occurred after
kexec "load'. Therefore, the log needs to be copied 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
kexec 'execute'.
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: steven chen <chenste@linux.microsoft.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: steven chen <chenste@linux.microsoft.com>
---
include/linux/ima.h | 3 ++
security/integrity/ima/ima_kexec.c | 47 ++++++++++++++++++++++++++++++
2 files changed, 50 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 34020b1513b0..9336c4f60650 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -12,10 +12,14 @@
#include <linux/kexec.h>
#include <linux/of.h>
#include <linux/ima.h>
+#include <linux/reboot.h>
+#include <asm/page.h>
#include "ima.h"
#ifdef CONFIG_IMA_KEXEC
+static bool ima_kexec_update_registered;
static struct seq_file ima_kexec_file;
+static void *ima_kexec_buffer;
static void ima_reset_kexec_file(struct seq_file *sf)
{
@@ -191,6 +195,49 @@ 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;
+}
+
+static struct notifier_block update_buffer_nb = {
+ .notifier_call = ima_update_kexec_buffer,
+ .priority = 1,
+};
+
+/*
+ * 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 */
/*
--
2.25.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-18 1:04 [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute steven chen
` (4 preceding siblings ...)
2025-03-18 1:04 ` [PATCH v10 5/8] ima: kexec: define functions to copy IMA log at soft boot steven chen
@ 2025-03-18 1:04 ` steven chen
2025-03-19 20:53 ` Mimi Zohar
2025-03-20 2:06 ` Baoquan He
2025-03-18 1:04 ` [PATCH v10 7/8] ima: make the kexec extra memory configurable steven chen
2025-03-18 1:04 ` [PATCH v10 8/8] ima: measure kexec load and exec events as critical data steven chen
7 siblings, 2 replies; 34+ messages in thread
From: steven chen @ 2025-03-18 1:04 UTC (permalink / raw)
To: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
ima_dump_measurement_list() is called during kexec 'load', which may
result in loss of IMA measurements during kexec soft reboot. Due to
missed measurements that only occurred after kexec 'load', this function
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
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 <tusharsu@linux.microsoft.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: steven chen <chenste@linux.microsoft.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
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
+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, 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 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;
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 **buffer,
unsigned long segment_size)
@@ -95,9 +96,6 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
}
}
- 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 *buffer_size, void **buffer,
*buffer_size = ima_kexec_file.count;
*buffer = ima_kexec_file.buf;
-out:
+
return ret;
}
@@ -135,9 +133,8 @@ void ima_add_kexec_buffer(struct kimage *image)
unsigned long binary_runtime_size;
/* use more understandable variable names than defined in kbuf */
+ size_t kexec_buffer_size = 0;
void *kexec_buffer = NULL;
- size_t kexec_buffer_size;
- size_t kexec_segment_size;
int ret;
/*
@@ -162,13 +159,6 @@ void ima_add_kexec_buffer(struct kimage *image)
return;
}
- 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 = kexec_buffer;
kbuf.bufsz = kexec_buffer_size;
kbuf.memsz = kexec_segment_size;
@@ -186,12 +176,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);
}
@@ -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 = 0;
+ int ret = NOTIFY_OK;
+ void *buf = 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 = 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;
}
static struct notifier_block update_buffer_nb = {
--
2.25.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v10 7/8] ima: make the kexec extra memory configurable
2025-03-18 1:04 [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute steven chen
` (5 preceding siblings ...)
2025-03-18 1:04 ` [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute steven chen
@ 2025-03-18 1:04 ` steven chen
2025-03-20 2:52 ` Baoquan He
2025-03-18 1:04 ` [PATCH v10 8/8] ima: measure kexec load and exec events as critical data steven chen
7 siblings, 1 reply; 34+ messages in thread
From: steven chen @ 2025-03-18 1:04 UTC (permalink / raw)
To: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
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.
Suggested-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
Signed-off-by: steven chen <chenste@linux.microsoft.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
---
security/integrity/ima/Kconfig | 10 ++++++++++
security/integrity/ima/ima_kexec.c | 16 +++++++++++-----
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 475c32615006..d73c96c3c1c9 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 of 0, an extra half 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 c390c745f882..0f214e41dd33 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -131,6 +131,7 @@ 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_memory;
/* use more understandable variable names than defined in kbuf */
size_t kexec_buffer_size = 0;
@@ -138,15 +139,20 @@ 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 during kexec.
*/
- binary_runtime_size = ima_get_binary_runtime_size();
+ if (CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB <= 0)
+ extra_memory = PAGE_SIZE / 2;
+ else
+ extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
+
+ binary_runtime_size = ima_get_binary_runtime_size() + extra_memory;
+
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");
--
2.25.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v10 8/8] ima: measure kexec load and exec events as critical data
2025-03-18 1:04 [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute steven chen
` (6 preceding siblings ...)
2025-03-18 1:04 ` [PATCH v10 7/8] ima: make the kexec extra memory configurable steven chen
@ 2025-03-18 1:04 ` steven chen
2025-03-20 2:59 ` Mimi Zohar
7 siblings, 1 reply; 34+ messages in thread
From: steven chen @ 2025-03-18 1:04 UTC (permalink / raw)
To: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
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.
These critical data events are displayed as hex encoded ascii in the
ascii_runtime_measurement_list. Verifying the critical data hash requires
calculating the hash of the decoded ascii string.
For example, to verify the 'kexec_load' data hash:
sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements
| grep kexec_load | cut -d' ' -f 6 | xxd -r -p | sha256sum
To verify the 'kexec_execute' data hash:
sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements
| grep kexec_execute | cut -d' ' -f 6 | xxd -r -p | sha256sum
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
Signed-off-by: steven chen <chenste@linux.microsoft.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
security/integrity/ima/ima.h | 6 ++++++
security/integrity/ima/ima_kexec.c | 21 +++++++++++++++++++++
security/integrity/ima/ima_queue.c | 5 +++++
3 files changed, 32 insertions(+)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 24d09ea91b87..34815baf5e21 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -240,6 +240,12 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
unsigned long flags, bool create);
#endif
+#ifdef CONFIG_IMA_KEXEC
+void ima_measure_kexec_event(const char *event_name);
+#else
+static inline void ima_measure_kexec_event(const char *event_name) {}
+#endif
+
/*
* The default binary_runtime_measurements list format is defined as the
* platform native format. The canonical format is defined as little-endian.
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
index 0f214e41dd33..43223eb99046 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 bool ima_kexec_update_registered;
static struct seq_file ima_kexec_file;
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);
}
+void ima_measure_kexec_event(const char *event_name)
+{
+ char ima_kexec_event[IMA_KEXEC_EVENT_LEN];
+ size_t buf_size = 0;
+ long len;
+ int n;
+
+ buf_size = ima_get_binary_runtime_size();
+ len = atomic_long_read(&ima_htable.len);
+
+ n = 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, n, false, NULL, 0);
+}
+
static int ima_alloc_kexec_file_buf(size_t segment_size)
{
/*
@@ -58,6 +78,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;
}
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 83d53824aa98..590637e81ad1 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -241,6 +241,11 @@ static int ima_reboot_notifier(struct notifier_block *nb,
unsigned long action,
void *data)
{
+#ifdef CONFIG_IMA_KEXEC
+ if (action == SYS_RESTART && data && !strcmp(data, "kexec reboot"))
+ ima_measure_kexec_event("kexec_execute");
+#endif
+
ima_measurements_suspend();
return NOTIFY_DONE;
--
2.25.1
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file"
2025-03-18 1:04 ` [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file" steven chen
@ 2025-03-18 15:10 ` Stefan Berger
2025-03-19 2:43 ` Baoquan He
2025-03-19 13:42 ` Mimi Zohar
1 sibling, 1 reply; 34+ messages in thread
From: Stefan Berger @ 2025-03-18 15:10 UTC (permalink / raw)
To: steven chen, zohar, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
On 3/17/25 9:04 PM, steven chen wrote:
> The name of the local variable "file" of type seq_file defined in the
> ima_dump_measurement_list function is too generic. To better reflect the
> purpose of the variable, rename it to "ima_kexec_file". This change will
> help improve code readability and maintainability by making the variable's
> role more explicit.
>
> The variable ima_kexec_file is indeed the memory allocated for copying IMA
> measurement records. The ima_dump_measurement_list function calculates the
> actual memory occupied by the IMA logs and compares it with the allocated
> memory. If there is enough memory, it copies all IMA measurement records;
> otherwise, it does not copy any records, which would result in a failure
> of remote attestation.
>
> Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
> Signed-off-by: steven chen <chenste@linux.microsoft.com>
> ---
> security/integrity/ima/ima_kexec.c | 39 ++++++++++++++++++------------
> 1 file changed, 24 insertions(+), 15 deletions(-)
>
> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> index 9d45f4d26f73..8567619889d1 100644
> --- a/security/integrity/ima/ima_kexec.c
> +++ b/security/integrity/ima/ima_kexec.c
> @@ -15,33 +15,41 @@
> #include "ima.h"
>
> #ifdef CONFIG_IMA_KEXEC
> +/*
> + * Copy the measurement list to the allocated memory
> + * compare the size of IMA measurement list with the size of the allocated memory
Compare the size of the IMA ... memory.
> + * 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
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,
return an error otherwise.
Looked a bit unusual. With this nit:
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> + */
> static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> unsigned long segment_size)
> {
> + struct seq_file ima_kexec_file;
> 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) {
> + ima_kexec_file.buf = vmalloc(segment_size);
> + if (!ima_kexec_file.buf) {
> ret = -ENOMEM;
> goto out;
> }
>
> - file.file = NULL;
> - file.size = segment_size;
> - file.read_pos = 0;
> - file.count = sizeof(khdr); /* reserved space */
> + ima_kexec_file.file = NULL;
> + ima_kexec_file.size = segment_size;
> + ima_kexec_file.read_pos = 0;
> + ima_kexec_file.count = sizeof(khdr); /* reserved space */
>
> memset(&khdr, 0, sizeof(khdr));
> khdr.version = 1;
> /* This is an append-only list, no need to hold the RCU read lock */
> list_for_each_entry_rcu(qe, &ima_measurements, later, true) {
> - if (file.count < file.size) {
> + if (ima_kexec_file.count < ima_kexec_file.size) {
> khdr.count++;
> - ima_measurements_show(&file, qe);
> + ima_measurements_show(&ima_kexec_file, qe);
> } else {
> ret = -EINVAL;
> break;
> @@ -55,23 +63,24 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> * 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;
> + *buffer_size = ima_kexec_file.count;
> + *buffer = ima_kexec_file.buf;
> out:
> if (ret == -EINVAL)
> - vfree(file.buf);
> + vfree(ima_kexec_file.buf);
> return ret;
> }
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file"
2025-03-18 15:10 ` Stefan Berger
@ 2025-03-19 2:43 ` Baoquan He
2025-03-21 16:15 ` steven chen
0 siblings, 1 reply; 34+ messages in thread
From: Baoquan He @ 2025-03-19 2:43 UTC (permalink / raw)
To: Stefan Berger
Cc: steven chen, zohar, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 03/18/25 at 11:10am, Stefan Berger wrote:
>
>
> On 3/17/25 9:04 PM, steven chen wrote:
> > The name of the local variable "file" of type seq_file defined in the
> > ima_dump_measurement_list function is too generic. To better reflect the
> > purpose of the variable, rename it to "ima_kexec_file". This change will
> > help improve code readability and maintainability by making the variable's
> > role more explicit.
> >
> > The variable ima_kexec_file is indeed the memory allocated for copying IMA
> > measurement records. The ima_dump_measurement_list function calculates the
> > actual memory occupied by the IMA logs and compares it with the allocated
> > memory. If there is enough memory, it copies all IMA measurement records;
> > otherwise, it does not copy any records, which would result in a failure
> > of remote attestation.
> >
> > Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
> > Signed-off-by: steven chen <chenste@linux.microsoft.com>
>
>
> > ---
> > security/integrity/ima/ima_kexec.c | 39 ++++++++++++++++++------------
> > 1 file changed, 24 insertions(+), 15 deletions(-)
> >
> > diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> > index 9d45f4d26f73..8567619889d1 100644
> > --- a/security/integrity/ima/ima_kexec.c
> > +++ b/security/integrity/ima/ima_kexec.c
> > @@ -15,33 +15,41 @@
> > #include "ima.h"
> > #ifdef CONFIG_IMA_KEXEC
> > +/*
> > + * Copy the measurement list to the allocated memory
> > + * compare the size of IMA measurement list with the size of the allocated memory
>
> Compare the size of the IMA ... memory.
>
>
> > + * 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
>
> 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, return
> an error otherwise.
Ack the suggested change.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf()
2025-03-18 1:04 ` [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf() steven chen
@ 2025-03-19 8:09 ` Baoquan He
2025-03-19 16:27 ` Mimi Zohar
0 siblings, 1 reply; 34+ messages in thread
From: Baoquan He @ 2025-03-19 8:09 UTC (permalink / raw)
To: steven chen
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 03/17/25 at 06:04pm, steven chen wrote:
> 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().
> - Make necessary changes to the function ima_add_kexec_buffer() to call
> the above two functions.
We may not need above details about code change because it's not so
difficult to get them from patch.
>
> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> Signed-off-by: steven chen <chenste@linux.microsoft.com>
> ---
> security/integrity/ima/ima_kexec.c | 67 +++++++++++++++++++++++++-----
> 1 file changed, 56 insertions(+), 11 deletions(-)
>
> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> index 8567619889d1..45170e283272 100644
> --- a/security/integrity/ima/ima_kexec.c
> +++ b/security/integrity/ima/ima_kexec.c
> @@ -15,6 +15,48 @@
> #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;
> +}
> +
> /*
> * Copy the measurement list to the allocated memory
> * compare the size of IMA measurement list with the size of the allocated memory
> @@ -26,23 +68,16 @@
> static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> unsigned long segment_size)
> {
> - struct seq_file ima_kexec_file;
> struct ima_queue_entry *qe;
> struct ima_kexec_hdr khdr;
> int ret = 0;
>
> /* segment size can't change between kexec load and execute */
> - ima_kexec_file.buf = vmalloc(segment_size);
> if (!ima_kexec_file.buf) {
> - ret = -ENOMEM;
> - goto out;
> + pr_err("Kexec file buf not allocated\n");
> + return -EINVAL;
> }
>
> - ima_kexec_file.file = NULL;
> - ima_kexec_file.size = segment_size;
> - ima_kexec_file.read_pos = 0;
> - ima_kexec_file.count = sizeof(khdr); /* reserved space */
> -
> memset(&khdr, 0, sizeof(khdr));
> khdr.version = 1;
> /* This is an append-only list, no need to hold the RCU read lock */
> @@ -79,8 +114,6 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> *buffer_size = ima_kexec_file.count;
> *buffer = ima_kexec_file.buf;
> out:
> - if (ret == -EINVAL)
> - vfree(ima_kexec_file.buf);
> return ret;
> }
>
> @@ -119,6 +152,12 @@ void ima_add_kexec_buffer(struct kimage *image)
> return;
> }
>
> + ret = ima_alloc_kexec_file_buf(kexec_segment_size);
> + if (ret < 0) {
> + pr_err("Not enough memory for the kexec measurement buffer.\n");
> + return;
> + }
> +
> ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
> kexec_segment_size);
> if (!kexec_buffer) {
> @@ -140,6 +179,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);
I can't see why we need call ima_reset_kexec_file() here. If we need
reuse the buffer, we will reset the needed fields at the end of
ima_alloc_kexec_file_buf(). Not sure if I miss anything.
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 */
return 0;
}
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 3/8] kexec: define functions to map and unmap segments
2025-03-18 1:04 ` [PATCH v10 3/8] kexec: define functions to map and unmap segments steven chen
@ 2025-03-19 10:12 ` Baoquan He
0 siblings, 0 replies; 34+ messages in thread
From: Baoquan He @ 2025-03-19 10:12 UTC (permalink / raw)
To: steven chen
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 03/17/25 at 06:04pm, steven chen wrote:
> Currently, the kernel behavior during kexec load is to fetch the IMA
> measurements log from TPM PCRs and store it in a buffer. When a kexec
> reboot is triggered, this stored log buffer is carried over to the second
> kernel. However, the time gap between kexec load and kexec reboot can be
> very long. During this time window, new events extended into TPM PCRs miss
> the chance to be carried over to the second kernel. This results in a
> mismatch between TPM PCR quotes and the actual IMA measurements list after
> kexec reboot, leading to remote attestation failure.
>
> To solve this problem, the new design defers reading TPM PCRs content into
> the kexec buffer to the kexec reboot phase, while still allocating the
> necessary buffer at kexec load time because it is not appropriate to
> allocate memory at the kexec reboot moment.
>
> The content of memory segments carried over to the new kernel during the
> kexec system call can be changed at the kexec 'execute' stage, but the size
> of the memory segments cannot be changed at the kexec 'execute' stage.
>
> To copy IMA measurement logs during the kexec operation, IMA allocates
> memory at the kexec 'load' stage and map the segments to the kimage
> structure. The mapped address will then be used to copy IMA measurements
> during the kexec 'execute' stage.
>
> Currently, the mechanism to map and unmap segments to the kimage structure
> is not available to subsystems outside of kexec.
>
> Implement kimage_map_segment() to enable IMA to map the measurement log
> list to the kimage structure during the kexec 'load' stage. This function
> takes a kimage pointer, a memory address, and a size, then gathers the
> source pages within the specified address range, creates an array of page
> pointers, and maps these to a contiguous virtual address range. The
> function returns the start virtual address of this range if successful,
> or NULL on failure.
>
> Implement kimage_unmap_segment() for unmapping segments using vunmap().
>
> From: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> Cc: Eric Biederman <ebiederm@xmission.com>
> Cc: Baoquan He <bhe@redhat.com>
> Cc: Vivek Goyal <vgoyal@redhat.com>
> Cc: Dave Young <dyoung@redhat.com>
> Signed-off-by: steven chen <chenste@linux.microsoft.com>
> ---
> include/linux/kexec.h | 6 +++++
> kernel/kexec_core.c | 54 +++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 60 insertions(+)
The log is a little verbose, otherwise it looks good to me.
Acked-by: Baoquan He <bhe@redhat.com>
>
> diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> index f0e9f8eda7a3..7d6b12f8b8d0 100644
> --- a/include/linux/kexec.h
> +++ b/include/linux/kexec.h
> @@ -467,13 +467,19 @@ 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;
> +struct kimage;
> 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 c0bdc1686154..a5e378e1dc7f 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 src_page_addr, dest_page_addr = 0;
> + unsigned long eaddr = addr + size;
> + kimage_entry_t *ptr, entry;
> + struct page **src_pages;
> + unsigned int npages;
> + void *vaddr = NULL;
> + int i;
> +
> + /*
> + * 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;
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 4/8] ima: kexec: skip IMA segment validation after kexec soft reboot
2025-03-18 1:04 ` [PATCH v10 4/8] ima: kexec: skip IMA segment validation after kexec soft reboot steven chen
@ 2025-03-19 10:16 ` Baoquan He
0 siblings, 0 replies; 34+ messages in thread
From: Baoquan He @ 2025-03-19 10:16 UTC (permalink / raw)
To: steven chen
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 03/17/25 at 06:04pm, steven chen wrote:
> With this series, the IMA segment will be updated with the measurement
> log at the kexec execute stage when a soft reboot is initiated.
> Therefore, the digests should be updated for the IMA segment in the
> normal case.
>
> The content of memory segments carried over to the new kernel during the
> kexec systemcall can be changed at kexec 'execute' stage, but the size
> and the location of the memory segments cannot be changed at kexec
> 'execute' stage.
>
> However, during the kexec execute stage, if kexec_calculate_store_digests()
> API is called to update the digest, it does not reuse the same memory
> segment allocated during the kexec 'load' stage and the new memory segment
> required cannot be transferred/mapped to the new kernel.
>
> As a result, digest verification will fail in verify_sha256_digest()
> after a kexec soft reboot into the new kernel. Therefore, the digest
> calculation/verification of the IMA segment needs to be skipped.
>
> To address this, skip the calculation and storage of the digest for the
> IMA segment in 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.
>
> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> Cc: Eric Biederman <ebiederm@xmission.com>
> Cc: Baoquan He <bhe@redhat.com>
> Cc: Vivek Goyal <vgoyal@redhat.com>
> Cc: Dave Young <dyoung@redhat.com>
> Signed-off-by: steven chen <chenste@linux.microsoft.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> include/linux/kexec.h | 3 +++
> kernel/kexec_file.c | 22 ++++++++++++++++++++++
> security/integrity/ima/ima_kexec.c | 3 +++
> 3 files changed, 28 insertions(+)
LGTM,
Acked-by: Baoquan He <bhe@redhat.com>
>
> diff --git a/include/linux/kexec.h b/include/linux/kexec.h
> index 7d6b12f8b8d0..107e726f2ef3 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..606132253c79 100644
> --- a/kernel/kexec_file.c
> +++ b/kernel/kexec_file.c
> @@ -38,6 +38,21 @@ 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 +779,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 45170e283272..34020b1513b0 100644
> --- a/security/integrity/ima/ima_kexec.c
> +++ b/security/integrity/ima/ima_kexec.c
> @@ -168,6 +168,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");
> @@ -178,6 +179,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
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file"
2025-03-18 1:04 ` [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file" steven chen
2025-03-18 15:10 ` Stefan Berger
@ 2025-03-19 13:42 ` Mimi Zohar
2025-03-21 16:16 ` steven chen
1 sibling, 1 reply; 34+ messages in thread
From: Mimi Zohar @ 2025-03-19 13:42 UTC (permalink / raw)
To: steven chen, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
Fix spelling: set_file
On Mon, 2025-03-17 at 18:04 -0700, steven chen wrote:
> The name of the local variable "file" of type seq_file defined in the
> ima_dump_measurement_list function is too generic. To better reflect the
> purpose of the variable, rename it to "ima_kexec_file". This change will
> help improve code readability and maintainability by making the variable's
> role more explicit.
The reason for making the variable name change is the variable scope.
-> Before making the function local seq_file "file" variable global, rename it
to ima_kexec_file.
>
> The variable ima_kexec_file is indeed the memory allocated for copying IMA
> measurement records. The ima_dump_measurement_list function calculates the
> actual memory occupied by the IMA logs and compares it with the allocated
> memory. If there is enough memory, it copies all IMA measurement records;
> otherwise, it does not copy any records, which would result in a failure
> of remote attestation.
This paragraph is not applicable to the patch change.
>
> Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
> Signed-off-by: steven chen <chenste@linux.microsoft.com>
> ---
> security/integrity/ima/ima_kexec.c | 39 ++++++++++++++++++------------
> 1 file changed, 24 insertions(+), 15 deletions(-)
>
> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> index 9d45f4d26f73..8567619889d1 100644
> --- a/security/integrity/ima/ima_kexec.c
> +++ b/security/integrity/ima/ima_kexec.c
> @@ -15,33 +15,41 @@
> #include "ima.h"
>
> #ifdef CONFIG_IMA_KEXEC
> +/*
> + * Copy the measurement list to the allocated memory
> + * compare the size of IMA measurement list with the size of the allocated memory
> + * 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
> + */
Please minimize patch changes. Before posting, please look at the patch(s) and
remove anything not applicable to it. In this case, the comment is not
applicable to the variable name change.
thanks,
Mimi
> static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> unsigned long segment_size)
> {
> + struct seq_file ima_kexec_file;
> 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) {
> + ima_kexec_file.buf = vmalloc(segment_size);
> + if (!ima_kexec_file.buf) {
> ret = -ENOMEM;
> goto out;
> }
>
> - file.file = NULL;
> - file.size = segment_size;
> - file.read_pos = 0;
> - file.count = sizeof(khdr); /* reserved space */
> + ima_kexec_file.file = NULL;
> + ima_kexec_file.size = segment_size;
> + ima_kexec_file.read_pos = 0;
> + ima_kexec_file.count = sizeof(khdr); /* reserved space */
>
> memset(&khdr, 0, sizeof(khdr));
> khdr.version = 1;
> /* This is an append-only list, no need to hold the RCU read lock */
> list_for_each_entry_rcu(qe, &ima_measurements, later, true) {
> - if (file.count < file.size) {
> + if (ima_kexec_file.count < ima_kexec_file.size) {
> khdr.count++;
> - ima_measurements_show(&file, qe);
> + ima_measurements_show(&ima_kexec_file, qe);
> } else {
> ret = -EINVAL;
> break;
> @@ -55,23 +63,24 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> * 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;
> + *buffer_size = ima_kexec_file.count;
> + *buffer = ima_kexec_file.buf;
> out:
> if (ret == -EINVAL)
> - vfree(file.buf);
> + vfree(ima_kexec_file.buf);
> return ret;
> }
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf()
2025-03-19 8:09 ` Baoquan He
@ 2025-03-19 16:27 ` Mimi Zohar
2025-03-20 1:51 ` Baoquan He
0 siblings, 1 reply; 34+ messages in thread
From: Mimi Zohar @ 2025-03-19 16:27 UTC (permalink / raw)
To: Baoquan He, steven chen
Cc: stefanb, roberto.sassu, roberto.sassu, eric.snowberg, ebiederm,
paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On Wed, 2025-03-19 at 16:09 +0800, Baoquan He wrote:
> On 03/17/25 at 06:04pm, steven chen wrote:
> > 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().
> > - Make necessary changes to the function ima_add_kexec_buffer() to call
> > the above two functions.
>
> We may not need above details about code change because it's not so
> difficult to get them from patch.
Agreed. The changes don't even reflect the current patch. Please remove the
entire section.
>
> >
> > Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> > Signed-off-by: steven chen <chenste@linux.microsoft.com>
> > ---
> > security/integrity/ima/ima_kexec.c | 67 +++++++++++++++++++++++++-----
> > 1 file changed, 56 insertions(+), 11 deletions(-)
> >
> > diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> > index 8567619889d1..45170e283272 100644
> > --- a/security/integrity/ima/ima_kexec.c
> > +++ b/security/integrity/ima/ima_kexec.c
> > @@ -15,6 +15,48 @@
> > #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;
The call to ima_reset_kexec_file() in ima_add_kexec_buffer() resets
ima_kexec_file.buf() hiding the fact that the above test always fails and falls
through. As a result, 'buf' is always being re-allocated.
> > +
> > + 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;
> > +}
> > +
> > /*
> > * Copy the measurement list to the allocated memory
> > * compare the size of IMA measurement list with the size of the allocated memory
> > @@ -26,23 +68,16 @@
> > static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> > unsigned long segment_size)
> > {
> > - struct seq_file ima_kexec_file;
> > struct ima_queue_entry *qe;
> > struct ima_kexec_hdr khdr;
> > int ret = 0;
> >
> > /* segment size can't change between kexec load and execute */
> > - ima_kexec_file.buf = vmalloc(segment_size);
> > if (!ima_kexec_file.buf) {
> > - ret = -ENOMEM;
> > - goto out;
> > + pr_err("Kexec file buf not allocated\n");
> > + return -EINVAL;
> > }
> >
> > - ima_kexec_file.file = NULL;
> > - ima_kexec_file.size = segment_size;
> > - ima_kexec_file.read_pos = 0;
> > - ima_kexec_file.count = sizeof(khdr); /* reserved space */
> > -
> > memset(&khdr, 0, sizeof(khdr));
> > khdr.version = 1;
> > /* This is an append-only list, no need to hold the RCU read lock */
> > @@ -79,8 +114,6 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> > *buffer_size = ima_kexec_file.count;
> > *buffer = ima_kexec_file.buf;
> > out:
> > - if (ret == -EINVAL)
> > - vfree(ima_kexec_file.buf);
> > return ret;
> > }
> >
> > @@ -119,6 +152,12 @@ void ima_add_kexec_buffer(struct kimage *image)
> > return;
> > }
> >
> > + ret = ima_alloc_kexec_file_buf(kexec_segment_size);
> > + if (ret < 0) {
> > + pr_err("Not enough memory for the kexec measurement buffer.\n");
> > + return;
> > + }
> > +
> > ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
> > kexec_segment_size);
> > if (!kexec_buffer) {
> > @@ -140,6 +179,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);
>
> I can't see why we need call ima_reset_kexec_file() here. If we need
> reuse the buffer, we will reset the needed fields at the end of
> ima_alloc_kexec_file_buf(). Not sure if I miss anything.
Without ima_reset_kexec_file(), calling 'kexec load' consecutively without
"kexec -s -e" in between fails.
# kexec -s -l /boot/vmlinuz-`uname -r` --initrd=/boot/initramfs-`uname -r`.img --reuse-cmdline
# kexec -s -l /boot/vmlinuz-`uname -r` --initrd=/boot/initramfs-`uname -r`.img --reuse-cmdline
Killed
As mentioned above, the call to ima_reset_kexec_file() resets
ima_kexec_file.buf, so the segment size test always fails and the memory is
being allocated.
Mimi
>
> 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 */
>
> return 0;
> }
>
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-18 1:04 ` [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute steven chen
@ 2025-03-19 20:53 ` Mimi Zohar
2025-03-21 16:20 ` steven chen
2025-03-20 2:06 ` Baoquan He
1 sibling, 1 reply; 34+ messages in thread
From: Mimi Zohar @ 2025-03-19 20:53 UTC (permalink / raw)
To: steven chen, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
On Mon, 2025-03-17 at 18:04 -0700, steven chen wrote:
> ima_dump_measurement_list() is called during kexec 'load', which may
> result in loss of IMA measurements during kexec soft reboot. Due to
> missed measurements that only occurred after kexec 'load', this function
> needs to be called during kexec 'execute'.
-> , defer calling ima_dump_measurement_list() to 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
> 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.
Let's summarize the above changes, as below, and then remove the list.
Define and call the new kimage_file_post_load() to call ima_kexec_post_load(),
which registers the reboot notifier (ima_update_kexec_buffer).
Finally, move ima_dump_measurement_list() from ima_add_kexec_buffer()
to ima_update_kexec_buffer() to defer copying the measurement list.
> - 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.
Instead of adding and then removing the ima_reset_kexec_file() call from
ima_add_kexec_buffer(), defer adding the test in ima_alloc_kexec_file_buf() to
see if the segment size has changed. That should be a subsequent patch, after
this one.
ima_reset_kexec_file() is then ever called from only one place. Combine
ima_reset_kexec_file() with ima_free_kexec_file_buf().
thanks,
Mimi
>
> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> Cc: Eric Biederman <ebiederm@xmission.com>
> Cc: Baoquan He <bhe@redhat.com>
> Cc: Vivek Goyal <vgoyal@redhat.com>
> Cc: Dave Young <dyoung@redhat.com>
> Signed-off-by: steven chen <chenste@linux.microsoft.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> ---
> 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
>
> +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, 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 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;
>
> 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 **buffer,
> unsigned long segment_size)
> @@ -95,9 +96,6 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> }
> }
>
> - 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 *buffer_size, void **buffer,
>
> *buffer_size = ima_kexec_file.count;
> *buffer = ima_kexec_file.buf;
> -out:
> +
> return ret;
> }
>
> @@ -135,9 +133,8 @@ void ima_add_kexec_buffer(struct kimage *image)
> unsigned long binary_runtime_size;
>
> /* use more understandable variable names than defined in kbuf */
> + size_t kexec_buffer_size = 0;
> void *kexec_buffer = NULL;
> - size_t kexec_buffer_size;
> - size_t kexec_segment_size;
> int ret;
>
> /*
> @@ -162,13 +159,6 @@ void ima_add_kexec_buffer(struct kimage *image)
> return;
> }
>
> - 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 = kexec_buffer;
> kbuf.bufsz = kexec_buffer_size;
> kbuf.memsz = kexec_segment_size;
> @@ -186,12 +176,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);
> }
> @@ -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 = 0;
> + int ret = NOTIFY_OK;
> + void *buf = 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 = 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;
> }
>
> static struct notifier_block update_buffer_nb = {
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf()
2025-03-19 16:27 ` Mimi Zohar
@ 2025-03-20 1:51 ` Baoquan He
2025-03-20 13:06 ` Mimi Zohar
0 siblings, 1 reply; 34+ messages in thread
From: Baoquan He @ 2025-03-20 1:51 UTC (permalink / raw)
To: Mimi Zohar
Cc: steven chen, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 03/19/25 at 12:27pm, Mimi Zohar wrote:
> On Wed, 2025-03-19 at 16:09 +0800, Baoquan He wrote:
> > On 03/17/25 at 06:04pm, steven chen wrote:
> > > 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().
> > > - Make necessary changes to the function ima_add_kexec_buffer() to call
> > > the above two functions.
> >
> > We may not need above details about code change because it's not so
> > difficult to get them from patch.
>
> Agreed. The changes don't even reflect the current patch. Please remove the
> entire section.
>
> >
> > >
> > > Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> > > Signed-off-by: steven chen <chenste@linux.microsoft.com>
> > > ---
> > > security/integrity/ima/ima_kexec.c | 67 +++++++++++++++++++++++++-----
> > > 1 file changed, 56 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> > > index 8567619889d1..45170e283272 100644
> > > --- a/security/integrity/ima/ima_kexec.c
> > > +++ b/security/integrity/ima/ima_kexec.c
> > > @@ -15,6 +15,48 @@
> > > #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;
>
> The call to ima_reset_kexec_file() in ima_add_kexec_buffer() resets
> ima_kexec_file.buf() hiding the fact that the above test always fails and falls
> through. As a result, 'buf' is always being re-allocated.
>
> > > +
> > > + 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;
> > > +}
> > > +
> > > /*
> > > * Copy the measurement list to the allocated memory
> > > * compare the size of IMA measurement list with the size of the allocated memory
> > > @@ -26,23 +68,16 @@
> > > static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> > > unsigned long segment_size)
> > > {
> > > - struct seq_file ima_kexec_file;
> > > struct ima_queue_entry *qe;
> > > struct ima_kexec_hdr khdr;
> > > int ret = 0;
> > >
> > > /* segment size can't change between kexec load and execute */
> > > - ima_kexec_file.buf = vmalloc(segment_size);
> > > if (!ima_kexec_file.buf) {
> > > - ret = -ENOMEM;
> > > - goto out;
> > > + pr_err("Kexec file buf not allocated\n");
> > > + return -EINVAL;
> > > }
> > >
> > > - ima_kexec_file.file = NULL;
> > > - ima_kexec_file.size = segment_size;
> > > - ima_kexec_file.read_pos = 0;
> > > - ima_kexec_file.count = sizeof(khdr); /* reserved space */
> > > -
> > > memset(&khdr, 0, sizeof(khdr));
> > > khdr.version = 1;
> > > /* This is an append-only list, no need to hold the RCU read lock */
> > > @@ -79,8 +114,6 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
> > > *buffer_size = ima_kexec_file.count;
> > > *buffer = ima_kexec_file.buf;
> > > out:
> > > - if (ret == -EINVAL)
> > > - vfree(ima_kexec_file.buf);
> > > return ret;
> > > }
> > >
> > > @@ -119,6 +152,12 @@ void ima_add_kexec_buffer(struct kimage *image)
> > > return;
> > > }
> > >
> > > + ret = ima_alloc_kexec_file_buf(kexec_segment_size);
> > > + if (ret < 0) {
> > > + pr_err("Not enough memory for the kexec measurement buffer.\n");
> > > + return;
> > > + }
> > > +
> > > ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
> > > kexec_segment_size);
> > > if (!kexec_buffer) {
> > > @@ -140,6 +179,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);
> >
> > I can't see why we need call ima_reset_kexec_file() here. If we need
> > reuse the buffer, we will reset the needed fields at the end of
> > ima_alloc_kexec_file_buf(). Not sure if I miss anything.
>
> Without ima_reset_kexec_file(), calling 'kexec load' consecutively without
> "kexec -s -e" in between fails.
>
> # kexec -s -l /boot/vmlinuz-`uname -r` --initrd=/boot/initramfs-`uname -r`.img --reuse-cmdline
> # kexec -s -l /boot/vmlinuz-`uname -r` --initrd=/boot/initramfs-`uname -r`.img --reuse-cmdline
> Killed
>
> As mentioned above, the call to ima_reset_kexec_file() resets
> ima_kexec_file.buf, so the segment size test always fails and the memory is
> being allocated.
Indeed, I didn't realize this.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-18 1:04 ` [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute steven chen
2025-03-19 20:53 ` Mimi Zohar
@ 2025-03-20 2:06 ` Baoquan He
2025-03-21 16:23 ` steven chen
1 sibling, 1 reply; 34+ messages in thread
From: Baoquan He @ 2025-03-20 2:06 UTC (permalink / raw)
To: steven chen
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 03/17/25 at 06:04pm, steven chen wrote:
...snip...
> ---
> 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
>
> +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, initrd_fd,
>
> kimage_terminate(image);
>
> + if (!(flags & KEXEC_FILE_ON_CRASH))
> + kimage_file_post_load(image);
machine_kexec_post_load() is called by both kexec_load and kexec_file_load,
we should use it to do things post load, but not introducing another
kimage_file_post_load().
> +
> ret = machine_kexec_post_load(image);
> if (ret)
> goto out;
...snip...
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 7/8] ima: make the kexec extra memory configurable
2025-03-18 1:04 ` [PATCH v10 7/8] ima: make the kexec extra memory configurable steven chen
@ 2025-03-20 2:52 ` Baoquan He
2025-03-21 16:46 ` steven chen
0 siblings, 1 reply; 34+ messages in thread
From: Baoquan He @ 2025-03-20 2:52 UTC (permalink / raw)
To: steven chen
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 03/17/25 at 06:04pm, steven chen wrote:
> 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.
>
> Suggested-by: Stefan Berger <stefanb@linux.ibm.com>
> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> Signed-off-by: steven chen <chenste@linux.microsoft.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
> ---
> security/integrity/ima/Kconfig | 10 ++++++++++
> security/integrity/ima/ima_kexec.c | 16 +++++++++++-----
> 2 files changed, 21 insertions(+), 5 deletions(-)
>
> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
> index 475c32615006..d73c96c3c1c9 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
Is there range for this memory, e.g [0, max] and max will be a value
according to our current perception?
> + 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 of 0, an extra half 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 c390c745f882..0f214e41dd33 100644
> --- a/security/integrity/ima/ima_kexec.c
> +++ b/security/integrity/ima/ima_kexec.c
> @@ -131,6 +131,7 @@ 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_memory;
>
> /* use more understandable variable names than defined in kbuf */
> size_t kexec_buffer_size = 0;
> @@ -138,15 +139,20 @@ 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 during kexec.
> */
> - binary_runtime_size = ima_get_binary_runtime_size();
> + if (CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB <= 0)
> + extra_memory = PAGE_SIZE / 2;
> + else
> + extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
> +
> + binary_runtime_size = ima_get_binary_runtime_size() + extra_memory;
> +
> 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");
> --
> 2.25.1
>
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 8/8] ima: measure kexec load and exec events as critical data
2025-03-18 1:04 ` [PATCH v10 8/8] ima: measure kexec load and exec events as critical data steven chen
@ 2025-03-20 2:59 ` Mimi Zohar
2025-03-21 16:49 ` steven chen
0 siblings, 1 reply; 34+ messages in thread
From: Mimi Zohar @ 2025-03-20 2:59 UTC (permalink / raw)
To: steven chen, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
On Mon, 2025-03-17 at 18:04 -0700, steven chen wrote:
> 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.
>
> These critical data events are displayed as hex encoded ascii in the
> ascii_runtime_measurement_list. Verifying the critical data hash requires
> calculating the hash of the decoded ascii string.
>
> For example, to verify the 'kexec_load' data hash:
>
> sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements
> > grep kexec_load | cut -d' ' -f 6 | xxd -r -p | sha256sum
>
>
> To verify the 'kexec_execute' data hash:
>
> sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements
> > grep kexec_execute | cut -d' ' -f 6 | xxd -r -p | sha256sum
>
> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
> Signed-off-by: steven chen <chenste@linux.microsoft.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
> ---
> security/integrity/ima/ima.h | 6 ++++++
> security/integrity/ima/ima_kexec.c | 21 +++++++++++++++++++++
> security/integrity/ima/ima_queue.c | 5 +++++
> 3 files changed, 32 insertions(+)
>
> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
> index 24d09ea91b87..34815baf5e21 100644
> --- a/security/integrity/ima/ima.h
> +++ b/security/integrity/ima/ima.h
> @@ -240,6 +240,12 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
> unsigned long flags, bool create);
> #endif
>
> +#ifdef CONFIG_IMA_KEXEC
> +void ima_measure_kexec_event(const char *event_name);
> +#else
> +static inline void ima_measure_kexec_event(const char *event_name) {}
> +#endif
> +
> /*
> * The default binary_runtime_measurements list format is defined as the
> * platform native format. The canonical format is defined as little-endian.
> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> index 0f214e41dd33..43223eb99046 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 bool ima_kexec_update_registered;
> static struct seq_file ima_kexec_file;
> 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);
> }
>
> +void ima_measure_kexec_event(const char *event_name)
> +{
> + char ima_kexec_event[IMA_KEXEC_EVENT_LEN];
> + size_t buf_size = 0;
> + long len;
> + int n;
> +
> + buf_size = ima_get_binary_runtime_size();
> + len = atomic_long_read(&ima_htable.len);
> +
> + n = 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, n, false, NULL, 0);
> +}
> +
> static int ima_alloc_kexec_file_buf(size_t segment_size)
> {
> /*
> @@ -58,6 +78,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;
> }
> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
> index 83d53824aa98..590637e81ad1 100644
> --- a/security/integrity/ima/ima_queue.c
> +++ b/security/integrity/ima/ima_queue.c
> @@ -241,6 +241,11 @@ static int ima_reboot_notifier(struct notifier_block *nb,
> unsigned long action,
> void *data)
> {
> +#ifdef CONFIG_IMA_KEXEC
> + if (action == SYS_RESTART && data && !strcmp(data, "kexec reboot"))
> + ima_measure_kexec_event("kexec_execute");
> +#endif
After a kexec execute, the measurement list does not verify properly and the
"kexec_execute" critical data does not appear in the measurement list. This
makes me think the critical data IS being extended into the TPM, but the
measurement list is being copied before the "kexec_execute" critical data is
called.
This actually makes sense since the reboot notifier ima_update_kexec_buffer()
priority is higher than ima_reboot_notifier().
INT_MIN: runs the callback late
INT_MAX: runs the callback early
Either reverse the callback priorities or revert moving the "kexec_execute"
critical data to ima_reboot_notifier().
thanks,
Mimi
> +
> ima_measurements_suspend();
>
> return NOTIFY_DONE;
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf()
2025-03-20 1:51 ` Baoquan He
@ 2025-03-20 13:06 ` Mimi Zohar
2025-03-21 16:18 ` steven chen
0 siblings, 1 reply; 34+ messages in thread
From: Mimi Zohar @ 2025-03-20 13:06 UTC (permalink / raw)
To: Baoquan He
Cc: steven chen, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On Thu, 2025-03-20 at 09:51 +0800, Baoquan He wrote:
> > > > diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
> > > > index 8567619889d1..45170e283272 100644
> > > > --- a/security/integrity/ima/ima_kexec.c
> > > > +++ b/security/integrity/ima/ima_kexec.c
> > > > @@ -15,6 +15,48 @@
> > > > #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;
> >
> > The call to ima_reset_kexec_file() in ima_add_kexec_buffer() resets
> > ima_kexec_file.buf() hiding the fact that the above test always fails and falls
> > through. As a result, 'buf' is always being re-allocated.
Hi Steven,
[Reiterating the comment in the "ima: kexec: move IMA log copy from kexec load
to execute" thread, here, for completeness.]
Instead of adding and then removing the ima_reset_kexec_file() call from
ima_add_kexec_buffer(), defer adding the segment size test to when it is
actually possible for the segment size to change. Please make the segment size
test as a separate patch.
ima_reset_kexec_file() will then only be called by ima_free_kexec_file_buf().
Inline the ima_reset_kexec_file() code in ima_free_kexec_file_buf().
thanks,
Mimi
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file"
2025-03-19 2:43 ` Baoquan He
@ 2025-03-21 16:15 ` steven chen
0 siblings, 0 replies; 34+ messages in thread
From: steven chen @ 2025-03-21 16:15 UTC (permalink / raw)
To: Baoquan He, Stefan Berger
Cc: zohar, roberto.sassu, roberto.sassu, eric.snowberg, ebiederm,
paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 3/18/2025 7:43 PM, Baoquan He wrote:
> On 03/18/25 at 11:10am, Stefan Berger wrote:
>>
>> On 3/17/25 9:04 PM, steven chen wrote:
>>> The name of the local variable "file" of type seq_file defined in the
>>> ima_dump_measurement_list function is too generic. To better reflect the
>>> purpose of the variable, rename it to "ima_kexec_file". This change will
>>> help improve code readability and maintainability by making the variable's
>>> role more explicit.
>>>
>>> The variable ima_kexec_file is indeed the memory allocated for copying IMA
>>> measurement records. The ima_dump_measurement_list function calculates the
>>> actual memory occupied by the IMA logs and compares it with the allocated
>>> memory. If there is enough memory, it copies all IMA measurement records;
>>> otherwise, it does not copy any records, which would result in a failure
>>> of remote attestation.
>>>
>>> Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
>>> Signed-off-by: steven chen <chenste@linux.microsoft.com>
>>
>>> ---
>>> security/integrity/ima/ima_kexec.c | 39 ++++++++++++++++++------------
>>> 1 file changed, 24 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
>>> index 9d45f4d26f73..8567619889d1 100644
>>> --- a/security/integrity/ima/ima_kexec.c
>>> +++ b/security/integrity/ima/ima_kexec.c
>>> @@ -15,33 +15,41 @@
>>> #include "ima.h"
>>> #ifdef CONFIG_IMA_KEXEC
>>> +/*
>>> + * Copy the measurement list to the allocated memory
>>> + * compare the size of IMA measurement list with the size of the allocated memory
>> Compare the size of the IMA ... memory.
>>
>>
>>> + * 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
>> 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, return
>> an error otherwise.
> Ack the suggested change.
Thanks for the comments.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file"
2025-03-19 13:42 ` Mimi Zohar
@ 2025-03-21 16:16 ` steven chen
0 siblings, 0 replies; 34+ messages in thread
From: steven chen @ 2025-03-21 16:16 UTC (permalink / raw)
To: Mimi Zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
On 3/19/2025 6:42 AM, Mimi Zohar wrote:
> Fix spelling: set_file
>
>
> On Mon, 2025-03-17 at 18:04 -0700, steven chen wrote:
>> The name of the local variable "file" of type seq_file defined in the
>> ima_dump_measurement_list function is too generic. To better reflect the
>> purpose of the variable, rename it to "ima_kexec_file". This change will
>> help improve code readability and maintainability by making the variable's
>> role more explicit.
> The reason for making the variable name change is the variable scope.
>
> -> Before making the function local seq_file "file" variable global, rename it
> to ima_kexec_file.
>
>> The variable ima_kexec_file is indeed the memory allocated for copying IMA
>> measurement records. The ima_dump_measurement_list function calculates the
>> actual memory occupied by the IMA logs and compares it with the allocated
>> memory. If there is enough memory, it copies all IMA measurement records;
>> otherwise, it does not copy any records, which would result in a failure
>> of remote attestation.
> This paragraph is not applicable to the patch change.
>
>> Suggested-by: Mimi Zohar <zohar@linux.ibm.com>
>> Signed-off-by: steven chen <chenste@linux.microsoft.com>
>> ---
>> security/integrity/ima/ima_kexec.c | 39 ++++++++++++++++++------------
>> 1 file changed, 24 insertions(+), 15 deletions(-)
>>
>> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
>> index 9d45f4d26f73..8567619889d1 100644
>> --- a/security/integrity/ima/ima_kexec.c
>> +++ b/security/integrity/ima/ima_kexec.c
>> @@ -15,33 +15,41 @@
>> #include "ima.h"
>>
>> #ifdef CONFIG_IMA_KEXEC
>> +/*
>> + * Copy the measurement list to the allocated memory
>> + * compare the size of IMA measurement list with the size of the allocated memory
>> + * 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
>> + */
> Please minimize patch changes. Before posting, please look at the patch(s) and
> remove anything not applicable to it. In this case, the comment is not
> applicable to the variable name change.
>
> thanks,
>
> Mimi
>
>> static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
>> unsigned long segment_size)
>> {
>> + struct seq_file ima_kexec_file;
>> 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) {
>> + ima_kexec_file.buf = vmalloc(segment_size);
>> + if (!ima_kexec_file.buf) {
>> ret = -ENOMEM;
>> goto out;
>> }
>>
>> - file.file = NULL;
>> - file.size = segment_size;
>> - file.read_pos = 0;
>> - file.count = sizeof(khdr); /* reserved space */
>> + ima_kexec_file.file = NULL;
>> + ima_kexec_file.size = segment_size;
>> + ima_kexec_file.read_pos = 0;
>> + ima_kexec_file.count = sizeof(khdr); /* reserved space */
>>
>> memset(&khdr, 0, sizeof(khdr));
>> khdr.version = 1;
>> /* This is an append-only list, no need to hold the RCU read lock */
>> list_for_each_entry_rcu(qe, &ima_measurements, later, true) {
>> - if (file.count < file.size) {
>> + if (ima_kexec_file.count < ima_kexec_file.size) {
>> khdr.count++;
>> - ima_measurements_show(&file, qe);
>> + ima_measurements_show(&ima_kexec_file, qe);
>> } else {
>> ret = -EINVAL;
>> break;
>> @@ -55,23 +63,24 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
>> * 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;
>> + *buffer_size = ima_kexec_file.count;
>> + *buffer = ima_kexec_file.buf;
>> out:
>> if (ret == -EINVAL)
>> - vfree(file.buf);
>> + vfree(ima_kexec_file.buf);
>> return ret;
>> }
>>
Hi Mimi,
I will update in next version.
Thanks,
Steven
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf()
2025-03-20 13:06 ` Mimi Zohar
@ 2025-03-21 16:18 ` steven chen
0 siblings, 0 replies; 34+ messages in thread
From: steven chen @ 2025-03-21 16:18 UTC (permalink / raw)
To: Mimi Zohar, Baoquan He
Cc: stefanb, roberto.sassu, roberto.sassu, eric.snowberg, ebiederm,
paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 3/20/2025 6:06 AM, Mimi Zohar wrote:
> On Thu, 2025-03-20 at 09:51 +0800, Baoquan He wrote:
>>>>> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
>>>>> index 8567619889d1..45170e283272 100644
>>>>> --- a/security/integrity/ima/ima_kexec.c
>>>>> +++ b/security/integrity/ima/ima_kexec.c
>>>>> @@ -15,6 +15,48 @@
>>>>> #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;
>>> The call to ima_reset_kexec_file() in ima_add_kexec_buffer() resets
>>> ima_kexec_file.buf() hiding the fact that the above test always fails and falls
>>> through. As a result, 'buf' is always being re-allocated.
> Hi Steven,
>
> [Reiterating the comment in the "ima: kexec: move IMA log copy from kexec load
> to execute" thread, here, for completeness.]
>
> Instead of adding and then removing the ima_reset_kexec_file() call from
> ima_add_kexec_buffer(), defer adding the segment size test to when it is
> actually possible for the segment size to change. Please make the segment size
> test as a separate patch.
>
> ima_reset_kexec_file() will then only be called by ima_free_kexec_file_buf().
> Inline the ima_reset_kexec_file() code in ima_free_kexec_file_buf().
>
> thanks,
>
> Mimi
Hi Mimi,
I will update in next version.
Thanks,
Steven
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-19 20:53 ` Mimi Zohar
@ 2025-03-21 16:20 ` steven chen
0 siblings, 0 replies; 34+ messages in thread
From: steven chen @ 2025-03-21 16:20 UTC (permalink / raw)
To: Mimi Zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
On 3/19/2025 1:53 PM, Mimi Zohar wrote:
> On Mon, 2025-03-17 at 18:04 -0700, steven chen wrote:
>> ima_dump_measurement_list() is called during kexec 'load', which may
>> result in loss of IMA measurements during kexec soft reboot. Due to
>> missed measurements that only occurred after kexec 'load', this function
>> needs to be called during kexec 'execute'.
> -> , defer calling ima_dump_measurement_list() to 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
>> 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.
> Let's summarize the above changes, as below, and then remove the list.
>
> Define and call the new kimage_file_post_load() to call ima_kexec_post_load(),
> which registers the reboot notifier (ima_update_kexec_buffer).
>
> Finally, move ima_dump_measurement_list() from ima_add_kexec_buffer()
> to ima_update_kexec_buffer() to defer copying the measurement list.
>
>> - 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.
> Instead of adding and then removing the ima_reset_kexec_file() call from
> ima_add_kexec_buffer(), defer adding the test in ima_alloc_kexec_file_buf() to
> see if the segment size has changed. That should be a subsequent patch, after
> this one.
>
> ima_reset_kexec_file() is then ever called from only one place. Combine
> ima_reset_kexec_file() with ima_free_kexec_file_buf().
>
> thanks,
>
> Mimi
Hi Mimi,
I will update the patchset in next version.
Thanks,
Steven
>
>> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
>> Cc: Eric Biederman <ebiederm@xmission.com>
>> Cc: Baoquan He <bhe@redhat.com>
>> Cc: Vivek Goyal <vgoyal@redhat.com>
>> Cc: Dave Young <dyoung@redhat.com>
>> Signed-off-by: steven chen <chenste@linux.microsoft.com>
>> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
>> ---
>> 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
>>
>> +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, 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 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;
>>
>> 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 **buffer,
>> unsigned long segment_size)
>> @@ -95,9 +96,6 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
>> }
>> }
>>
>> - 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 *buffer_size, void **buffer,
>>
>> *buffer_size = ima_kexec_file.count;
>> *buffer = ima_kexec_file.buf;
>> -out:
>> +
>> return ret;
>> }
>>
>> @@ -135,9 +133,8 @@ void ima_add_kexec_buffer(struct kimage *image)
>> unsigned long binary_runtime_size;
>>
>> /* use more understandable variable names than defined in kbuf */
>> + size_t kexec_buffer_size = 0;
>> void *kexec_buffer = NULL;
>> - size_t kexec_buffer_size;
>> - size_t kexec_segment_size;
>> int ret;
>>
>> /*
>> @@ -162,13 +159,6 @@ void ima_add_kexec_buffer(struct kimage *image)
>> return;
>> }
>>
>> - 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 = kexec_buffer;
>> kbuf.bufsz = kexec_buffer_size;
>> kbuf.memsz = kexec_segment_size;
>> @@ -186,12 +176,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);
>> }
>> @@ -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 = 0;
>> + int ret = NOTIFY_OK;
>> + void *buf = 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 = 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;
>> }
>>
>> static struct notifier_block update_buffer_nb = {
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-20 2:06 ` Baoquan He
@ 2025-03-21 16:23 ` steven chen
2025-03-24 11:00 ` Baoquan He
0 siblings, 1 reply; 34+ messages in thread
From: steven chen @ 2025-03-21 16:23 UTC (permalink / raw)
To: Baoquan He
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 3/19/2025 7:06 PM, Baoquan He wrote:
> On 03/17/25 at 06:04pm, steven chen wrote:
> ...snip...
>> ---
>> 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
>>
>> +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, initrd_fd,
>>
>> kimage_terminate(image);
>>
>> + if (!(flags & KEXEC_FILE_ON_CRASH))
>> + kimage_file_post_load(image);
> machine_kexec_post_load() is called by both kexec_load and kexec_file_load,
> we should use it to do things post load, but not introducing another
> kimage_file_post_load().
Hi Baoquan,
Could you give me more detail about this?
Thanks,
Steven
>
>> +
>> ret = machine_kexec_post_load(image);
>> if (ret)
>> goto out;
> ...snip...
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 7/8] ima: make the kexec extra memory configurable
2025-03-20 2:52 ` Baoquan He
@ 2025-03-21 16:46 ` steven chen
0 siblings, 0 replies; 34+ messages in thread
From: steven chen @ 2025-03-21 16:46 UTC (permalink / raw)
To: Baoquan He
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 3/19/2025 7:52 PM, Baoquan He wrote:
> On 03/17/25 at 06:04pm, steven chen wrote:
>> 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.
>>
>> Suggested-by: Stefan Berger <stefanb@linux.ibm.com>
>> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
>> Signed-off-by: steven chen <chenste@linux.microsoft.com>
>> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
>> Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
>> ---
>> security/integrity/ima/Kconfig | 10 ++++++++++
>> security/integrity/ima/ima_kexec.c | 16 +++++++++++-----
>> 2 files changed, 21 insertions(+), 5 deletions(-)
>>
>> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
>> index 475c32615006..d73c96c3c1c9 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
> Is there range for this memory, e.g [0, max] and max will be a value
> according to our current perception?
Hi Baoquan,
In the code below there is value check for this
if ((kexec_segment_size == ULONG_MAX) ||
((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) {
Hi Mimi,
Could you provide any guidance if we need to set the range?
Thanks,
Steven
>> + 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 of 0, an extra half 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 c390c745f882..0f214e41dd33 100644
>> --- a/security/integrity/ima/ima_kexec.c
>> +++ b/security/integrity/ima/ima_kexec.c
>> @@ -131,6 +131,7 @@ 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_memory;
>>
>> /* use more understandable variable names than defined in kbuf */
>> size_t kexec_buffer_size = 0;
>> @@ -138,15 +139,20 @@ 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 during kexec.
>> */
>> - binary_runtime_size = ima_get_binary_runtime_size();
>> + if (CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB <= 0)
>> + extra_memory = PAGE_SIZE / 2;
>> + else
>> + extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
>> +
>> + binary_runtime_size = ima_get_binary_runtime_size() + extra_memory;
>> +
>> 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");
>> --
>> 2.25.1
>>
>>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 8/8] ima: measure kexec load and exec events as critical data
2025-03-20 2:59 ` Mimi Zohar
@ 2025-03-21 16:49 ` steven chen
0 siblings, 0 replies; 34+ messages in thread
From: steven chen @ 2025-03-21 16:49 UTC (permalink / raw)
To: Mimi Zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel
Cc: madvenka, nramas, James.Bottomley, bhe, vgoyal, dyoung
On 3/19/2025 7:59 PM, Mimi Zohar wrote:
> On Mon, 2025-03-17 at 18:04 -0700, steven chen wrote:
>> 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.
>>
>> These critical data events are displayed as hex encoded ascii in the
>> ascii_runtime_measurement_list. Verifying the critical data hash requires
>> calculating the hash of the decoded ascii string.
>>
>> For example, to verify the 'kexec_load' data hash:
>>
>> sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements
>>> grep kexec_load | cut -d' ' -f 6 | xxd -r -p | sha256sum
>>
>> To verify the 'kexec_execute' data hash:
>>
>> sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements
>>> grep kexec_execute | cut -d' ' -f 6 | xxd -r -p | sha256sum
>> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
>> Signed-off-by: steven chen <chenste@linux.microsoft.com>
>> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
>> ---
>> security/integrity/ima/ima.h | 6 ++++++
>> security/integrity/ima/ima_kexec.c | 21 +++++++++++++++++++++
>> security/integrity/ima/ima_queue.c | 5 +++++
>> 3 files changed, 32 insertions(+)
>>
>> diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
>> index 24d09ea91b87..34815baf5e21 100644
>> --- a/security/integrity/ima/ima.h
>> +++ b/security/integrity/ima/ima.h
>> @@ -240,6 +240,12 @@ void ima_post_key_create_or_update(struct key *keyring, struct key *key,
>> unsigned long flags, bool create);
>> #endif
>>
>> +#ifdef CONFIG_IMA_KEXEC
>> +void ima_measure_kexec_event(const char *event_name);
>> +#else
>> +static inline void ima_measure_kexec_event(const char *event_name) {}
>> +#endif
>> +
>> /*
>> * The default binary_runtime_measurements list format is defined as the
>> * platform native format. The canonical format is defined as little-endian.
>> diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
>> index 0f214e41dd33..43223eb99046 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 bool ima_kexec_update_registered;
>> static struct seq_file ima_kexec_file;
>> 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);
>> }
>>
>> +void ima_measure_kexec_event(const char *event_name)
>> +{
>> + char ima_kexec_event[IMA_KEXEC_EVENT_LEN];
>> + size_t buf_size = 0;
>> + long len;
>> + int n;
>> +
>> + buf_size = ima_get_binary_runtime_size();
>> + len = atomic_long_read(&ima_htable.len);
>> +
>> + n = 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, n, false, NULL, 0);
>> +}
>> +
>> static int ima_alloc_kexec_file_buf(size_t segment_size)
>> {
>> /*
>> @@ -58,6 +78,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;
>> }
>> diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
>> index 83d53824aa98..590637e81ad1 100644
>> --- a/security/integrity/ima/ima_queue.c
>> +++ b/security/integrity/ima/ima_queue.c
>> @@ -241,6 +241,11 @@ static int ima_reboot_notifier(struct notifier_block *nb,
>> unsigned long action,
>> void *data)
>> {
>> +#ifdef CONFIG_IMA_KEXEC
>> + if (action == SYS_RESTART && data && !strcmp(data, "kexec reboot"))
>> + ima_measure_kexec_event("kexec_execute");
>> +#endif
> After a kexec execute, the measurement list does not verify properly and the
> "kexec_execute" critical data does not appear in the measurement list. This
> makes me think the critical data IS being extended into the TPM, but the
> measurement list is being copied before the "kexec_execute" critical data is
> called.
>
> This actually makes sense since the reboot notifier ima_update_kexec_buffer()
> priority is higher than ima_reboot_notifier().
>
> INT_MIN: runs the callback late
> INT_MAX: runs the callback early
>
> Either reverse the callback priorities or revert moving the "kexec_execute"
> critical data to ima_reboot_notifier().
>
> thanks,
>
> Mimi
Hi Mimi,
I will reverse the callback priority.
Thanks,
Steven
>> +
>> ima_measurements_suspend();
>>
>> return NOTIFY_DONE;
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-21 16:23 ` steven chen
@ 2025-03-24 11:00 ` Baoquan He
2025-03-25 22:27 ` steven chen
0 siblings, 1 reply; 34+ messages in thread
From: Baoquan He @ 2025-03-24 11:00 UTC (permalink / raw)
To: steven chen
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 03/21/25 at 09:23am, steven chen wrote:
> On 3/19/2025 7:06 PM, Baoquan He wrote:
> > On 03/17/25 at 06:04pm, steven chen wrote:
> > ...snip...
> > > ---
> > > 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
> > > +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, initrd_fd,
> > > kimage_terminate(image);
> > > + if (!(flags & KEXEC_FILE_ON_CRASH))
> > > + kimage_file_post_load(image);
> > machine_kexec_post_load() is called by both kexec_load and kexec_file_load,
> > we should use it to do things post load, but not introducing another
> > kimage_file_post_load().
>
> Hi Baoquan,
>
> Could you give me more detail about this?
I mean machine_kexec_post_load() is the place where post load operations
are done, including kexec_load and kexec_file_load. There's no need to
specifically introduce a kimage_file_post_load() to do post load
operaton for kexec_file_load.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-24 11:00 ` Baoquan He
@ 2025-03-25 22:27 ` steven chen
2025-03-26 2:27 ` Baoquan He
0 siblings, 1 reply; 34+ messages in thread
From: steven chen @ 2025-03-25 22:27 UTC (permalink / raw)
To: Baoquan He
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 3/24/2025 4:00 AM, Baoquan He wrote:
> On 03/21/25 at 09:23am, steven chen wrote:
>> On 3/19/2025 7:06 PM, Baoquan He wrote:
>>> On 03/17/25 at 06:04pm, steven chen wrote:
>>> ...snip...
>>>> ---
>>>> 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
>>>> +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, initrd_fd,
>>>> kimage_terminate(image);
>>>> + if (!(flags & KEXEC_FILE_ON_CRASH))
>>>> + kimage_file_post_load(image);
>>> machine_kexec_post_load() is called by both kexec_load and kexec_file_load,
>>> we should use it to do things post load, but not introducing another
>>> kimage_file_post_load().
>> Hi Baoquan,
>>
>> Could you give me more detail about this?
> I mean machine_kexec_post_load() is the place where post load operations
> are done, including kexec_load and kexec_file_load. There's no need to
> specifically introduce a kimage_file_post_load() to do post load
> operaton for kexec_file_load.
Hi Baoquan,
Updating the machine_kexec_post_load() API to carry flags would indeed
require changes to multiple files. This approach involves the condition
check if (!(flags & KEXEC_FILE_ON_CRASH)) and ensuring that the flags
are properly passed and handled across the relevant file
if just adding a API kimage_file_post_load() here, it is much easy and
clean, right?
How do you think?
Thanks,
Steven
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-25 22:27 ` steven chen
@ 2025-03-26 2:27 ` Baoquan He
2025-03-26 22:46 ` steven chen
0 siblings, 1 reply; 34+ messages in thread
From: Baoquan He @ 2025-03-26 2:27 UTC (permalink / raw)
To: steven chen
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 03/25/25 at 03:27pm, steven chen wrote:
> On 3/24/2025 4:00 AM, Baoquan He wrote:
> > On 03/21/25 at 09:23am, steven chen wrote:
> > > On 3/19/2025 7:06 PM, Baoquan He wrote:
> > > > On 03/17/25 at 06:04pm, steven chen wrote:
> > > > ...snip...
> > > > > ---
> > > > > 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
> > > > > +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, initrd_fd,
> > > > > kimage_terminate(image);
> > > > > + if (!(flags & KEXEC_FILE_ON_CRASH))
> > > > > + kimage_file_post_load(image);
> > > > machine_kexec_post_load() is called by both kexec_load and kexec_file_load,
> > > > we should use it to do things post load, but not introducing another
> > > > kimage_file_post_load().
> > > Hi Baoquan,
> > >
> > > Could you give me more detail about this?
> > I mean machine_kexec_post_load() is the place where post load operations
> > are done, including kexec_load and kexec_file_load. There's no need to
> > specifically introduce a kimage_file_post_load() to do post load
> > operaton for kexec_file_load.
>
> Hi Baoquan,
>
> Updating the machine_kexec_post_load() API to carry flags would indeed
> require changes to multiple files. This approach involves the condition
> check if (!(flags & KEXEC_FILE_ON_CRASH)) and ensuring that the flags are
> properly passed and handled across the relevant file
>
> if just adding a API kimage_file_post_load() here, it is much easy and
> clean, right?
Hmm, it's easier, while maybe not good. We should not repeatedly
introduce similar things into codes. Here, it's similar as
what kexec_apply_relocations() and arch_kexec_apply_relocations() are
doing.
int machine_kexec_post_load(struct kimage *image)
{
#ifdef CONFIG_IMA_KEXEC
ima_kexec_post_load(image);
#endif
return arch_machine_kexec_post_load();
}
Then a generic arch_machine_kexec_post_load(struct kimage *image)
{return 0;} version, and a arm64 specific version.
Is it OK to you?
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-26 2:27 ` Baoquan He
@ 2025-03-26 22:46 ` steven chen
2025-03-26 23:44 ` Mimi Zohar
0 siblings, 1 reply; 34+ messages in thread
From: steven chen @ 2025-03-26 22:46 UTC (permalink / raw)
To: Baoquan He
Cc: zohar, stefanb, roberto.sassu, roberto.sassu, eric.snowberg,
ebiederm, paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
On 3/25/2025 7:27 PM, Baoquan He wrote:
> On 03/25/25 at 03:27pm, steven chen wrote:
>> On 3/24/2025 4:00 AM, Baoquan He wrote:
>>> On 03/21/25 at 09:23am, steven chen wrote:
>>>> On 3/19/2025 7:06 PM, Baoquan He wrote:
>>>>> On 03/17/25 at 06:04pm, steven chen wrote:
>>>>> ...snip...
>>>>>> ---
>>>>>> 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
>>>>>> +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, initrd_fd,
>>>>>> kimage_terminate(image);
>>>>>> + if (!(flags & KEXEC_FILE_ON_CRASH))
>>>>>> + kimage_file_post_load(image);
>>>>> machine_kexec_post_load() is called by both kexec_load and kexec_file_load,
>>>>> we should use it to do things post load, but not introducing another
>>>>> kimage_file_post_load().
>>>> Hi Baoquan,
>>>>
>>>> Could you give me more detail about this?
>>> I mean machine_kexec_post_load() is the place where post load operations
>>> are done, including kexec_load and kexec_file_load. There's no need to
>>> specifically introduce a kimage_file_post_load() to do post load
>>> operaton for kexec_file_load.
>> Hi Baoquan,
>>
>> Updating the machine_kexec_post_load() API to carry flags would indeed
>> require changes to multiple files. This approach involves the condition
>> check if (!(flags & KEXEC_FILE_ON_CRASH)) and ensuring that the flags are
>> properly passed and handled across the relevant file
>>
>> if just adding a API kimage_file_post_load() here, it is much easy and
>> clean, right?
> Hmm, it's easier, while maybe not good. We should not repeatedly
> introduce similar things into codes. Here, it's similar as
> what kexec_apply_relocations() and arch_kexec_apply_relocations() are
> doing.
>
> int machine_kexec_post_load(struct kimage *image)
> {
> #ifdef CONFIG_IMA_KEXEC
> ima_kexec_post_load(image);
> #endif
> return arch_machine_kexec_post_load();
> }
>
> Then a generic arch_machine_kexec_post_load(struct kimage *image)
> {return 0;} version, and a arm64 specific version.
>
> Is it OK to you?
Hi Baoquan,
Thanks for your suggestion. I will update in the next version.
Steven
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute
2025-03-26 22:46 ` steven chen
@ 2025-03-26 23:44 ` Mimi Zohar
0 siblings, 0 replies; 34+ messages in thread
From: Mimi Zohar @ 2025-03-26 23:44 UTC (permalink / raw)
To: steven chen, Baoquan He
Cc: stefanb, roberto.sassu, roberto.sassu, eric.snowberg, ebiederm,
paul, code, bauermann, linux-integrity, kexec,
linux-security-module, linux-kernel, madvenka, nramas,
James.Bottomley, vgoyal, dyoung
> > Hmm, it's easier, while maybe not good. We should not repeatedly
> > introduce similar things into codes. Here, it's similar as
> > what kexec_apply_relocations() and arch_kexec_apply_relocations() are
> > doing.
> >
> > int machine_kexec_post_load(struct kimage *image)
(As discussed) just as kexec_apply_relocation calls
arch_kexec_apply_relocations(). Name this function kexec_post_load() and call
machine_kexec_post_load().
Mimi
> > {
> > #ifdef CONFIG_IMA_KEXEC
> > ima_kexec_post_load(image);
> > #endif
> > return arch_machine_kexec_post_load();
> > }
>
^ permalink raw reply [flat|nested] 34+ messages in thread
end of thread, other threads:[~2025-03-26 23:44 UTC | newest]
Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-18 1:04 [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute steven chen
2025-03-18 1:04 ` [PATCH v10 1/8] ima: rename variable the ser_file "file" to "ima_kexec_file" steven chen
2025-03-18 15:10 ` Stefan Berger
2025-03-19 2:43 ` Baoquan He
2025-03-21 16:15 ` steven chen
2025-03-19 13:42 ` Mimi Zohar
2025-03-21 16:16 ` steven chen
2025-03-18 1:04 ` [PATCH v10 2/8] ima: define and call ima_alloc_kexec_file_buf() steven chen
2025-03-19 8:09 ` Baoquan He
2025-03-19 16:27 ` Mimi Zohar
2025-03-20 1:51 ` Baoquan He
2025-03-20 13:06 ` Mimi Zohar
2025-03-21 16:18 ` steven chen
2025-03-18 1:04 ` [PATCH v10 3/8] kexec: define functions to map and unmap segments steven chen
2025-03-19 10:12 ` Baoquan He
2025-03-18 1:04 ` [PATCH v10 4/8] ima: kexec: skip IMA segment validation after kexec soft reboot steven chen
2025-03-19 10:16 ` Baoquan He
2025-03-18 1:04 ` [PATCH v10 5/8] ima: kexec: define functions to copy IMA log at soft boot steven chen
2025-03-18 1:04 ` [PATCH v10 6/8] ima: kexec: move IMA log copy from kexec load to execute steven chen
2025-03-19 20:53 ` Mimi Zohar
2025-03-21 16:20 ` steven chen
2025-03-20 2:06 ` Baoquan He
2025-03-21 16:23 ` steven chen
2025-03-24 11:00 ` Baoquan He
2025-03-25 22:27 ` steven chen
2025-03-26 2:27 ` Baoquan He
2025-03-26 22:46 ` steven chen
2025-03-26 23:44 ` Mimi Zohar
2025-03-18 1:04 ` [PATCH v10 7/8] ima: make the kexec extra memory configurable steven chen
2025-03-20 2:52 ` Baoquan He
2025-03-21 16:46 ` steven chen
2025-03-18 1:04 ` [PATCH v10 8/8] ima: measure kexec load and exec events as critical data steven chen
2025-03-20 2:59 ` Mimi Zohar
2025-03-21 16:49 ` steven chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).