From: Stefan Berger <stefanb@linux.ibm.com>
To: Tushar Sugandhi <tusharsu@linux.microsoft.com>,
zohar@linux.ibm.com, roberto.sassu@huaweicloud.com,
roberto.sassu@huawei.com, eric.snowberg@oracle.com,
ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com,
linux-integrity@vger.kernel.org, kexec@lists.infradead.org
Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com
Subject: Re: [PATCH v4 1/7] ima: define and call ima_alloc_kexec_file_buf
Date: Tue, 23 Jan 2024 22:38:53 -0500 [thread overview]
Message-ID: <efc24a43-2ebb-4fa4-814a-7c0ad5ef022e@linux.ibm.com> (raw)
In-Reply-To: <2c4e98bc-8e26-4df1-8567-04d81d2c3963@linux.ibm.com>
On 1/23/24 21:54, Stefan Berger wrote:
>
>
> On 1/22/24 13:37, Tushar Sugandhi wrote:
>> Refactor ima_dump_measurement_list() to move the memory allocation part
>> 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 function ima_dump_measurement_list() as 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>
>> ---
>> security/integrity/ima/ima_kexec.c | 96 +++++++++++++++++++++---------
>> 1 file changed, 67 insertions(+), 29 deletions(-)
>>
>> diff --git a/security/integrity/ima/ima_kexec.c
>> b/security/integrity/ima/ima_kexec.c
>> index 419dc405c831..99daac355c70 100644
>> --- a/security/integrity/ima/ima_kexec.c
>> +++ b/security/integrity/ima/ima_kexec.c
>> @@ -15,62 +15,93 @@
>> #include "ima.h"
>> #ifdef CONFIG_IMA_KEXEC
>> +static struct seq_file ima_kexec_file;
>> +
>> +static void ima_free_kexec_file_buf(struct seq_file *sf)
>> +{
>> + vfree(sf->buf);
>> + sf->buf = NULL;
>> + sf->size = 0;
>> + sf->read_pos = 0;
>> + sf->count = 0;
>> +}
>> +
>> +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 &&
>> + ima_kexec_file.read_pos == 0 &&
>> + ima_kexec_file.count == sizeof(struct ima_kexec_hdr))
>> + return 0;
>> +
>> + 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;
>> + ima_kexec_file.read_pos = 0;
>> + ima_kexec_file.count = sizeof(struct ima_kexec_hdr); /*
>> reserved space */
>> +
>> + return 0;
>> +}
>> +
>> static int ima_dump_measurement_list(unsigned long *buffer_size,
>> void **buffer,
>> unsigned long segment_size)
>> {
>> struct ima_queue_entry *qe;
>> - struct seq_file file;
>> struct ima_kexec_hdr khdr;
>> - int ret = 0;
>> - /* segment size can't change between kexec load and execute */
>> - file.buf = vmalloc(segment_size);
>> - if (!file.buf) {
>> - ret = -ENOMEM;
>> - goto out;
>> + if (!ima_kexec_file.buf) {
>> + *buffer_size = 0;
>> + *buffer = NULL;
>> + pr_err("%s: Kexec file buf not allocated\n", __func__);
>> + return -EINVAL;
>> }
>> - file.size = segment_size;
>> - file.read_pos = 0;
>> - file.count = sizeof(khdr); /* reserved space */
>> -
>> memset(&khdr, 0, sizeof(khdr));
>> khdr.version = 1;
>> +
>> + /* Copy as many IMA measurements list records as possible */
>> list_for_each_entry_rcu(qe, &ima_measurements, later) {
>> - if (file.count < file.size) {
>> + 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;
>> + pr_err("%s: IMA log file is too big for Kexec buf\n",
>> + __func__);
>> break;
>> }
>> }
>> - if (ret < 0)
>> - goto out;
>> -
>> /*
>> * fill in reserved space with some buffer details
>> * (eg. version, buffer size, number of measurements)
>> */
>> - khdr.buffer_size = file.count;
>> + khdr.buffer_size = ima_kexec_file.count;
>> if (ima_canonical_fmt) {
>> khdr.version = cpu_to_le16(khdr.version);
>> khdr.count = cpu_to_le64(khdr.count);
>> khdr.buffer_size = cpu_to_le64(khdr.buffer_size);
>> }
>> - memcpy(file.buf, &khdr, sizeof(khdr));
>> + memcpy(ima_kexec_file.buf, &khdr, sizeof(khdr));
>> print_hex_dump_debug("ima dump: ", DUMP_PREFIX_NONE, 16, 1,
>> - file.buf, file.count < 100 ? file.count : 100,
>> + ima_kexec_file.buf, ima_kexec_file.count < 100 ?
>> + ima_kexec_file.count : 100,
>> true);
>> - *buffer_size = file.count;
>> - *buffer = file.buf;
>> -out:
>> - if (ret == -EINVAL)
>> - vfree(file.buf);
>> - return ret;
>> + *buffer_size = ima_kexec_file.count;
>> + *buffer = ima_kexec_file.buf;
>> +
>> + return 0;
>> }
>> /*
>> @@ -108,13 +139,20 @@ void ima_add_kexec_buffer(struct kimage *image)
>> return;
>> }
>> - ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
>> - kexec_segment_size);
>> - if (!kexec_buffer) {
>> + ret = ima_alloc_kexec_file_buf(kexec_segment_size);
>> + if (ret < 0) {
>> pr_err("Not enough memory for the kexec measurement
>> buffer.\n");
>> return;
>> }
>> + ret = ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
>> + kexec_segment_size);
>> + if (ret < 0) {
>> + pr_err("%s: Failed to dump IMA measurements. Error:%d.\n",
>> + __func__, ret);
>> + return;
>> + }
>> +
>> kbuf.buffer = kexec_buffer;
>> kbuf.bufsz = kexec_buffer_size;
>> kbuf.memsz = kexec_segment_size;
>
>
> A dent with this patch when only applying this patch:
>
> Two consecutive kexec loads lead to this here:
>
> [ 30.670330] IMA buffer at 0x3fff10000, size = 0xf0000
> [ 32.519618] ------------[ cut here ]------------
> [ 32.519669] Trying to vfree() nonexistent vm area (00000000093ae29c)
> [ 32.519762] WARNING: CPU: 11 PID: 1796 at mm/vmalloc.c:2826
> vfree+0x254/0x340
> [ 32.519786] Modules linked in: bonding tls rfkill sunrpc
> virtio_console virtio_balloon crct10dif_vpmsum fuse loop zram bochs
> drm_vram_helper drm_kms_helper drm_ttm_helper ttm ibmvscsi
> scsi_transport_srp drm virtio_blk virtio_net vmx_crypto net_failover
> crc32c_vpmsum failover pseries_wdt drm_panel_orientation_quirks
> scsi_dh_rdac scsi_dh_emc scsi_dh_alua dm_multipath
> [ 32.519939] CPU: 11 PID: 1796 Comm: kexec Not tainted 6.5.0+ #112
> [ 32.519953] Hardware name: IBM pSeries (emulated by qemu) POWER8E
> (raw) 0x4b0201 0xf000004 of:SLOF,git-5b4c5a hv:linux,kvm pSeries
> [ 32.519973] NIP: c0000000004bd004 LR: c0000000004bd000 CTR:
> c00000000017ef00
> [ 32.519986] REGS: c00000004593b670 TRAP: 0700 Not tainted (6.5.0+)
> [ 32.519999] MSR: 8000000002029033 <SF,VEC,EE,ME,IR,DR,RI,LE> CR:
> 44424842 XER: 00000000
> [ 32.520023] CFAR: c0000000001515b0 IRQMASK: 0
> GPR00: c0000000004bd000 c00000004593b910
> c000000001e17000 0000000000000038
> GPR04: 00000000ffffbfff c00000004593b6e8
> c00000004593b6e0 00000003f9580000
> GPR08: 0000000000000027 c0000003fb707010
> 0000000000000001 0000000044424842
> GPR12: c00000000017ef00 c00000003fff1300
> 0000000000000000 0000000000000000
> GPR16: 0000000000000000 0000000000000000
> 0000000000000000 0000000000000000
> GPR20: 0000000000000000 0000000000000000
> 0000000000000003 0000000000000004
> GPR24: 00007fffeab0f68f 000000000000004c
> 0000000000000000 c00000002bdce400
> GPR28: c000000002bf28f0 0000000000000000
> c008000004770000 0000000000000000
> [ 32.520180] NIP [c0000000004bd004] vfree+0x254/0x340
> [ 32.520212] LR [c0000000004bd000] vfree+0x250/0x340
> [ 32.520225] Call Trace:
> [ 32.520232] [c00000004593b910] [c0000000004bd000] vfree+0x250/0x340
> (unreliable)
> [ 32.520250] [c00000004593b990] [c00000000091d590]
> ima_add_kexec_buffer+0xe0/0x3c0
> [ 32.520296] [c00000004593ba90] [c000000000280968]
> sys_kexec_file_load+0x148/0x9b0
> [ 32.520333] [c00000004593bb70] [c00000000002ea84]
> system_call_exception+0x174/0x320
> [ 32.520372] [c00000004593be50] [c00000000000d6a0]
> system_call_common+0x160/0x2c4
> [ 32.520408] --- interrupt: c00 at 0x7fffa52e7ae4
> [ 32.520420] NIP: 00007fffa52e7ae4 LR: 0000000108481d8c CTR:
> 0000000000000000
> [ 32.520452] REGS: c00000004593be80 TRAP: 0c00 Not tainted (6.5.0+)
> [ 32.520483] MSR: 800000000000f033 <SF,EE,PR,FP,ME,IR,DR,RI,LE> CR:
> 24424202 XER: 00000000
> [ 32.520507] IRQMASK: 0
> GPR00: 000000000000017e 00007fffeab09470
> 00007fffa53f6f00 0000000000000003
> GPR04: 0000000000000004 000000000000004c
> 00007fffeab0f68f 0000000000000000
> GPR08: 0000000000000000 0000000000000000
> 0000000000000000 0000000000000000
> GPR12: 0000000000000000 00007fffa559b280
> 0000000000000002 0000000000000001
> GPR16: 0000000000000000 0000000000000000
> 0000000000000000 0000000000000000
> GPR20: 00007fffa53f0454 00007fffa53f0458
> 0000000000000000 0000000000000001
> GPR24: 0000000000000000 00007fffeab0f64d
> 0000000000000006 0000000000000000
> GPR28: 0000000000000003 00007fffeab09530
> 00007fffeab09b08 0000000000000007
> [ 32.520767] NIP [00007fffa52e7ae4] 0x7fffa52e7ae4
> [ 32.521192] LR [0000000108481d8c] 0x108481d8c
> [ 32.521587] --- interrupt: c00
> [ 32.521981] Code: 3884c208 4bfc20f1 60000000 0fe00000 60000000
> 60000000 60420000 3c62ff94 7fc4f378 38632b20 4bc944cd 60000000
> <0fe00000> eba10068 4bffff34 2c080000
> [ 32.522823] ---[ end trace 0000000000000000 ]---
> [ 32.536347] Removed old IMA buffer reservation.
> [ 32.536473] IMA buffer at 0x3fff10000, size = 0xf0000
>
> This vfree here probably has to go:
>
> ret = kexec_add_buffer(&kbuf);
> if (ret) {
> pr_err("Error passing over kexec measurement buffer.\n");
> vfree(kexec_buffer);
> return;
> }
>
The vfree may need to be removed or replaced with
ima_free_kexec_file_buf() but it doesn't seem to solve the problem alone.
I got rid of this issue later with this:
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);
}
[...]
@@ -170,6 +175,9 @@ 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 since kexec_add_buffer and will
vfree() it */
+ ima_reset_kexec_file(&ima_kexec_file);
+
pr_debug("kexec measurement buffer for the loaded kernel at
0x%lx.\n",
kbuf.mem);
> _______________________________________________
> kexec mailing list
> kexec@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kexec
next prev parent reply other threads:[~2024-01-24 3:39 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-22 18:37 [PATCH v4 0/7] ima: kexec: measure events between kexec load and execute Tushar Sugandhi
2024-01-22 18:37 ` [PATCH v4 1/7] ima: define and call ima_alloc_kexec_file_buf Tushar Sugandhi
2024-01-24 2:54 ` Stefan Berger
2024-01-24 3:38 ` Stefan Berger [this message]
2024-01-26 22:14 ` Tushar Sugandhi
2024-01-24 13:33 ` Mimi Zohar
2024-01-25 19:03 ` Tushar Sugandhi
2024-01-22 18:37 ` [PATCH v4 2/7] kexec: define functions to map and unmap segments Tushar Sugandhi
2024-01-23 17:03 ` Stefan Berger
2024-01-23 20:39 ` Tushar Sugandhi
2024-01-22 18:38 ` [PATCH v4 3/7] ima: kexec: skip IMA segment validation after kexec soft reboot Tushar Sugandhi
2024-01-22 18:38 ` [PATCH v4 4/7] ima: kexec: move ima log copy from kexec load to execute Tushar Sugandhi
2024-01-24 16:11 ` Mimi Zohar
2024-01-25 19:06 ` Tushar Sugandhi
2024-01-22 18:38 ` [PATCH v4 5/7] ima: suspend measurements during buffer copy at kexec execute Tushar Sugandhi
2024-01-23 18:18 ` Stefan Berger
2024-01-23 20:55 ` Tushar Sugandhi
2024-01-22 18:38 ` [PATCH v4 6/7] ima: make the kexec extra memory configurable Tushar Sugandhi
2024-01-23 19:02 ` Stefan Berger
2024-01-23 21:19 ` Tushar Sugandhi
2024-01-24 1:48 ` Stefan Berger
2024-01-24 14:07 ` Mimi Zohar
2024-01-25 19:14 ` Tushar Sugandhi
2024-01-22 18:38 ` [PATCH v4 7/7] ima: measure kexec load and exec events as critical data Tushar Sugandhi
2024-01-24 14:35 ` Mimi Zohar
2024-01-25 19:16 ` Tushar Sugandhi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=efc24a43-2ebb-4fa4-814a-7c0ad5ef022e@linux.ibm.com \
--to=stefanb@linux.ibm.com \
--cc=bauermann@kolabnow.com \
--cc=code@tyhicks.com \
--cc=ebiederm@xmission.com \
--cc=eric.snowberg@oracle.com \
--cc=kexec@lists.infradead.org \
--cc=linux-integrity@vger.kernel.org \
--cc=noodles@fb.com \
--cc=nramas@linux.microsoft.com \
--cc=paul@paul-moore.com \
--cc=roberto.sassu@huawei.com \
--cc=roberto.sassu@huaweicloud.com \
--cc=tusharsu@linux.microsoft.com \
--cc=zohar@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox