diff mbox series

[RFC,4/7] dm: measure data on table clear

Message ID 20210526005954.31564-5-tusharsu@linux.microsoft.com (mailing list archive)
State Changes Requested, archived
Delegated to: Mike Snitzer
Headers show
Series device mapper target measurements using IMA | expand

Commit Message

Tushar Sugandhi May 26, 2021, 12:59 a.m. UTC
For a given block device, an inactive table slot contains the parameters
to configure the device with.  The inactive table can be cleared
multiple times, accidentally or maliciously, which may impact the
functionality of the device, and compromise the system.  Therefore it is
important to measure and log the event when a table is cleared.

Measure device parameters, and table hashes when the inactive table slot
is cleared.

Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
---
 drivers/md/dm-ima.c   | 50 +++++++++++++++++++++++++++++++++++++++++++
 drivers/md/dm-ima.h   |  2 ++
 drivers/md/dm-ioctl.c |  3 +++
 3 files changed, 55 insertions(+)
diff mbox series

Patch

diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index a93387beda9e..6670b5f74004 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -312,10 +312,60 @@  void dm_ima_measure_on_device_remove(struct mapped_device *md)
 	kfree(md->ima.device_data);
 }
 
+/*
+ * measure ima data on table clear
+ */
+void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map)
+{
+	unsigned int noio_flag, l;
+	char *device_table_data;
+	char inactive[] = "inactive_table_hash=";
+	unsigned int inactive_len = strlen(inactive);
+
+	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)
+		goto bad;
+
+	l = strlen(md->ima.device_data);
+	memcpy(device_table_data, md->ima.device_data, l);
+	memcpy(device_table_data + l, inactive, inactive_len);
+	l += inactive_len;
+
+	memcpy(device_table_data + l, md->ima.inactive_table_hash,
+	       md->ima.inactive_table_hash_len);
+
+	l += md->ima.inactive_table_hash_len;
+
+	memcpy(device_table_data + l, ";", 1);
+	l++;
+
+	dm_ima_measure_data("table_clear", device_table_data, l);
+
+	if (new_map) {
+		kfree(md->ima.inactive_table_hash);
+		md->ima.inactive_table_hash = NULL;
+		md->ima.inactive_table_hash_len = 0;
+
+		if (md->ima.active_table_hash) {
+			md->ima.inactive_table_hash = md->ima.active_table_hash;
+			md->ima.inactive_table_hash_len = md->ima.active_table_hash_len;
+		}
+
+	}
+
+	kfree(device_table_data);
+bad:
+	return;
+}
+
 #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) {}
 void dm_ima_measure_on_device_remove(struct mapped_device *md) {}
+void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map) {}
 #endif
 MODULE_AUTHOR("Tushar Sugandhi <tusharsu@linux.microsoft.com>");
 MODULE_DESCRIPTION("Enables IMA measurements for DM targets");
diff --git a/drivers/md/dm-ima.h b/drivers/md/dm-ima.h
index 974b14361958..ed633e031a18 100644
--- a/drivers/md/dm-ima.h
+++ b/drivers/md/dm-ima.h
@@ -35,4 +35,6 @@  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);
 void dm_ima_measure_on_device_remove(struct mapped_device *md);
+void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map);
+
 #endif /*DM_IMA_H*/
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index cb6392c156c2..b4f47d596985 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1509,6 +1509,7 @@  static int table_clear(struct file *filp, struct dm_ioctl *param, size_t param_s
 	struct hash_cell *hc;
 	struct mapped_device *md;
 	struct dm_table *old_map = NULL;
+	bool has_new_map = false;
 
 	down_write(&_hash_lock);
 
@@ -1522,6 +1523,7 @@  static int table_clear(struct file *filp, struct dm_ioctl *param, size_t param_s
 	if (hc->new_map) {
 		old_map = hc->new_map;
 		hc->new_map = NULL;
+		has_new_map = true;
 	}
 
 	param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
@@ -1533,6 +1535,7 @@  static int table_clear(struct file *filp, struct dm_ioctl *param, size_t param_s
 		dm_sync_table(md);
 		dm_table_destroy(old_map);
 	}
+	dm_ima_measure_on_table_clear(md, has_new_map);
 	dm_put(md);
 
 	return 0;