From: Tushar Sugandhi <tusharsu@linux.microsoft.com> To: zohar@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, kexec@lists.infradead.org, linux-integrity@vger.kernel.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v2 1/7] ima: refactor ima_dump_measurement_list to move memory allocation to a separate function Date: Thu, 5 Oct 2023 11:25:56 -0700 [thread overview] Message-ID: <20231005182602.634615-2-tusharsu@linux.microsoft.com> (raw) In-Reply-To: <20231005182602.634615-1-tusharsu@linux.microsoft.com> IMA allocates memory and dumps the measurement during kexec soft reboot as a single function call ima_dump_measurement_list(). It gets called during kexec 'load' operation. It results in the IMA measurements between the window of kexec 'load' and 'execute' getting dropped when the system boots into the new Kernel. One of the kexec requirements is the segment size cannot change between the 'load' and the 'execute'. Therefore, to address this problem, ima_dump_measurement_list() needs to be refactored to allocate the memory at kexec 'load', and dump the measurements at kexec 'execute'. The function that allocates the memory should handle the scenario where the kexec load is called multiple times. Refactor ima_dump_measurement_list() to move the memory allocation part to a separate function ima_alloc_kexec_buf() to allocate buffer of size 'kexec_segment_size' at kexec 'load'. Make the local variables in function ima_dump_measurement_list() global, so that they can be accessed from ima_alloc_kexec_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 | 126 +++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 33 deletions(-) diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 419dc405c831..307e07991865 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -15,61 +15,114 @@ #include "ima.h" #ifdef CONFIG_IMA_KEXEC +struct seq_file ima_kexec_file; +struct ima_kexec_hdr ima_khdr; + +void ima_clear_kexec_file(void) +{ + vfree(ima_kexec_file.buf); + ima_kexec_file.buf = NULL; + ima_kexec_file.size = 0; + ima_kexec_file.read_pos = 0; + ima_kexec_file.count = 0; +} + +static int ima_alloc_kexec_buf(size_t kexec_segment_size) +{ + if ((kexec_segment_size == 0) || + (kexec_segment_size == ULONG_MAX) || + ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) { + pr_err("%s: Invalid segment size for kexec: %zu\n", + __func__, kexec_segment_size); + return -EINVAL; + } + + /* + * If kexec load was called before, clear the existing buffer + * before allocating a new one + */ + if (ima_kexec_file.buf) + ima_clear_kexec_file(); + + /* segment size can't change between kexec load and execute */ + ima_kexec_file.buf = vmalloc(kexec_segment_size); + if (!ima_kexec_file.buf) { + pr_err("%s: No memory for ima kexec measurement buffer\n", + __func__); + return -ENOMEM; + } + + ima_kexec_file.size = kexec_segment_size; + ima_kexec_file.read_pos = 0; + ima_kexec_file.count = sizeof(ima_khdr); /* reserved space */ + + memset(&ima_khdr, 0, sizeof(ima_khdr)); + ima_khdr.version = 1; + + 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) { + 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 */ + /* + * Ensure the kexec buffer is large enough to hold ima_khdr + */ + if (ima_kexec_file.size < sizeof(ima_khdr)) { + pr_err("%s: Kexec buffer size too low to hold ima_khdr\n", + __func__); + ima_clear_kexec_file(); + return -ENOMEM; + } - memset(&khdr, 0, sizeof(khdr)); - khdr.version = 1; + /* + * If we reach here, then there is enough memory + * of size kexec_segment_size in ima_kexec_file.buf + * to copy at least partial IMA log. + * Make best effort to copy as many IMA measurements + * as possible. + */ list_for_each_entry_rcu(qe, &ima_measurements, later) { - if (file.count < file.size) { - khdr.count++; - ima_measurements_show(&file, qe); + if (ima_kexec_file.count < ima_kexec_file.size) { + ima_khdr.count++; + ima_measurements_show(&ima_kexec_file, qe); } else { - ret = -EINVAL; + ret = EFBIG; + 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; + ima_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); + ima_khdr.version = cpu_to_le16(ima_khdr.version); + ima_khdr.count = cpu_to_le64(ima_khdr.count); + ima_khdr.buffer_size = cpu_to_le64(ima_khdr.buffer_size); } - memcpy(file.buf, &khdr, sizeof(khdr)); + memcpy(ima_kexec_file.buf, &ima_khdr, sizeof(ima_khdr)); print_hex_dump_debug("ima dump: ", DUMP_PREFIX_NONE, 16, 1, - file.buf, file.count < 100 ? file.count : 100, + ima_kexec_file.buf, ima_kexec_file.count < 100 ? + ima_kexec_file.count : 100, true); - *buffer_size = file.count; - *buffer = file.buf; -out: - if (ret == -EINVAL) - vfree(file.buf); + *buffer_size = ima_kexec_file.count; + *buffer = ima_kexec_file.buf; + return ret; } @@ -108,13 +161,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_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; -- 2.25.1
WARNING: multiple messages have this Message-ID (diff)
From: Tushar Sugandhi <tusharsu@linux.microsoft.com> To: zohar@linux.ibm.com, ebiederm@xmission.com, noodles@fb.com, bauermann@kolabnow.com, kexec@lists.infradead.org, linux-integrity@vger.kernel.org Cc: code@tyhicks.com, nramas@linux.microsoft.com, paul@paul-moore.com Subject: [PATCH v2 1/7] ima: refactor ima_dump_measurement_list to move memory allocation to a separate function Date: Thu, 5 Oct 2023 11:25:56 -0700 [thread overview] Message-ID: <20231005182602.634615-2-tusharsu@linux.microsoft.com> (raw) In-Reply-To: <20231005182602.634615-1-tusharsu@linux.microsoft.com> IMA allocates memory and dumps the measurement during kexec soft reboot as a single function call ima_dump_measurement_list(). It gets called during kexec 'load' operation. It results in the IMA measurements between the window of kexec 'load' and 'execute' getting dropped when the system boots into the new Kernel. One of the kexec requirements is the segment size cannot change between the 'load' and the 'execute'. Therefore, to address this problem, ima_dump_measurement_list() needs to be refactored to allocate the memory at kexec 'load', and dump the measurements at kexec 'execute'. The function that allocates the memory should handle the scenario where the kexec load is called multiple times. Refactor ima_dump_measurement_list() to move the memory allocation part to a separate function ima_alloc_kexec_buf() to allocate buffer of size 'kexec_segment_size' at kexec 'load'. Make the local variables in function ima_dump_measurement_list() global, so that they can be accessed from ima_alloc_kexec_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 | 126 +++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 33 deletions(-) diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c index 419dc405c831..307e07991865 100644 --- a/security/integrity/ima/ima_kexec.c +++ b/security/integrity/ima/ima_kexec.c @@ -15,61 +15,114 @@ #include "ima.h" #ifdef CONFIG_IMA_KEXEC +struct seq_file ima_kexec_file; +struct ima_kexec_hdr ima_khdr; + +void ima_clear_kexec_file(void) +{ + vfree(ima_kexec_file.buf); + ima_kexec_file.buf = NULL; + ima_kexec_file.size = 0; + ima_kexec_file.read_pos = 0; + ima_kexec_file.count = 0; +} + +static int ima_alloc_kexec_buf(size_t kexec_segment_size) +{ + if ((kexec_segment_size == 0) || + (kexec_segment_size == ULONG_MAX) || + ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages() / 2)) { + pr_err("%s: Invalid segment size for kexec: %zu\n", + __func__, kexec_segment_size); + return -EINVAL; + } + + /* + * If kexec load was called before, clear the existing buffer + * before allocating a new one + */ + if (ima_kexec_file.buf) + ima_clear_kexec_file(); + + /* segment size can't change between kexec load and execute */ + ima_kexec_file.buf = vmalloc(kexec_segment_size); + if (!ima_kexec_file.buf) { + pr_err("%s: No memory for ima kexec measurement buffer\n", + __func__); + return -ENOMEM; + } + + ima_kexec_file.size = kexec_segment_size; + ima_kexec_file.read_pos = 0; + ima_kexec_file.count = sizeof(ima_khdr); /* reserved space */ + + memset(&ima_khdr, 0, sizeof(ima_khdr)); + ima_khdr.version = 1; + + 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) { + 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 */ + /* + * Ensure the kexec buffer is large enough to hold ima_khdr + */ + if (ima_kexec_file.size < sizeof(ima_khdr)) { + pr_err("%s: Kexec buffer size too low to hold ima_khdr\n", + __func__); + ima_clear_kexec_file(); + return -ENOMEM; + } - memset(&khdr, 0, sizeof(khdr)); - khdr.version = 1; + /* + * If we reach here, then there is enough memory + * of size kexec_segment_size in ima_kexec_file.buf + * to copy at least partial IMA log. + * Make best effort to copy as many IMA measurements + * as possible. + */ list_for_each_entry_rcu(qe, &ima_measurements, later) { - if (file.count < file.size) { - khdr.count++; - ima_measurements_show(&file, qe); + if (ima_kexec_file.count < ima_kexec_file.size) { + ima_khdr.count++; + ima_measurements_show(&ima_kexec_file, qe); } else { - ret = -EINVAL; + ret = EFBIG; + 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; + ima_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); + ima_khdr.version = cpu_to_le16(ima_khdr.version); + ima_khdr.count = cpu_to_le64(ima_khdr.count); + ima_khdr.buffer_size = cpu_to_le64(ima_khdr.buffer_size); } - memcpy(file.buf, &khdr, sizeof(khdr)); + memcpy(ima_kexec_file.buf, &ima_khdr, sizeof(ima_khdr)); print_hex_dump_debug("ima dump: ", DUMP_PREFIX_NONE, 16, 1, - file.buf, file.count < 100 ? file.count : 100, + ima_kexec_file.buf, ima_kexec_file.count < 100 ? + ima_kexec_file.count : 100, true); - *buffer_size = file.count; - *buffer = file.buf; -out: - if (ret == -EINVAL) - vfree(file.buf); + *buffer_size = ima_kexec_file.count; + *buffer = ima_kexec_file.buf; + return ret; } @@ -108,13 +161,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_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; -- 2.25.1 _______________________________________________ kexec mailing list kexec@lists.infradead.org http://lists.infradead.org/mailman/listinfo/kexec
next prev parent reply other threads:[~2023-10-05 18:26 UTC|newest] Thread overview: 64+ messages / expand[flat|nested] mbox.gz Atom feed top 2023-10-05 18:25 [PATCH v2 0/7] ima: kexec: measure events between kexec load and execute Tushar Sugandhi 2023-10-05 18:25 ` Tushar Sugandhi 2023-10-05 18:25 ` Tushar Sugandhi [this message] 2023-10-05 18:25 ` [PATCH v2 1/7] ima: refactor ima_dump_measurement_list to move memory allocation to a separate function Tushar Sugandhi 2023-10-13 0:28 ` Stefan Berger 2023-10-13 0:28 ` Stefan Berger 2023-10-20 20:33 ` Tushar Sugandhi 2023-10-20 20:33 ` Tushar Sugandhi 2023-10-20 21:21 ` Stefan Berger 2023-10-20 21:21 ` Stefan Berger 2023-10-20 21:50 ` Tushar Sugandhi 2023-10-20 21:50 ` Tushar Sugandhi 2023-10-26 20:16 ` Mimi Zohar 2023-10-26 20:16 ` Mimi Zohar 2023-10-27 3:25 ` Mimi Zohar 2023-10-27 3:25 ` Mimi Zohar 2023-11-14 22:32 ` Tushar Sugandhi 2023-11-14 22:32 ` Tushar Sugandhi 2023-11-14 22:31 ` Tushar Sugandhi 2023-11-14 22:31 ` Tushar Sugandhi 2023-10-05 18:25 ` [PATCH v2 2/7] ima: move ima_dump_measurement_list call from kexec load to execute Tushar Sugandhi 2023-10-05 18:25 ` Tushar Sugandhi 2023-10-13 0:28 ` Stefan Berger 2023-10-13 0:28 ` Stefan Berger 2023-10-20 20:35 ` Tushar Sugandhi 2023-10-20 20:35 ` Tushar Sugandhi [not found] ` <989af3e9a8621f57643b67b717d9a39fdb2ffe24.camel@linux.ibm.com> 2023-11-14 22:43 ` Tushar Sugandhi 2023-11-14 22:43 ` Tushar Sugandhi 2023-11-15 22:30 ` Tushar Sugandhi 2023-11-15 22:30 ` Tushar Sugandhi 2023-10-05 18:25 ` [PATCH v2 3/7] ima: kexec: map source pages containing IMA buffer to image post kexec load Tushar Sugandhi 2023-10-05 18:25 ` Tushar Sugandhi 2023-10-13 0:29 ` Stefan Berger 2023-10-13 0:29 ` Stefan Berger 2023-10-20 20:36 ` Tushar Sugandhi 2023-10-20 20:36 ` Tushar Sugandhi 2023-10-05 18:25 ` [PATCH v2 4/7] kexec: update kexec_file_load syscall to call ima_kexec_post_load Tushar Sugandhi 2023-10-05 18:25 ` Tushar Sugandhi 2023-10-05 18:26 ` [PATCH v2 5/7] ima: suspend measurements while the buffer is being copied during kexec reboot Tushar Sugandhi 2023-10-05 18:26 ` Tushar Sugandhi 2023-10-05 18:26 ` [PATCH v2 6/7] ima: make the memory for events between kexec load and exec configurable Tushar Sugandhi 2023-10-05 18:26 ` Tushar Sugandhi 2023-10-13 0:27 ` Stefan Berger 2023-10-13 0:27 ` Stefan Berger 2023-10-20 20:39 ` Tushar Sugandhi 2023-10-20 20:39 ` Tushar Sugandhi 2023-10-20 21:16 ` Stefan Berger 2023-10-20 21:16 ` Stefan Berger 2023-10-20 21:53 ` Tushar Sugandhi 2023-10-20 21:53 ` Tushar Sugandhi 2023-10-05 18:26 ` [PATCH v2 7/7] ima: record log size at kexec load and execute Tushar Sugandhi 2023-10-05 18:26 ` Tushar Sugandhi 2023-10-13 0:27 ` Stefan Berger 2023-10-13 0:27 ` Stefan Berger 2023-10-20 20:40 ` Tushar Sugandhi 2023-10-20 20:40 ` Tushar Sugandhi [not found] ` <2b95e8b9ebe10a24c7cb6fc90cb2d1342a157ed5.camel@linux.ibm.com> 2023-11-14 22:48 ` Tushar Sugandhi 2023-11-14 22:48 ` Tushar Sugandhi [not found] ` <8f87e7e4fe5c5a24cdc0d3e2267eeaf00825d1bb.camel@linux.ibm.com> 2023-10-27 19:51 ` [PATCH v2 0/7] ima: kexec: measure events between " Mimi Zohar 2023-10-27 19:51 ` Mimi Zohar 2023-11-15 19:21 ` Tushar Sugandhi 2023-11-15 19:21 ` Tushar Sugandhi 2023-11-14 23:24 ` Tushar Sugandhi 2023-11-14 23:24 ` 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=20231005182602.634615-2-tusharsu@linux.microsoft.com \ --to=tusharsu@linux.microsoft.com \ --cc=bauermann@kolabnow.com \ --cc=code@tyhicks.com \ --cc=ebiederm@xmission.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=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: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.