Message ID | 20250218225502.747963-5-chenste@linux.microsoft.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | ima: kexec: measure events between kexec load and execute | expand |
On 2/18/25 5:54 PM, steven chen wrote: > IMA log is copied to the new Kernel during kexec 'load' using The IMA log is currently copied to the new kernel ... > ima_dump_measurement_list(). The log copy at kexec 'load' may result in > loss of IMA measurements during kexec soft reboot. It needs to be copied However, the log copied at kexec 'load' may result in loss of IMA measurements due to missed measurements that only occurred after kexec 'load'. Therefore, the log needs to be copied during kexec 'execute'. Setup the ... > over 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 > exec 'execute'. kexec 'execute' > > Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> > Signed-off-by: steven chen <chenste@linux.microsoft.com> With the above changes: Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> > --- > include/linux/ima.h | 3 ++ > security/integrity/ima/ima_kexec.c | 46 ++++++++++++++++++++++++++++++ > 2 files changed, 49 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 704676fa6615..0fa65f91414b 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 struct seq_file ima_kexec_file; > +static void *ima_kexec_buffer; > +static bool ima_kexec_update_registered; > > static void ima_reset_kexec_file(struct seq_file *sf) > { > @@ -183,6 +187,48 @@ 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; > +} > + > +struct notifier_block update_buffer_nb = { > + .notifier_call = ima_update_kexec_buffer, > +}; > + > +/* > + * 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 */ > > /*
On 2/19/2025 7:37 AM, Stefan Berger wrote: > > > On 2/18/25 5:54 PM, steven chen wrote: >> IMA log is copied to the new Kernel during kexec 'load' using > > The IMA log is currently copied to the new kernel ... > > >> ima_dump_measurement_list(). The log copy at kexec 'load' may result in >> loss of IMA measurements during kexec soft reboot. It needs to be >> copied > > However, the log copied at kexec 'load' may result in loss of IMA > measurements due to missed measurements that only occurred after kexec > 'load'. Therefore, the log needs to be copied during kexec 'execute'. > Setup the ... > >> over 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 >> exec 'execute'. > > kexec 'execute' > >> >> Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> >> Signed-off-by: steven chen <chenste@linux.microsoft.com> > > With the above changes: > > Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> > >> --- >> include/linux/ima.h | 3 ++ >> security/integrity/ima/ima_kexec.c | 46 ++++++++++++++++++++++++++++++ >> 2 files changed, 49 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 704676fa6615..0fa65f91414b 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 struct seq_file ima_kexec_file; >> +static void *ima_kexec_buffer; >> +static bool ima_kexec_update_registered; >> static void ima_reset_kexec_file(struct seq_file *sf) >> { >> @@ -183,6 +187,48 @@ 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; >> +} >> + >> +struct notifier_block update_buffer_nb = { >> + .notifier_call = ima_update_kexec_buffer, >> +}; >> + >> +/* >> + * 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 */ >> /* Hi Stefan, thanks for your comments. I will update in next version.
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 704676fa6615..0fa65f91414b 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 struct seq_file ima_kexec_file; +static void *ima_kexec_buffer; +static bool ima_kexec_update_registered; static void ima_reset_kexec_file(struct seq_file *sf) { @@ -183,6 +187,48 @@ 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; +} + +struct notifier_block update_buffer_nb = { + .notifier_call = ima_update_kexec_buffer, +}; + +/* + * 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 */ /*