@@ -211,8 +211,55 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl
kfree(ima_buf_head);
}
+/*
+ * Measure IMA data on device resume
+ */
+void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap)
+{
+ char *device_table_data;
+ unsigned int noio_flag, l;
+ char active[] = "active_table_hash=";
+ unsigned int active_len = strlen(active);
+
+ noio_flag = memalloc_noio_save();
+ device_table_data = kzalloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL);
+ memalloc_noio_restore(noio_flag);
+
+ if (!device_table_data)
+ return;
+
+ if (swap) {
+ kfree(md->ima.active_table_hash);
+ md->ima.active_table_hash = NULL;
+ md->ima.active_table_hash_len = 0;
+
+ if (md->ima.inactive_table_hash) {
+ md->ima.active_table_hash = md->ima.inactive_table_hash;
+ md->ima.active_table_hash_len = md->ima.inactive_table_hash_len;
+ md->ima.inactive_table_hash = NULL;
+ md->ima.inactive_table_hash_len = 0;
+ }
+ }
+
+ l = md->ima.device_data_len;
+ memcpy(device_table_data, md->ima.device_data, l);
+ memcpy(device_table_data + l, active, active_len);
+ l += active_len;
+
+ memcpy(device_table_data + l, md->ima.active_table_hash, md->ima.active_table_hash_len);
+ l += md->ima.active_table_hash_len;
+
+ memcpy(device_table_data + l, ";", 1);
+ l++;
+
+ dm_ima_measure_data("device_resume", device_table_data, l);
+
+ kfree(device_table_data);
+}
+
#else
void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags) {}
+void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap) {}
#endif
MODULE_AUTHOR("Tushar Sugandhi <tusharsu@linux.microsoft.com>");
MODULE_DESCRIPTION("Enables IMA measurements for DM targets");
@@ -33,4 +33,5 @@ struct dm_ima_measurements {
};
void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags);
+void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap);
#endif /*DM_IMA_H*/
@@ -1162,8 +1162,12 @@ static int do_resume(struct dm_ioctl *param)
if (dm_suspended_md(md)) {
r = dm_resume(md);
- if (!r && !dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr))
- param->flags |= DM_UEVENT_GENERATED_FLAG;
+ if (!r) {
+ dm_ima_measure_on_device_resume(md, new_map ? true : false);
+
+ if (!dm_kobject_uevent(md, KOBJ_CHANGE, param->event_nr))
+ param->flags |= DM_UEVENT_GENERATED_FLAG;
+ }
}
/*
A given block device can load a table multiple times, with different input parameters, before eventually resuming it. Further, a device may be suspended and then resumed. The device may never resume after a table-load. Because of the above valid scenarios for a given device, it is important to measure and log the device resume event using IMA. Also, if the table is large, measuring it in clear-text each time the device changes state, will unnecessarily increase the size of IMA log. Since the table clear-text is already measured during table-load event, measuring the hash during resume should be sufficient to validate the table contents. Measure the device parameters, and hash of the active table, when the device is resumed. Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> --- drivers/md/dm-ima.c | 47 +++++++++++++++++++++++++++++++++++++++++++ drivers/md/dm-ima.h | 1 + drivers/md/dm-ioctl.c | 8 ++++++-- 3 files changed, 54 insertions(+), 2 deletions(-)