All of lore.kernel.org
 help / color / mirror / Atom feed
* [dm-devel] [RFC 0/7] device mapper target measurements using IMA
@ 2021-05-26  0:59 Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 1/7] dm: measure data on table load Tushar Sugandhi
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Tushar Sugandhi @ 2021-05-26  0:59 UTC (permalink / raw)
  To: dm-devel; +Cc: tusharsu, nramas, zohar, snitzer, agk

Hello all,
I have been working on measuring various device mapper target attributes
using IMA kernel subsystem. 
(more context in the patch series cover-letter below)

I still have to work on:
 - filling the gaps in the documentation, 
 - testing some corner cases etc.

But I would like to get an early feedback from the device-mapper
community on the code and therefore sharing the series as an RFC for
the time being.

Thanks,
Tushar

----------------
--Cover Letter--
----------------
For a given system, various external services/infrastructure tools
(including the attestation service) interact with it - both during the
setup and during rest of the system run-time.  They share sensitive data
and/or execute critical workload on that system.  The external services
may want to verify the current run-time state of the relevant kernel
subsystems before fully trusting the system with business-critical
data/workload.

Device mapper is one such kernel subsystem that plays a critical role on
a given system by providing various important functionalities to the
block devices using various target types like crypt, verity, integrity 
etc.  Each of these target types’ functionalities can be configured with
various attributes.  The attributes chosen to configure these target types
can significantly impact the security profile of the block device,
and in-turn, of the system itself.  For instance, the type of encryption
algorithm and the key size determines the strength of encryption for a
given block device.

Therefore, verifying the current state of various block devices as well
as their various target attributes is crucial for external services
before fully trusting the system with business-critical data/workload.

IMA provides the necessary functionality for device mapper to measure the
state and configuration of various block devices -
  - BY device mapper itself, from within the kernel,
  - in a tamper resistant way,
  - and re-measured - triggered on state/configuration change.

This patch series uses this IMA functionality, by calling the function
ima_measure_critical_data(), when a block device state is changed (e.g.
on device create, resume, rename, remove etc.)  It measures the device
state and configuration and stores it in IMA logs, so that it can be
used by external services for managing the system.

Tushar Sugandhi (7):
  dm: measure data on table load
  dm: measure data on device resume
  dm: measure data on device remove
  dm: measure data on table clear
  dm: measure data on device rename
  dm: update target specific status functions to measure data
  dm: add documentation for IMA measurement support

 .../admin-guide/device-mapper/dm-ima.rst      | 271 +++++++++++
 .../admin-guide/device-mapper/index.rst       |   1 +
 drivers/md/Makefile                           |   2 +
 drivers/md/dm-cache-target.c                  |  30 ++
 drivers/md/dm-clone-target.c                  |   7 +
 drivers/md/dm-core.h                          |   5 +
 drivers/md/dm-crypt.c                         |  50 ++
 drivers/md/dm-delay.c                         |   4 +
 drivers/md/dm-dust.c                          |   4 +
 drivers/md/dm-ebs-target.c                    |   3 +
 drivers/md/dm-era-target.c                    |   4 +
 drivers/md/dm-flakey.c                        |   4 +
 drivers/md/dm-ima.c                           | 442 ++++++++++++++++++
 drivers/md/dm-ima.h                           |  41 ++
 drivers/md/dm-integrity.c                     |  38 ++
 drivers/md/dm-ioctl.c                         |  23 +-
 drivers/md/dm-linear.c                        |   8 +
 drivers/md/dm-log-userspace-base.c            |   3 +
 drivers/md/dm-log-writes.c                    |   4 +
 drivers/md/dm-log.c                           |  10 +
 drivers/md/dm-mpath.c                         |  29 ++
 drivers/md/dm-ps-historical-service-time.c    |   3 +
 drivers/md/dm-ps-io-affinity.c                |   3 +
 drivers/md/dm-ps-queue-length.c               |   3 +
 drivers/md/dm-ps-round-robin.c                |   4 +
 drivers/md/dm-ps-service-time.c               |   3 +
 drivers/md/dm-raid.c                          |  42 ++
 drivers/md/dm-raid1.c                         |  18 +
 drivers/md/dm-snap-persistent.c               |   4 +
 drivers/md/dm-snap-transient.c                |   4 +
 drivers/md/dm-snap.c                          |  16 +
 drivers/md/dm-stripe.c                        |  15 +
 drivers/md/dm-switch.c                        |   4 +
 drivers/md/dm-thin.c                          |   8 +
 drivers/md/dm-unstripe.c                      |   4 +
 drivers/md/dm-verity-target.c                 |  46 ++
 drivers/md/dm-writecache.c                    |   3 +
 drivers/md/dm-zoned-target.c                  |   3 +
 include/linux/device-mapper.h                 |   6 +-
 include/uapi/linux/dm-ioctl.h                 |   6 +
 40 files changed, 1175 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/admin-guide/device-mapper/dm-ima.rst
 create mode 100644 drivers/md/dm-ima.c
 create mode 100644 drivers/md/dm-ima.h

-- 
2.17.1


--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [dm-devel] [RFC 1/7] dm: measure data on table load
  2021-05-26  0:59 [dm-devel] [RFC 0/7] device mapper target measurements using IMA Tushar Sugandhi
@ 2021-05-26  0:59 ` Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 2/7] dm: measure data on device resume Tushar Sugandhi
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Tushar Sugandhi @ 2021-05-26  0:59 UTC (permalink / raw)
  To: dm-devel; +Cc: tusharsu, nramas, zohar, snitzer, agk

DM configures a block device with various target specific attributes
passed to it as a table.  DM loads the table, and calls each target’s
respective constructors with the attributes as input parameters.
Some of these attributes are critical to ensure the device meets
certain security bar.  Thus, IMA should measure these attributes, to
ensure they are not tampered with, during the lifetime of the device.
So that external services can have high confidence in the configuration
of the block-devices on a given system.

Some devices may have large tables.  And a given device may change its
state (table-load, suspend, resume, rename, remove, table-clear etc.)
many times.  Measuring these attributes each time when the device 
changes its state will significantly increase the size of the IMA logs.
Further, once configured, these attributes are not expected to change
unless a new table is loaded, or a device is removed and recreated.
Therefore the clear text of the attributes should only be measured
during table load, and the hash of the active/inactive table should be
measured for the remaining device state changes.

Measure device parameters, as well as target specific attributes, during
table load, using IMA function ima_measure_critical_data().  Compute the
hash of the inactive table and store it for measurements during future
state change.  If a load is called multiple times, update the inactive
table hash with the hash of the latest populated table.  So that the
correct inactive table hash is measured when the device transitions to
different states like resume, remove, rename etc.

Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
---
 drivers/md/Makefile           |   2 +
 drivers/md/dm-core.h          |   5 +
 drivers/md/dm-ima.c           | 219 ++++++++++++++++++++++++++++++++++
 drivers/md/dm-ima.h           |  36 ++++++
 drivers/md/dm-ioctl.c         |   7 ++
 include/linux/device-mapper.h |   2 +-
 include/uapi/linux/dm-ioctl.h |   6 +
 7 files changed, 276 insertions(+), 1 deletion(-)
 create mode 100644 drivers/md/dm-ima.c
 create mode 100644 drivers/md/dm-ima.h

diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index ef7ddc27685c..af349b7cbf8b 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -92,6 +92,8 @@ ifeq ($(CONFIG_DM_UEVENT),y)
 dm-mod-objs			+= dm-uevent.o
 endif
 
+dm-mod-objs			+= dm-ima.o
+
 ifeq ($(CONFIG_DM_VERITY_FEC),y)
 dm-verity-objs			+= dm-verity-fec.o
 endif
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h
index 5953ff2bd260..f67f898803db 100644
--- a/drivers/md/dm-core.h
+++ b/drivers/md/dm-core.h
@@ -18,6 +18,7 @@
 #include <trace/events/block.h>
 
 #include "dm.h"
+#include "dm-ima.h"
 
 #define DM_RESERVED_MAX_IOS		1024
 
@@ -114,6 +115,10 @@ struct mapped_device {
 	bool init_tio_pdu:1;
 
 	struct srcu_struct io_barrier;
+
+#ifdef CONFIG_IMA
+	struct dm_ima_measurements ima;
+#endif
 };
 
 void disable_discard(struct mapped_device *md);
diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
new file mode 100644
index 000000000000..8903e746ead6
--- /dev/null
+++ b/drivers/md/dm-ima.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Microsoft Corporation
+ *
+ * Author: Tushar Sugandhi <tusharsu@linux.microsoft.com>
+ *
+ * File: dm-ima.c
+ *       Enables IMA measurements for DM targets
+ */
+
+#include "dm-core.h"
+#include "dm-ima.h"
+
+#include <linux/ima.h>
+#include <linux/device-mapper.h>
+#include <crypto/hash.h>
+#include <linux/crypto.h>
+#include <crypto/hash_info.h>
+
+#define DM_MSG_PREFIX "dm-ima"
+
+#ifdef CONFIG_IMA
+/*
+ * Internal function to prefix separator characters in input buffer with escape
+ * character, so that they don't interfere with the construction of key-value pairs,
+ * and clients can split the key1=value1;key2=value2; pairs properly.
+ */
+void fix_separator_chars(char **buf)
+{
+	int l = strlen(*buf);
+	int i, j, sp = 0;
+
+	for (i = 0; i < l; i++)
+		if ((*buf)[i] == '\\' || (*buf)[i] == ';' || (*buf)[i] == '=')
+			sp++;
+
+	if (sp == 0)
+		return;
+
+	for (i = l-1, j = i+sp; i >= 0; i--) {
+		(*buf)[j--] = (*buf)[i];
+		if ((*buf)[i] == '\\' || (*buf)[i] == ';' || (*buf)[i] == '=')
+			(*buf)[j--] = '\\';
+	}
+}
+
+/*
+ * Internal wrapper function to call IMA to measure DM data.
+ */
+void dm_ima_measure_data(const char *event_name, const void *buf, size_t buf_len)
+{
+	unsigned int noio_flag;
+
+	noio_flag = memalloc_noio_save();
+	ima_measure_critical_data(DM_NAME, event_name, buf, buf_len, false);
+	memalloc_noio_restore(noio_flag);
+}
+
+/*
+ * Build up the IMA data for each target, and finally measure.
+ */
+void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags)
+{
+	char *ima_buf_head = NULL, *ima_buf_cur = NULL, *device_data = NULL, *digest_buf = NULL;
+	size_t total_buf_len = DM_IMA_DEVICE_BUF_LEN + DM_IMA_TABLE_BUF_LEN;
+	unsigned int num_targets, device_data_len, i;
+	int desc_size, digest_size, last_i = -1, r;
+	char *dev_name = NULL, *dev_uuid = NULL;
+	status_type_t type = STATUSTYPE_IMA;
+	struct shash_desc *desc = NULL;
+	struct crypto_shash *tfm;
+	long ima_remaining;
+	sector_t capacity;
+	u8 *digest = NULL;
+
+	dev_name = kzalloc(DM_NAME_LEN*2, GFP_KERNEL);
+	if (!dev_name)
+		goto error;
+
+	dev_uuid = kzalloc(DM_UUID_LEN*2, GFP_KERNEL);
+	if (!dev_uuid)
+		goto error;
+
+	if (dm_copy_name_and_uuid(table->md, dev_name, dev_uuid))
+		goto error;
+
+	fix_separator_chars(&dev_name);
+	fix_separator_chars(&dev_uuid);
+
+	ima_buf_head = ima_buf_cur = kzalloc(total_buf_len, GFP_KERNEL);
+	if (!ima_buf_head)
+		goto error;
+
+	device_data = kzalloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL);
+	if (!device_data)
+		goto error;
+
+	tfm = crypto_alloc_shash("sha256", 0, 0);
+	if (IS_ERR(tfm))
+		goto error;
+
+	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+	digest_size = crypto_shash_digestsize(tfm);
+
+	digest = kzalloc(digest_size, GFP_KERNEL);
+	if (!digest)
+		goto error;
+
+	desc = kzalloc(desc_size, GFP_KERNEL);
+	if (!desc)
+		goto error;
+
+	desc->tfm = tfm;
+
+	num_targets = dm_table_get_num_targets(table);
+	capacity = get_capacity(table->md->disk);
+
+	scnprintf(device_data, DM_IMA_DEVICE_BUF_LEN,
+		  "name=%s;uuid=%s;capacity=%llu;major=%d;minor=%d;minor_count=%d;num_targets=%u;",
+		  dev_name, dev_uuid, capacity, table->md->disk->major,
+		  table->md->disk->first_minor, table->md->disk->minors, num_targets);
+
+	device_data_len = strlen(device_data);
+	memcpy(ima_buf_cur, device_data, device_data_len);
+	ima_buf_cur += device_data_len;
+
+	for (i = 0; i < num_targets; i++) {
+		struct dm_target *ti = dm_table_get_target(table, i);
+		size_t l = 0;
+
+		ima_remaining = total_buf_len - (ima_buf_cur - ima_buf_head);
+
+		if (ti->type->status)
+			ti->type->status(ti, type, status_flags, ima_buf_cur, ima_remaining);
+		else
+			ima_buf_cur[0] = '\0';
+
+		l = strlen(ima_buf_cur);
+
+		ima_remaining -= (l+1);
+
+		if (ima_remaining > 0) {
+			ima_buf_cur += l;
+			last_i = -1;
+			continue;
+		}
+
+		if (unlikely(i == last_i)) {
+		/* IMA measurements for DM targets are best-effort.
+		 * If the IMA data from current target type is too large to fit
+		 * into total_buf_len, measure what we have in the current buffer, and bail-out.
+		 */
+			DMERR("IMA data for %s target too large.", ti->type->name);
+			break;
+		}
+		/* The buffer ima_buf_head is full if we reach here.
+		 * In this case, measure the current buffer, free it, and reallocate a new buffer,
+		 * and continue measuring the remaining targets in the table.
+		 */
+		ima_buf_cur[0] = '\0';
+		dm_ima_measure_data("table_load", ima_buf_head, strlen(ima_buf_head));
+		crypto_shash_update(desc, (const u8 *)ima_buf_head, strlen(ima_buf_head));
+		kfree(ima_buf_head);
+		ima_buf_head = ima_buf_cur = kzalloc(total_buf_len, GFP_KERNEL);
+		if (!ima_buf_head)
+			goto error;
+		/*
+		 * Each new "table_load" entry in IMA log should have device data prefix,
+		 * so that multiple records from the same table load can be linked together.
+		 */
+		memcpy(ima_buf_cur, device_data, device_data_len);
+		ima_buf_cur += device_data_len;
+
+		last_i = i;
+		i--;
+	}
+
+	dm_ima_measure_data("table_load", ima_buf_head, strlen(ima_buf_head));
+
+	kfree(table->md->ima.inactive_table_hash);
+	table->md->ima.inactive_table_hash = NULL;
+	table->md->ima.inactive_table_hash_len = 0;
+
+	r = crypto_shash_update(desc, (const u8 *)ima_buf_head, strlen(ima_buf_head));
+	if (r < 0)
+		goto error;
+
+	r = crypto_shash_final(desc, digest);
+	if (r < 0)
+		goto error;
+
+	digest_buf = kzalloc((digest_size*2)+1, GFP_KERNEL);
+	if (!digest_buf)
+		goto error;
+
+	for (i = 0; i < digest_size; i++)
+		snprintf((digest_buf+(i*2)), 3, "%02x", digest[i]);
+
+	table->md->ima.inactive_table_hash = digest_buf;
+	table->md->ima.inactive_table_hash_len = strlen(digest_buf);
+	table->md->ima.device_data = device_data;
+	table->md->ima.device_data_len = device_data_len;
+	table->md->ima.num_targets = num_targets;
+
+error:
+	kfree(dev_name);
+	kfree(dev_uuid);
+	kfree(digest);
+	kfree(desc);
+	crypto_free_shash(tfm);
+	kfree(ima_buf_head);
+}
+
+#else
+void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags) {}
+#endif
+MODULE_AUTHOR("Tushar Sugandhi <tusharsu@linux.microsoft.com>");
+MODULE_DESCRIPTION("Enables IMA measurements for DM targets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-ima.h b/drivers/md/dm-ima.h
new file mode 100644
index 000000000000..a71e0682fcb9
--- /dev/null
+++ b/drivers/md/dm-ima.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2021 Microsoft Corporation
+ *
+ * Author: Tushar Sugandhi <tusharsu@linux.microsoft.com>
+ *
+ * File: dm-ima.h
+ *       Header file for device mapper IMA measurements.
+ */
+
+#ifndef DM_IMA_H
+#define DM_IMA_H
+
+#define DM_IMA_TABLE_BUF_LEN 4096
+#define DM_IMA_DEVICE_BUF_LEN 1024
+
+struct dm_ima_measurements {
+	/* Contains data specific to the device which is common across
+	 * all the targets in the table.e.g. name, uuid, major, minor, capacity etc.
+	 * The values are stored in semicolon separated key=value; pairs.
+	 */
+	char *device_data;
+	unsigned int device_data_len;
+	unsigned int num_targets;
+
+	/* Contains the sha256 hashs of the IMA measurements of the
+	 * target attributes key-value pairs from the active/inactive tables.
+	 */
+	char *active_table_hash;
+	unsigned int active_table_hash_len;
+	char *inactive_table_hash;
+	unsigned int inactive_table_hash_len;
+};
+
+void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_flags);
+#endif /*DM_IMA_H*/
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 2209cbcd84db..21deff8513a7 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -21,6 +21,9 @@
 
 #include <linux/uaccess.h>
 
+#include <linux/ima.h>
+#include "dm-ima.h"
+
 #define DM_MSG_PREFIX "ioctl"
 #define DM_DRIVER_EMAIL "dm-devel@redhat.com"
 
@@ -1224,6 +1227,8 @@ static void retrieve_status(struct dm_table *table,
 
 	if (param->flags & DM_STATUS_TABLE_FLAG)
 		type = STATUSTYPE_TABLE;
+	else if (param->flags & DM_IMA_MEASUREMENT_FLAG)
+		type = STATUSTYPE_IMA;
 	else
 		type = STATUSTYPE_INFO;
 
@@ -1391,6 +1396,8 @@ static int populate_table(struct dm_table *table,
 		next = spec->next;
 	}
 
+	dm_ima_measure_on_table_load(table, STATUSTYPE_IMA);
+
 	return dm_table_complete(table);
 }
 
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index ff700fb6ce1d..738a7d023650 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -31,7 +31,7 @@ enum dm_queue_mode {
 	DM_TYPE_DAX_BIO_BASED	 = 3,
 };
 
-typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t;
+typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE, STATUSTYPE_IMA } status_type_t;
 
 union map_info {
 	void *ptr;
diff --git a/include/uapi/linux/dm-ioctl.h b/include/uapi/linux/dm-ioctl.h
index e5c6e458bdf7..c12ce30b52df 100644
--- a/include/uapi/linux/dm-ioctl.h
+++ b/include/uapi/linux/dm-ioctl.h
@@ -376,4 +376,10 @@ enum {
  */
 #define DM_INTERNAL_SUSPEND_FLAG	(1 << 18) /* Out */
 
+/*
+ * If set, returns in the in buffer passed by UM, the raw table information
+ * that would be measured by IMA subsystem on device state change.
+ */
+#define DM_IMA_MEASUREMENT_FLAG	(1 << 19) /* In */
+
 #endif				/* _LINUX_DM_IOCTL_H */
-- 
2.17.1


--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [dm-devel] [RFC 2/7] dm: measure data on device resume
  2021-05-26  0:59 [dm-devel] [RFC 0/7] device mapper target measurements using IMA Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 1/7] dm: measure data on table load Tushar Sugandhi
@ 2021-05-26  0:59 ` Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 3/7] dm: measure data on device remove Tushar Sugandhi
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Tushar Sugandhi @ 2021-05-26  0:59 UTC (permalink / raw)
  To: dm-devel; +Cc: tusharsu, nramas, zohar, snitzer, agk

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(-)

diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index 8903e746ead6..b244a7fd58fe 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -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");
diff --git a/drivers/md/dm-ima.h b/drivers/md/dm-ima.h
index a71e0682fcb9..1cd0c76e0379 100644
--- a/drivers/md/dm-ima.h
+++ b/drivers/md/dm-ima.h
@@ -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*/
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 21deff8513a7..e06e256d1a7e 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -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;
+		}
 	}
 
 	/*
-- 
2.17.1

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [dm-devel] [RFC 3/7] dm: measure data on device remove
  2021-05-26  0:59 [dm-devel] [RFC 0/7] device mapper target measurements using IMA Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 1/7] dm: measure data on table load Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 2/7] dm: measure data on device resume Tushar Sugandhi
@ 2021-05-26  0:59 ` Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 4/7] dm: measure data on table clear Tushar Sugandhi
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Tushar Sugandhi @ 2021-05-26  0:59 UTC (permalink / raw)
  To: dm-devel; +Cc: tusharsu, nramas, zohar, snitzer, agk

Presence of an active block-device, configured with expected parameters,
is important for an external attestation service to determine if a system
meets the attestation requirements.  Therefore it is important for DM to
measure the device remove events.

Measure device parameters, and table hashes when the device is removed.

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

diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index b244a7fd58fe..a93387beda9e 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -257,9 +257,65 @@ void dm_ima_measure_on_device_resume(struct mapped_device *md, bool swap)
 	kfree(device_table_data);
 }
 
+/*
+ * Measure IMA data on remove
+ */
+void dm_ima_measure_on_device_remove(struct mapped_device *md)
+{
+	unsigned int noio_flag, l;
+	char *dev_table_data;
+	char active[] = "active_table_hash=";
+	char inactive[] = "inactive_table_hash=";
+	unsigned int active_len = strlen(active);
+	unsigned int inactive_len = strlen(inactive);
+
+	noio_flag = memalloc_noio_save();
+	dev_table_data = kzalloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL);
+	memalloc_noio_restore(noio_flag);
+
+	if (!dev_table_data)
+		goto bad;
+	l = strlen(md->ima.device_data);
+	memcpy(dev_table_data, md->ima.device_data, l);
+
+	if (md->ima.active_table_hash) {
+		memcpy(dev_table_data + l, active, active_len);
+		l += active_len;
+
+		memcpy(dev_table_data + l,
+		md->ima.active_table_hash,
+		md->ima.active_table_hash_len);
+		l += md->ima.active_table_hash_len;
+
+		memcpy(dev_table_data + l, ";", 1);
+		l++;
+	}
+
+	if (md->ima.inactive_table_hash) {
+		memcpy(dev_table_data + l, inactive, inactive_len);
+		l += inactive_len;
+
+		memcpy(dev_table_data + l,
+		md->ima.inactive_table_hash,
+		md->ima.inactive_table_hash_len);
+
+		l += md->ima.inactive_table_hash_len;
+
+		memcpy(dev_table_data + l, ";", 1);
+		l++;
+	}
+
+	dm_ima_measure_data("device_remove", dev_table_data, l);
+
+	kfree(dev_table_data);
+bad:
+	kfree(md->ima.device_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) {}
+void dm_ima_measure_on_device_remove(struct mapped_device *md) {}
 #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 1cd0c76e0379..974b14361958 100644
--- a/drivers/md/dm-ima.h
+++ b/drivers/md/dm-ima.h
@@ -34,4 +34,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);
+void dm_ima_measure_on_device_remove(struct mapped_device *md);
 #endif /*DM_IMA_H*/
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index e06e256d1a7e..cb6392c156c2 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -984,6 +984,8 @@ static int dev_remove(struct file *filp, struct dm_ioctl *param, size_t param_si
 
 	param->flags &= ~DM_DEFERRED_REMOVE;
 
+	dm_ima_measure_on_device_remove(md);
+
 	if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
 		param->flags |= DM_UEVENT_GENERATED_FLAG;
 
-- 
2.17.1

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [dm-devel] [RFC 4/7] dm: measure data on table clear
  2021-05-26  0:59 [dm-devel] [RFC 0/7] device mapper target measurements using IMA Tushar Sugandhi
                   ` (2 preceding siblings ...)
  2021-05-26  0:59 ` [dm-devel] [RFC 3/7] dm: measure data on device remove Tushar Sugandhi
@ 2021-05-26  0:59 ` Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 5/7] dm: measure data on device rename Tushar Sugandhi
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Tushar Sugandhi @ 2021-05-26  0:59 UTC (permalink / raw)
  To: dm-devel; +Cc: tusharsu, nramas, zohar, snitzer, agk

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 --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;
-- 
2.17.1

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [dm-devel] [RFC 5/7] dm: measure data on device rename
  2021-05-26  0:59 [dm-devel] [RFC 0/7] device mapper target measurements using IMA Tushar Sugandhi
                   ` (3 preceding siblings ...)
  2021-05-26  0:59 ` [dm-devel] [RFC 4/7] dm: measure data on table clear Tushar Sugandhi
@ 2021-05-26  0:59 ` Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 6/7] dm: update target specific status functions to measure data Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 7/7] dm: add documentation for IMA measurement support Tushar Sugandhi
  6 siblings, 0 replies; 8+ messages in thread
From: Tushar Sugandhi @ 2021-05-26  0:59 UTC (permalink / raw)
  To: dm-devel; +Cc: tusharsu, nramas, zohar, snitzer, agk

A given block device is identified by it's name and UUID.  However, both
these parameters can be renamed.  For an external attestation service to
correctly attest a given device, it needs to keep track of these rename
events.

Fix if there are any separator characters in the new name/UUID. Update 
the device data for IMA with the new values. Measure both old device
data and the new device name/UUID parameters in the same IMA measurement
event, so that the old and new values can be connected later.

Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
---
 drivers/md/dm-ima.c   | 70 +++++++++++++++++++++++++++++++++++++++++++
 drivers/md/dm-ima.h   |  1 +
 drivers/md/dm-ioctl.c |  3 ++
 3 files changed, 74 insertions(+)

diff --git a/drivers/md/dm-ima.c b/drivers/md/dm-ima.c
index 6670b5f74004..511d471648a1 100644
--- a/drivers/md/dm-ima.c
+++ b/drivers/md/dm-ima.c
@@ -361,11 +361,81 @@ void dm_ima_measure_on_table_clear(struct mapped_device *md, bool new_map)
 	return;
 }
 
+/*
+ * Measure IMA data on device rename
+ */
+void dm_ima_measure_on_device_rename(struct mapped_device *md)
+{
+	char *old_device_data = NULL, *new_device_data = NULL, *combined_device_data = NULL;
+	char *new_dev_name = NULL, *new_dev_uuid = NULL;
+	unsigned int noio_flag;
+	sector_t capacity;
+
+	noio_flag = memalloc_noio_save();
+	new_device_data = kzalloc(DM_IMA_DEVICE_BUF_LEN, GFP_KERNEL);
+	memalloc_noio_restore(noio_flag);
+
+	if (!new_device_data)
+		return;
+
+	noio_flag = memalloc_noio_save();
+	new_dev_name = kzalloc(DM_NAME_LEN*2, GFP_KERNEL);
+	memalloc_noio_restore(noio_flag);
+	if (!new_dev_name)
+		goto error;
+
+	memalloc_noio_restore(noio_flag);
+	new_dev_uuid = kzalloc(DM_UUID_LEN*2, GFP_KERNEL);
+	memalloc_noio_restore(noio_flag);
+	if (!new_dev_uuid)
+		goto error;
+
+	if (dm_copy_name_and_uuid(md, new_dev_name, new_dev_uuid))
+		goto error;
+
+	fix_separator_chars(&new_dev_name);
+	fix_separator_chars(&new_dev_uuid);
+
+	noio_flag = memalloc_noio_save();
+	combined_device_data = kzalloc(DM_IMA_DEVICE_BUF_LEN * 2, GFP_KERNEL);
+	memalloc_noio_restore(noio_flag);
+
+	if (!combined_device_data)
+		goto error;
+
+	capacity = get_capacity(md->disk);
+
+	old_device_data = md->ima.device_data;
+
+	scnprintf(new_device_data, DM_IMA_DEVICE_BUF_LEN,
+		  "name=%s;uuid=%s;capacity=%llu;major=%d;minor=%d;minor_count=%d;num_targets=%u;",
+		  new_dev_name, new_dev_uuid, capacity, md->disk->major, md->disk->first_minor,
+		  md->disk->minors, md->ima.num_targets);
+	md->ima.device_data = new_device_data;
+	md->ima.device_data_len = strlen(new_device_data);
+
+	scnprintf(combined_device_data, DM_IMA_DEVICE_BUF_LEN * 2, "%snew_name=%s;new_uuid=%s;",
+		  old_device_data, new_dev_name, new_dev_uuid);
+
+	dm_ima_measure_data("device_rename", combined_device_data, strlen(combined_device_data));
+
+	goto exit;
+
+error:
+	kfree(new_device_data);
+exit:
+	kfree(combined_device_data);
+	kfree(old_device_data);
+	kfree(new_dev_name);
+	kfree(new_dev_uuid);
+}
+
 #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) {}
+void dm_ima_measure_on_device_rename(struct mapped_device *md) {}
 #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 ed633e031a18..340032f1d07f 100644
--- a/drivers/md/dm-ima.h
+++ b/drivers/md/dm-ima.h
@@ -36,5 +36,6 @@ void dm_ima_measure_on_table_load(struct dm_table *table, unsigned int status_fl
 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);
+void dm_ima_measure_on_device_rename(struct mapped_device *md);
 
 #endif /*DM_IMA_H*/
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index b4f47d596985..9d8258dd014e 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -486,6 +486,9 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
 		param->flags |= DM_UEVENT_GENERATED_FLAG;
 
 	md = hc->md;
+
+	dm_ima_measure_on_device_rename(md);
+
 	up_write(&_hash_lock);
 	kfree(old_name);
 
-- 
2.17.1

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [dm-devel] [RFC 6/7] dm: update target specific status functions to measure data
  2021-05-26  0:59 [dm-devel] [RFC 0/7] device mapper target measurements using IMA Tushar Sugandhi
                   ` (4 preceding siblings ...)
  2021-05-26  0:59 ` [dm-devel] [RFC 5/7] dm: measure data on device rename Tushar Sugandhi
@ 2021-05-26  0:59 ` Tushar Sugandhi
  2021-05-26  0:59 ` [dm-devel] [RFC 7/7] dm: add documentation for IMA measurement support Tushar Sugandhi
  6 siblings, 0 replies; 8+ messages in thread
From: Tushar Sugandhi @ 2021-05-26  0:59 UTC (permalink / raw)
  To: dm-devel; +Cc: tusharsu, nramas, zohar, snitzer, agk

For device mapper targets to take advantage of IMA's measurement
capabilities, the status functions for the individual targets need to be
updated to handle the status_type_t case for value STATUSTYPE_IMA.

Update status functions for the following target types, to log their
respective attributes to be measured using IMA.
 01. cache
 02. crypt
 03. integrity
 04. linear
 05. mirror
 06. multipath
 07. raid
 08. snapshot
 09. striped
 10. verity 

For rest of the targets, handle the STATUSTYPE_IMA case by setting the 
measurement buffer to NULL.

For IMA to measure the data on a given system, the IMA policy on the
system needs to be updated to have the following line, and the system 
needs to be restarted for the measurements to take effect.

/etc/ima/ima-policy
 measure func=CRITICAL_DATA label=device-mapper template=ima-buf

The measurements will be reflected in the IMA logs, which are located at:

/sys/kernel/security/integrity/ima/ascii_runtime_measurements
/sys/kernel/security/integrity/ima/binary_runtime_measurements

These IMA logs can later be consumed by various attestation clients
running on the system, and send them to external services for attesting
the system.

Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
---
 drivers/md/dm-cache-target.c               | 30 +++++++++++++
 drivers/md/dm-clone-target.c               |  7 +++
 drivers/md/dm-crypt.c                      | 50 ++++++++++++++++++++++
 drivers/md/dm-delay.c                      |  4 ++
 drivers/md/dm-dust.c                       |  4 ++
 drivers/md/dm-ebs-target.c                 |  3 ++
 drivers/md/dm-era-target.c                 |  4 ++
 drivers/md/dm-flakey.c                     |  4 ++
 drivers/md/dm-integrity.c                  | 38 ++++++++++++++++
 drivers/md/dm-linear.c                     |  8 ++++
 drivers/md/dm-log-userspace-base.c         |  3 ++
 drivers/md/dm-log-writes.c                 |  4 ++
 drivers/md/dm-log.c                        | 10 +++++
 drivers/md/dm-mpath.c                      | 29 +++++++++++++
 drivers/md/dm-ps-historical-service-time.c |  3 ++
 drivers/md/dm-ps-io-affinity.c             |  3 ++
 drivers/md/dm-ps-queue-length.c            |  3 ++
 drivers/md/dm-ps-round-robin.c             |  4 ++
 drivers/md/dm-ps-service-time.c            |  3 ++
 drivers/md/dm-raid.c                       | 42 ++++++++++++++++++
 drivers/md/dm-raid1.c                      | 18 ++++++++
 drivers/md/dm-snap-persistent.c            |  4 ++
 drivers/md/dm-snap-transient.c             |  4 ++
 drivers/md/dm-snap.c                       | 16 +++++++
 drivers/md/dm-stripe.c                     | 15 +++++++
 drivers/md/dm-switch.c                     |  4 ++
 drivers/md/dm-thin.c                       |  8 ++++
 drivers/md/dm-unstripe.c                   |  4 ++
 drivers/md/dm-verity-target.c              | 46 ++++++++++++++++++++
 drivers/md/dm-writecache.c                 |  3 ++
 drivers/md/dm-zoned-target.c               |  3 ++
 include/linux/device-mapper.h              |  4 ++
 32 files changed, 385 insertions(+)

diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 6ab01ff25747..7cb089fd416e 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -3192,6 +3192,36 @@ static void cache_status(struct dm_target *ti, status_type_t type,
 			DMEMIT(" %s", cache->ctr_args[i]);
 		if (cache->nr_ctr_args)
 			DMEMIT(" %s", cache->ctr_args[cache->nr_ctr_args - 1]);
+		break;
+
+	case STATUSTYPE_IMA:
+		DMEMIT_NAME_VERSION(ti->type);
+
+		if (get_cache_mode(cache) == CM_FAIL)
+			DMEMIT("metadata_mode=fail;");
+		else if (get_cache_mode(cache) == CM_READ_ONLY)
+			DMEMIT("metadata_mode=ro;");
+		else
+			DMEMIT("metadata_mode=rw;");
+
+		format_dev_t(buf, cache->metadata_dev->bdev->bd_dev);
+		DMEMIT("cache_metadata_device=%s;", buf);
+		format_dev_t(buf, cache->cache_dev->bdev->bd_dev);
+		DMEMIT("cache_device=%s;", buf);
+		format_dev_t(buf, cache->origin_dev->bdev->bd_dev);
+		DMEMIT("cache_origin_device=%s;", buf);
+
+		for (i = 0; i < cache->nr_ctr_args - 1; i++) {
+			if (!strcmp(cache->ctr_args[i], "writethrough"))
+				DMEMIT("writethrough=y;");
+			else if (!strcmp(cache->ctr_args[i], "passthrough"))
+				DMEMIT("passthrough=y;");
+			else if (!strcmp(cache->ctr_args[i], "metadata2"))
+				DMEMIT("metadata2=y;");
+			else if (!strcmp(cache->ctr_args[i], "no_discard_passdown"))
+				DMEMIT("no_discard_passdown=y;");
+		}
+		break;
 	}
 
 	return;
diff --git a/drivers/md/dm-clone-target.c b/drivers/md/dm-clone-target.c
index a90bdf9b2ca6..e5dc68f18ee6 100644
--- a/drivers/md/dm-clone-target.c
+++ b/drivers/md/dm-clone-target.c
@@ -1499,6 +1499,13 @@ static void clone_status(struct dm_target *ti, status_type_t type,
 
 		for (i = 0; i < clone->nr_ctr_args; i++)
 			DMEMIT(" %s", clone->ctr_args[i]);
+
+		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+
+		break;
 	}
 
 	return;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index b0ab080f2567..5d179c57a55a 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -3473,6 +3473,56 @@ static void crypt_status(struct dm_target *ti, status_type_t type,
 				DMEMIT(" iv_large_sectors");
 		}
 
+		break;
+
+	case STATUSTYPE_IMA:
+		DMEMIT_NAME_VERSION(ti->type);
+
+		if (ti->num_discard_bios)
+			DMEMIT("allow_discards=y;");
+		else
+			DMEMIT("allow_discards=n;");
+
+		if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
+			DMEMIT("same_cpu=y;");
+		else
+			DMEMIT("same_cpu=n;");
+
+		if (test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags))
+			DMEMIT("submit_from_crypt_cpus=y;");
+		else
+			DMEMIT("submit_from_crypt_cpus=n;");
+
+		if (test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags))
+			DMEMIT("no_read_workqueue=y;");
+		else
+			DMEMIT("no_read_workqueue=n;");
+
+		if (test_bit(DM_CRYPT_NO_WRITE_WORKQUEUE, &cc->flags))
+			DMEMIT("no_write_workqueue=y;");
+		else
+			DMEMIT("no_write_workqueue=n;");
+
+		if (cc->on_disk_tag_size)
+			DMEMIT("integrity_tag_size=%u;cipher_auth=%s;",
+				cc->on_disk_tag_size, cc->cipher_auth);
+
+		if (cc->sector_size != (1 << SECTOR_SHIFT))
+			DMEMIT("sector_size=%d;", cc->sector_size);
+
+		if (test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags))
+			DMEMIT("iv_large_sectors=y;");
+		else
+			DMEMIT("iv_large_sectors=y;");
+
+		if (cc->cipher_string)
+			DMEMIT("cipher_string=%s;", cc->cipher_string);
+
+		DMEMIT("key_size=%u;", cc->key_size);
+		DMEMIT("key_parts=%u;", cc->key_parts);
+		DMEMIT("key_extra_size=%u;", cc->key_extra_size);
+		DMEMIT("key_mac_size=%u;", cc->key_mac_size);
+
 		break;
 	}
 }
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index 2628a832787b..76c0bed73840 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -326,6 +326,10 @@ static void delay_status(struct dm_target *ti, status_type_t type,
 			DMEMIT_DELAY_CLASS(&dc->flush);
 		}
 		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-dust.c b/drivers/md/dm-dust.c
index cbe1058ee589..5e455da70678 100644
--- a/drivers/md/dm-dust.c
+++ b/drivers/md/dm-dust.c
@@ -527,6 +527,10 @@ static void dust_status(struct dm_target *ti, status_type_t type,
 		DMEMIT("%s %llu %u", dd->dev->name,
 		       (unsigned long long)dd->start, dd->blksz);
 		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-ebs-target.c b/drivers/md/dm-ebs-target.c
index 71475a2410be..6b42bdaf0ce2 100644
--- a/drivers/md/dm-ebs-target.c
+++ b/drivers/md/dm-ebs-target.c
@@ -401,6 +401,9 @@ static void ebs_status(struct dm_target *ti, status_type_t type,
 		snprintf(result, maxlen, ec->u_bs_set ? "%s %llu %u %u" : "%s %llu %u",
 			 ec->dev->name, (unsigned long long) ec->start, ec->e_bs, ec->u_bs);
 		break;
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c
index d9ac7372108c..9d2d072729c0 100644
--- a/drivers/md/dm-era-target.c
+++ b/drivers/md/dm-era-target.c
@@ -1640,6 +1640,10 @@ static void era_status(struct dm_target *ti, status_type_t type,
 		format_dev_t(buf, era->origin_dev->bdev->bd_dev);
 		DMEMIT("%s %u", buf, era->sectors_per_block);
 		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 
 	return;
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index b7fee9936f05..8720e1a4873b 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -440,6 +440,10 @@ static void flakey_status(struct dm_target *ti, status_type_t type,
 			       fc->corrupt_bio_value, fc->corrupt_bio_flags);
 
 		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-integrity.c b/drivers/md/dm-integrity.c
index 781942aeddd1..df234575dda4 100644
--- a/drivers/md/dm-integrity.c
+++ b/drivers/md/dm-integrity.c
@@ -3310,6 +3310,44 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
 		EMIT_ALG(journal_mac_alg, "journal_mac");
 		break;
 	}
+	case STATUSTYPE_IMA:
+		DMEMIT_NAME_VERSION(ti->type);
+		DMEMIT("dev_name=%s;start=%llu;tag_size=%u;mode=%c;",
+			ic->dev->name, ic->start, ic->tag_size, ic->mode);
+
+		if (ic->meta_dev)
+			DMEMIT("meta_device=%s;", ic->meta_dev->name);
+		if (ic->sectors_per_block != 1)
+			DMEMIT("block_size=%u;", ic->sectors_per_block << SECTOR_SHIFT);
+		if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))
+			DMEMIT("recalculate=y;");
+		else
+			DMEMIT("recalculate=n;");
+
+		if (ic->discard)
+			DMEMIT("allow_discards=y;");
+		else
+			DMEMIT("allow_discards=n;");
+
+		DMEMIT("journal_sectors=%u;", ic->initial_sectors - SB_SECTORS);
+		DMEMIT("interleave_sectors=%u;", 1U << ic->sb->log2_interleave_sectors);
+		DMEMIT("buffer_sectors=%u;", 1U << ic->log2_buffer_sectors);
+		DMEMIT("mode=%c;", ic->mode);
+		if ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_PADDING)) != 0)
+			DMEMIT("fix_padding=y;");
+		else
+			DMEMIT("fix_padding=n;");
+
+		if ((ic->sb->flags & cpu_to_le32(SB_FLAG_FIXED_HMAC)) != 0)
+			DMEMIT("fix_hmac=y;");
+		else
+			DMEMIT("fix_hmac=n;");
+
+		if (ic->legacy_recalculate)
+			DMEMIT("legacy_recalculate=y;");
+		else
+			DMEMIT("legacy_recalculate=n;");
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 92db0f5e7f28..42acf4ed3b39 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -106,6 +106,7 @@ static void linear_status(struct dm_target *ti, status_type_t type,
 			  unsigned status_flags, char *result, unsigned maxlen)
 {
 	struct linear_c *lc = (struct linear_c *) ti->private;
+	size_t sz = 0;
 
 	switch (type) {
 	case STATUSTYPE_INFO:
@@ -116,6 +117,13 @@ static void linear_status(struct dm_target *ti, status_type_t type,
 		snprintf(result, maxlen, "%s %llu", lc->dev->name,
 				(unsigned long long)lc->start);
 		break;
+
+	case STATUSTYPE_IMA:
+		DMEMIT_NAME_VERSION(ti->type);
+
+		DMEMIT("device_name=%s;start=%llu;", lc->dev->name,
+		       (unsigned long long)lc->start);
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c
index 52090bee17c2..15cfe33ea68c 100644
--- a/drivers/md/dm-log-userspace-base.c
+++ b/drivers/md/dm-log-userspace-base.c
@@ -820,6 +820,9 @@ static int userspace_status(struct dm_dirty_log *log, status_type_t status_type,
 			DMEMIT("integrated_flush ");
 		DMEMIT("%s ", table_args);
 		break;
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 	return (r) ? 0 : (int)sz;
 }
diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c
index 57882654ffee..f3a6a0d3bf2d 100644
--- a/drivers/md/dm-log-writes.c
+++ b/drivers/md/dm-log-writes.c
@@ -834,6 +834,10 @@ static void log_writes_status(struct dm_target *ti, status_type_t type,
 	case STATUSTYPE_TABLE:
 		DMEMIT("%s %s", lc->dev->name, lc->logdev->name);
 		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 33e71ea6cc14..e0bcdf339df7 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -793,6 +793,11 @@ static int core_status(struct dm_dirty_log *log, status_type_t status,
 		DMEMIT("%s %u %u ", log->type->name,
 		       lc->sync == DEFAULTSYNC ? 1 : 2, lc->region_size);
 		DMEMIT_SYNC;
+		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 
 	return sz;
@@ -817,6 +822,11 @@ static int disk_status(struct dm_dirty_log *log, status_type_t status,
 		       lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name,
 		       lc->region_size);
 		DMEMIT_SYNC;
+		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 
 	return sz;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index bced42f082b0..4d9af76fb6e8 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1904,6 +1904,35 @@ static void multipath_status(struct dm_target *ti, status_type_t type,
 			}
 		}
 		break;
+
+	case STATUSTYPE_IMA:
+		DMEMIT_NAME_VERSION(ti->type);
+
+		list_for_each_entry(pg, &m->priority_groups, list) {
+			if (pg->bypassed)
+				state = 'D';	/* Disabled */
+			else if (pg == m->current_pg)
+				state = 'A';	/* Currently Active */
+			else
+				state = 'E';	/* Enabled */
+
+			DMEMIT("state=%c;", state);
+
+			list_for_each_entry(p, &pg->pgpaths, list) {
+				DMEMIT("path_name=%s;is_active=%s;fail_count=%u;",
+					p->path.dev->name,
+					p->is_active ? "A" : "F",
+					p->fail_count);
+				if (pg->ps.type->status) {
+					DMEMIT("path_selector_status=");
+					sz += pg->ps.type->status(&pg->ps,
+					      &p->path, type, result + sz,
+					      maxlen - sz);
+					DMEMIT(";");
+				}
+			}
+		}
+		break;
 	}
 
 	spin_unlock_irqrestore(&m->lock, flags);
diff --git a/drivers/md/dm-ps-historical-service-time.c b/drivers/md/dm-ps-historical-service-time.c
index 186f91e2752c..0ad613e12b22 100644
--- a/drivers/md/dm-ps-historical-service-time.c
+++ b/drivers/md/dm-ps-historical-service-time.c
@@ -255,6 +255,9 @@ static int hst_status(struct path_selector *ps, struct dm_path *path,
 		case STATUSTYPE_TABLE:
 			DMEMIT("0 ");
 			break;
+		case STATUSTYPE_IMA:
+			result[0] = '\0';
+			break;
 		}
 	}
 
diff --git a/drivers/md/dm-ps-io-affinity.c b/drivers/md/dm-ps-io-affinity.c
index 077655cd4fae..618179028c13 100644
--- a/drivers/md/dm-ps-io-affinity.c
+++ b/drivers/md/dm-ps-io-affinity.c
@@ -171,6 +171,9 @@ static int ioa_status(struct path_selector *ps, struct dm_path *path,
 		pi = path->pscontext;
 		DMEMIT("%*pb ", cpumask_pr_args(pi->cpumask));
 		break;
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 
 	return sz;
diff --git a/drivers/md/dm-ps-queue-length.c b/drivers/md/dm-ps-queue-length.c
index 5fd018d18418..5988f52b5a6e 100644
--- a/drivers/md/dm-ps-queue-length.c
+++ b/drivers/md/dm-ps-queue-length.c
@@ -102,6 +102,9 @@ static int ql_status(struct path_selector *ps, struct dm_path *path,
 		case STATUSTYPE_TABLE:
 			DMEMIT("%u ", pi->repeat_count);
 			break;
+		case STATUSTYPE_IMA:
+			result[0] = '\0';
+			break;
 		}
 	}
 
diff --git a/drivers/md/dm-ps-round-robin.c b/drivers/md/dm-ps-round-robin.c
index bdbb7e6e8212..8b47949454e9 100644
--- a/drivers/md/dm-ps-round-robin.c
+++ b/drivers/md/dm-ps-round-robin.c
@@ -100,6 +100,10 @@ static int rr_status(struct path_selector *ps, struct dm_path *path,
 			pi = path->pscontext;
 			DMEMIT("%u ", pi->repeat_count);
 			break;
+
+		case STATUSTYPE_IMA:
+			result[0] = '\0';
+			break;
 		}
 	}
 
diff --git a/drivers/md/dm-ps-service-time.c b/drivers/md/dm-ps-service-time.c
index 9cfda665e9eb..3ec9c33265c5 100644
--- a/drivers/md/dm-ps-service-time.c
+++ b/drivers/md/dm-ps-service-time.c
@@ -99,6 +99,9 @@ static int st_status(struct path_selector *ps, struct dm_path *path,
 			DMEMIT("%u %u ", pi->repeat_count,
 			       pi->relative_throughput);
 			break;
+		case STATUSTYPE_IMA:
+			result[0] = '\0';
+			break;
 		}
 	}
 
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index bf4a467fc73a..67d7f9e5b89b 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -3671,6 +3671,48 @@ static void raid_status(struct dm_target *ti, status_type_t type,
 		for (i = 0; i < rs->raid_disks; i++)
 			DMEMIT(" %s %s", __get_dev_name(rs->dev[i].meta_dev),
 					 __get_dev_name(rs->dev[i].data_dev));
+		break;
+
+	case STATUSTYPE_IMA:
+		/* *Should* always succeed */
+		rt = get_raid_type_by_ll(mddev->new_level, mddev->new_layout);
+		if (!rt)
+			return;
+
+		DMEMIT_NAME_VERSION(ti->type);
+
+		DMEMIT("raid_type=%s;raid_disks=%d;", rt->name, mddev->raid_disks);
+
+		/* Access most recent mddev properties for status output */
+		smp_rmb();
+		state = decipher_sync_action(mddev, recovery);
+		DMEMIT("raid_state=%s;", sync_str(state));
+
+		for (i = 0; i < rs->raid_disks; i++) {
+			DMEMIT("raid_device_%d_status=", i);
+			DMEMIT(__raid_dev_status(rs, &rs->dev[i].rdev));
+			DMEMIT(";");
+		}
+
+		if (rt_is_raid456(rt)) {
+			DMEMIT("journal_dev_mode=");
+			switch (rs->journal_dev.mode) {
+			case R5C_JOURNAL_MODE_WRITE_THROUGH:
+				DMEMIT("%s",
+				       _raid456_journal_mode[R5C_JOURNAL_MODE_WRITE_THROUGH].param);
+				break;
+			case R5C_JOURNAL_MODE_WRITE_BACK:
+				DMEMIT("%s",
+				       _raid456_journal_mode[R5C_JOURNAL_MODE_WRITE_BACK].param);
+				break;
+			default:
+				DMEMIT("invalid");
+				break;
+			}
+			DMEMIT(";");
+		}
+		break;
+
 	}
 }
 
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index b0a82f29a2e4..ecfc6d4c41e3 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1435,6 +1435,24 @@ static void mirror_status(struct dm_target *ti, status_type_t type,
 		}
 
 		break;
+
+	case STATUSTYPE_IMA:
+		DMEMIT_NAME_VERSION(ti->type);
+
+		DMEMIT("mirrors=%d;", ms->nr_mirrors);
+		for (m = 0; m < ms->nr_mirrors; m++) {
+			DMEMIT("mirror_device_%d=%s;", m, ms->mirror[m].dev->name);
+			DMEMIT("mirror_device_%d_status=%c;",
+			       m, device_status_char(&(ms->mirror[m])));
+		}
+
+		DMEMIT("%s", errors_handled(ms) ? "handle_errors=y;" : "handle_errors=n;");
+		DMEMIT("%s", keep_log(ms) ? "keep_log=y;" : "keep_log=n;");
+
+		DMEMIT("log_type_status=");
+		sz += log->type->status(log, type, result+sz, maxlen-sz);
+		DMEMIT(";");
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index 9ab4bf651ca9..ed7e903c5b44 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -908,6 +908,10 @@ static unsigned persistent_status(struct dm_exception_store *store,
 	case STATUSTYPE_TABLE:
 		DMEMIT(" %s %llu", store->userspace_supports_overflow ? "PO" : "P",
 		       (unsigned long long)store->chunk_size);
+		break;
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 
 	return sz;
diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c
index 4d50a12cf00c..f6d46610ae77 100644
--- a/drivers/md/dm-snap-transient.c
+++ b/drivers/md/dm-snap-transient.c
@@ -95,6 +95,10 @@ static unsigned transient_status(struct dm_exception_store *store,
 		break;
 	case STATUSTYPE_TABLE:
 		DMEMIT(" N %llu", (unsigned long long)store->chunk_size);
+		break;
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 
 	return sz;
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index a2acb014c13a..daebbc92016d 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -2389,6 +2389,19 @@ static void snapshot_status(struct dm_target *ti, status_type_t type,
 				DMEMIT(" discard_passdown_origin");
 		}
 		break;
+
+	case STATUSTYPE_IMA:
+		DMEMIT_NAME_VERSION(ti->type);
+
+		DMEMIT("snap_origin_name=%s;", snap->origin->name);
+		DMEMIT("snap_cow_name=%s;", snap->cow->name);
+		DMEMIT("%s", snap->valid ? "snap_valid=y;" : "snap_valid=n;");
+		DMEMIT("%s", snap->merge_failed ?
+		       "snap_merge_failed=y;" : "snap_merge_failed=n;");
+		DMEMIT("%s", snap->snapshot_overflowed ?
+		       "snapshot_overflowed=y;" : "snapshot_overflowed=n");
+		break;
+
 	}
 }
 
@@ -2733,6 +2746,9 @@ static void origin_status(struct dm_target *ti, status_type_t type,
 	case STATUSTYPE_TABLE:
 		snprintf(result, maxlen, "%s", o->dev->name);
 		break;
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index df359d33cda8..65352c6005f3 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -428,6 +428,21 @@ static void stripe_status(struct dm_target *ti, status_type_t type,
 			DMEMIT(" %s %llu", sc->stripe[i].dev->name,
 			    (unsigned long long)sc->stripe[i].physical_start);
 		break;
+
+	case STATUSTYPE_IMA:
+		DMEMIT_NAME_VERSION(ti->type);
+
+		DMEMIT("stripes=%d;chunk_size=%llu;",
+			sc->stripes,
+			(unsigned long long)sc->chunk_size);
+		for (i = 0; i < sc->stripes; i++) {
+			DMEMIT("stripe_%d_device_name=%s;", i, sc->stripe[i].dev->name);
+			DMEMIT("stripe_%d_physical_start=%llu;", i,
+			       (unsigned long long)sc->stripe[i].physical_start);
+			DMEMIT("stripe_%d_status=%c;", i,
+			       atomic_read(&(sc->stripe[i].error_count)) ? 'D' : 'A');
+		}
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c
index 262e2b0fd975..028a92ff6d57 100644
--- a/drivers/md/dm-switch.c
+++ b/drivers/md/dm-switch.c
@@ -504,6 +504,10 @@ static void switch_status(struct dm_target *ti, status_type_t type,
 			DMEMIT(" %s %llu", sctx->path_list[path_nr].dmdev->name,
 			       (unsigned long long)sctx->path_list[path_nr].start);
 		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 985baee3a678..fc299cf90135 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -4012,6 +4012,10 @@ static void pool_status(struct dm_target *ti, status_type_t type,
 		       (unsigned long long)pt->low_water_blocks);
 		emit_flags(&pt->requested_pf, result, sz, maxlen);
 		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 	return;
 
@@ -4423,6 +4427,10 @@ static void thin_status(struct dm_target *ti, status_type_t type,
 			if (tc->origin_dev)
 				DMEMIT(" %s", format_dev_t(buf, tc->origin_dev->bdev->bd_dev));
 			break;
+
+		case STATUSTYPE_IMA:
+			result[0] = '\0';
+			break;
 		}
 	}
 
diff --git a/drivers/md/dm-unstripe.c b/drivers/md/dm-unstripe.c
index 7357c1bd5863..c04be1f6d059 100644
--- a/drivers/md/dm-unstripe.c
+++ b/drivers/md/dm-unstripe.c
@@ -156,6 +156,10 @@ static void unstripe_status(struct dm_target *ti, status_type_t type,
 		       uc->stripes, (unsigned long long)uc->chunk_size, uc->unstripe,
 		       uc->dev->name, (unsigned long long)uc->physical_start);
 		break;
+
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index d3e76aefc1a6..38c991eb5069 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -772,6 +772,52 @@ static void verity_status(struct dm_target *ti, status_type_t type,
 			DMEMIT(" " DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY
 				" %s", v->signature_key_desc);
 		break;
+
+	case STATUSTYPE_IMA:
+		DMEMIT_NAME_VERSION(ti->type);
+
+		DMEMIT("hash_failed=%c;", v->hash_failed ? 'C' : 'V');
+
+		DMEMIT("verity_version=%u;", v->version);
+		DMEMIT("data_device_name=%s;", v->data_dev->name);
+		DMEMIT("hash_device_name=%s;", v->hash_dev->name);
+		DMEMIT("verity_algorithm=%s;", v->alg_name);
+
+		DMEMIT("root_digest=");
+		for (x = 0; x < v->digest_size; x++)
+			DMEMIT("%02x", v->root_digest[x]);
+		DMEMIT(";");
+
+		DMEMIT("salt=");
+		if (!v->salt_size)
+			DMEMIT("-");
+		else
+			for (x = 0; x < v->salt_size; x++)
+				DMEMIT("%02x", v->salt[x]);
+		DMEMIT(";");
+
+		DMEMIT("%s", v->zero_digest ? "ignore_zero_blocks=y;" : "ignore_zero_blocks=n;");
+		DMEMIT("%s", v->validated_blocks ? "check_at_most_once=y;" :
+		       "check_at_most_once=n;");
+
+		if (v->mode != DM_VERITY_MODE_EIO) {
+			DMEMIT("verity_mode=");
+			switch (v->mode) {
+			case DM_VERITY_MODE_LOGGING:
+				DMEMIT(DM_VERITY_OPT_LOGGING);
+				break;
+			case DM_VERITY_MODE_RESTART:
+				DMEMIT(DM_VERITY_OPT_RESTART);
+				break;
+			case DM_VERITY_MODE_PANIC:
+				DMEMIT(DM_VERITY_OPT_PANIC);
+				break;
+			default:
+				DMEMIT("invalid");
+			}
+			DMEMIT(";");
+		}
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c
index aecc246ade26..02bb1019bdc6 100644
--- a/drivers/md/dm-writecache.c
+++ b/drivers/md/dm-writecache.c
@@ -2536,6 +2536,9 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
 		if (wc->writeback_fua_set)
 			DMEMIT(" %sfua", wc->writeback_fua ? "" : "no");
 		break;
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 }
 
diff --git a/drivers/md/dm-zoned-target.c b/drivers/md/dm-zoned-target.c
index 7e88df64d197..b1d311238b5b 100644
--- a/drivers/md/dm-zoned-target.c
+++ b/drivers/md/dm-zoned-target.c
@@ -1119,6 +1119,9 @@ static void dmz_status(struct dm_target *ti, status_type_t type,
 			DMEMIT(" %s", buf);
 		}
 		break;
+	case STATUSTYPE_IMA:
+		result[0] = '\0';
+		break;
 	}
 	return;
 }
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index 738a7d023650..61ac0fcec7d4 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -596,6 +596,10 @@ void dm_destroy_keyslot_manager(struct blk_keyslot_manager *ksm);
 #define DMEMIT(x...) sz += ((sz >= maxlen) ? \
 			  0 : scnprintf(result + sz, maxlen - sz, x))
 
+#define DMEMIT_NAME_VERSION(y) \
+		DMEMIT("target_type_name=%s;target_type_version=%u.%u.%u;", \
+			y->name, y->version[0], y->version[1], y->version[2])
+
 /*
  * Definitions of return values from target end_io function.
  */
-- 
2.17.1

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [dm-devel] [RFC 7/7] dm: add documentation for IMA measurement support
  2021-05-26  0:59 [dm-devel] [RFC 0/7] device mapper target measurements using IMA Tushar Sugandhi
                   ` (5 preceding siblings ...)
  2021-05-26  0:59 ` [dm-devel] [RFC 6/7] dm: update target specific status functions to measure data Tushar Sugandhi
@ 2021-05-26  0:59 ` Tushar Sugandhi
  6 siblings, 0 replies; 8+ messages in thread
From: Tushar Sugandhi @ 2021-05-26  0:59 UTC (permalink / raw)
  To: dm-devel; +Cc: tusharsu, nramas, zohar, snitzer, agk

System administrators need instructions to set the IMA policy correctly
to enable measurement of various DM targets using IMA.  Various
attestation client/server component owners also need the detailed 
information on how to interpret the IMA measurement data emitted by DM 
targets.  To address that, a separate documentation page is needed.

Add documentation to admin-guide to help system administrators and 
attestation client/server component owners interpret the measurement
data generated by various DM targets, on various device / table state
changes.

Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
---
 .../admin-guide/device-mapper/dm-ima.rst      | 271 ++++++++++++++++++
 .../admin-guide/device-mapper/index.rst       |   1 +
 2 files changed, 272 insertions(+)
 create mode 100644 Documentation/admin-guide/device-mapper/dm-ima.rst

diff --git a/Documentation/admin-guide/device-mapper/dm-ima.rst b/Documentation/admin-guide/device-mapper/dm-ima.rst
new file mode 100644
index 000000000000..f7b486ed2ca1
--- /dev/null
+++ b/Documentation/admin-guide/device-mapper/dm-ima.rst
@@ -0,0 +1,271 @@
+======
+dm-ima
+======
+
+For a given system, various external services/infrastructure tools
+(including the attestation service) interact with it - both during the
+setup and during rest of the system run-time.  They share sensitive data
+and/or execute critical workload on that system.  The external services
+may want to verify the current run-time state of the relevant kernel
+subsystems before fully trusting the system with business-critical
+data/workload.
+
+Device mapper plays a critical role on a given system by providing
+various important functionalities to the block devices using various
+target types like crypt, verity, integrity etc.  Each of these target
+types’ functionalities can be configured with various attributes.
+The attributes chosen to configure these target types can significantly
+impact the security profile of the block device, and in-turn, of the
+system itself.  For instance, the type of encryption algorithm and the
+key size determines the strength of encryption for a given block device.
+
+Therefore, verifying the current state of various block devices as well
+as their various target attributes is crucial for external services before
+fully trusting the system with business-critical data/workload.
+
+IMA kernel subsystem provides the necessary functionality for
+device mapper to measure the state and configuration of
+various block devices -
+  - BY device mapper itself, from within the kernel,
+  - in a tamper resistant way,
+  - and re-measured - triggered on state/configuration change.
+
+Setting the IMA Policy:
+=======================
+For IMA to measure the data on a given system, the IMA policy on the
+system needs to be updated to have following line, and the system needs
+to be restarted for the measurements to take effect.
+
+/etc/ima/ima-policy
+ measure func=CRITICAL_DATA label=device-mapper template=ima-buf
+
+The measurements will be reflected in the IMA logs, which are located at:
+
+/sys/kernel/security/integrity/ima/ascii_runtime_measurements
+/sys/kernel/security/integrity/ima/binary_runtime_measurements
+
+Supported Device States:
+========================
+Following device state changes will trigger IMA measurements.
+01. Table load
+02. Device resume
+03. Device remove
+04. Table clear
+05. Device rename
+
+01. Table load:
+---------------
+When a new table is loaded in a device's inactive table slot,
+the device information and target specific details from the
+targets in the table are measured.
+
+For instance, if a linear device is created with the following table entries,
+#dmsetup create linear1
+0 1 linear /dev/loop0 8192
+1 1 linear /dev/loop1 8192
+2 1 linear /dev/loop2 8192
+3 1 linear /dev/loop3 8192
+
+Then IMA ASCII measurement log will have an entry similar to the following,
+with the format:
+[device_data];[target_data_row_1];[target_data_row_2];...[target_data_row_n];
+
+(converted from ASCII to text for readability)
+
+10 0d27cf7227d473d1c2b56b0433ca0215f2aefa0f ima-buf sha1:ec047e05fa07a9b477631d298539dcac8bdd3025
+table_load name=linear1;uuid=;capacity=0;major=253;minor=0;minor_count=1;num_targets=4;
+target_type_name=linear;target_type_version=1.4.0;device_name=7:0;start=8192;
+target_type_name=linear;target_type_version=1.4.0;device_name=7:1;start=8192;
+target_type_name=linear;target_type_version=1.4.0;device_name=7:2;start=8192;
+target_type_name=linear;target_type_version=1.4.0;device_name=7:3;start=8192;
+
+02. Device resume:
+------------------
+When a suspended device is resumed, the device information and a sha256 hash of the
+data from previous load of an active table are measured.
+
+For instance, if a linear device is resumed with the following command,
+#dmsetup resume linear1
+
+Then IMA ASCII measurement log will have an entry similar to the following,
+with the format:
+[device_data];active_table_hash=(sha256hash([device_data];[target_data_row_1];...[target_data_row_n]);
+
+(converted from ASCII to text for readability)
+
+10 e36dce92b9070434876d01bfc8e3cc942dbe3ce2 ima-buf sha1:fb5c71b7dc91bcc64bcae552694e809bfcb4e52e
+device_resume name=linear1;uuid=;capacity=0;major=253;minor=0;minor_count=1;num_targets=4;
+active_table_hash=07b98a0b742f8a45588118632cef4c5706579caa552585ec5ddb50fe03aa083b;
+
+
+
+03. Device remove:
+------------------
+When a device is removed, the device information and a sha256 hash of the
+data from an active and inactive table are measured.
+
+For instance, if a linear device is removed with the following command,
+# dmsetup remove linear1
+
+Then IMA ASCII measurement log will have an entry similar to the following,
+with the format:
+[device_data];active_table_hash=(sha256hash([device_data];[rows_from_active_table]]);
+inactive_table_hash=(sha256hash([device_data];[rows_from_inactive_table]]);
+
+(converted from ASCII to text for readability)
+
+10 724e209d998546427f70ce45b508a42eeebb9d0a ima-buf sha1:27f7bc1380d38058025007df0fff94a5e8fe2374
+device_remove name=linear1;uuid=1234;capacity=4;major=253;minor=0;minor_count=1;num_targets=4;
+active_table_hash=07b98a0b742f8a45588118632cef4c5706579caa552585ec5ddb50fe03aa083b;
+inactive_table_hash=07b98a0b742f8a45588118632cef4c5706579caa552585ec5ddb50fe03aa083b;
+
+
+04. Table clear:
+----------------
+When an inactive table is cleared from the device, the device information and a sha256 hash of the
+data from an inactive table are measured.
+
+For instance, if a linear device's inactive table is cleared with the following command,
+
+# dmsetup clear linear1
+
+Then IMA ASCII measurement log will have an entry similar to the following,
+with the format:
+[device_data];inactive_table_hash=(sha256hash([device_data];[rows_from_inactive_table]]);
+
+(converted from ASCII to text for readability)
+
+10 5f9ae8da02ab2abde3b92df20d6d3f8b8d3369db ima-buf sha1:0105b5946801e6e42e6f42b5d90f7583e98b08c5
+table_clear name=linear1;uuid=1234;capacity=4;major=253;minor=0;minor_count=1;num_targets=4;
+inactive_table_hash=80bfc94f14f7f5a3d68ea6dbbd53064f90cdd30e0ea1cbdb593f7a1f2b0e96c7;
+
+
+05. Device rename:
+------------------
+When an device's NAME or UUID is changed, the device information and the new NAME and UUID
+are measured.
+
+For instance, if a linear device's name is changed with the following command,
+
+#dmsetup rename linear1 linear=2
+Then IMA ASCII measurement log will have an entry similar to the following,
+with the format:
+[current_device_data];new_name=<new_name_value>;new_uuid=<new_uuid_value>;
+
+
+(converted from ASCII to text for readability)
+10 10b599505894c0885aeef801ede7e04a87b4245e ima-buf sha1:b0abee16f7caa778035b49c1c8119186248b44a4
+device_rename name=linear1;uuid=1234;capacity=4;major=253;minor=0;minor_count=1;num_targets=4;
+new_name=linear\=2;new_uuid=1234;
+
+
+Supported targets:
+==================
+Following targets are supported to measure their data using IMA.
+
+01. cache
+02. crypt
+03. integrity
+04. linear
+05. mirror
+06. multipath
+07. raid
+08. snapshot
+09. striped
+10. verity
+
+01. cache
+---------
+<<documenatation in progress>>
+
+02. crypt
+-----
+When a crypt target is loaded, then IMA ASCII measurement log will have an entry
+similar to the following, depicting what crypt attributes are measured.
+
+(converted from ASCII to text for readability)
+
+10 7852bada6bb36d59cdc9a17369f9b9f71f46c1eb ima-buf sha1:c84c1680a37f049a01430dd3886f20a597f9fec8
+ table_load name=luks-2777bb3d-6160-4dcd-8722-a86a519a95c1;
+ uuid=CRYPT-LUKS1-2777bb3d61604dcd8722a86a519a95c1-luks-2777bb3d-6160-4dcd-8722-a86a519a95c1;
+ capacity=0;major=253;minor=15;minor_count=1;num_targets=1;target_type_name=crypt;
+ target_type_version=1.23.0;allow_discards=n;same_cpu=n;submit_from_crypt_cpus=n;no_read_workqueue=n;
+ no_write_workqueue=n;iv_large_sectors=y;cipher_string=aes-xts-plain64;key_size=32;key_parts=1;
+ key_extra_size=0;key_mac_size=0;
+
+03. integrity
+-------------
+<<documenatation in progress>>
+
+
+04. linear
+----------
+When a linear target is loaded, then IMA ASCII measurement log will have an entry
+similar to the following, depicting what linear attributes are measured.
+
+(converted from ASCII to text for readability)
+10 8fb70d291178abcc2acca33ef57adc0d3ff0e67a ima-buf sha1:4b9ae1ae655505054b0ab37181e2f9f8d847f675
+table_load name=linear1;uuid=1234;capacity=4;major=253;minor=0;minor_count=1;num_targets=4;
+target_type_name=linear;target_type_version=1.4.0;device_name=7:0;start=8192;
+
+
+05. mirror
+----------
+When a mirror target is loaded, then IMA ASCII measurement log will have an entry
+similar to the following, depicting what mirror attributes are measured.
+
+(converted from ASCII to text for readability)
+10 4dd208e0fd00a5b5ca358364b5a90eb2c4f2013e ima-buf sha1:7bf75a5db56958ec07ee3f5ae356e58d52fe8910
+table_load name=test-mirror;uuid=;capacity=0;major=253;minor=7;minor_count=1;num_targets=1;
+target_type_name=mirror;target_type_version=1.14.0;mirrors=2;mirror_device_0=253:2;
+mirror_device_0_status=A;mirror_device_1=253:6;mirror_device_1_status=A;handle_errors=y;
+keep_log=n;log_type_status=;
+
+06. multipath
+-------------
+<<documenatation in progress>>
+
+07. raid
+--------
+When a raid target is loaded, then IMA ASCII measurement log will have an entry
+similar to the following, depicting what raid attributes are measured.
+
+(converted from ASCII to text for readability)
+10 ad7ce5156f6675bacf07e57fc7d24b52128682a6 ima-buf sha1:024b05c82badd4edf8a1e877f8fc558e8de80acb
+table_load name=test-raid1;uuid=;capacity=0;major=253;minor=2;minor_count=1;num_targets=1;
+target_type_name=raid;target_type_version=1.15.1;raid_type=raid1;raid_disks=2;raid_state=idle;
+raid_device_0_status=A;raid_device_1_status=A;
+
+08. snapshot
+------------
+<<documenatation in progress>>
+
+09. striped
+----------
+When a linear target is loaded, then IMA ASCII measurement log will have an entry
+similar to the following, depicting what linear attributes are measured.
+
+(converted from ASCII to text for readability)
+10 b75993407d68c74de8a13a9467049a57013fb855 ima-buf sha1:fa75997f2bf9b87ee4b4dff5bd420055b22f938a
+table_load name=test-raid0;uuid=;capacity=0;major=253;minor=11;minor_count=1;num_targets=1;
+target_type_name=striped;target_type_version=1.6.0;stripes=4;chunk_size=128;
+stripe_0_device_name=253:1;stripe_0_physical_start=0;stripe_0_status=A;
+stripe_1_device_name=253:6;stripe_1_physical_start=0;stripe_1_status=A;
+stripe_2_device_name=253:8;stripe_2_physical_start=0;stripe_2_status=A;
+stripe_3_device_name=253:10;stripe_3_physical_start=0;stripe_3_status=A;
+
+10. verity
+----------
+When a verity target is loaded, then IMA ASCII measurement log will have an entry
+similar to the following, depicting what verity attributes are measured.
+
+(converted from ASCII to text for readability)
+
+0 c5188b404e70166baa1573fb289eea81981d5164 ima-buf sha1:a2cc6780198ede624d4f0864ffa76741332f85d3
+table_load name=vr2;uuid=CRYPT-VERITY-c5203ede74d349d89941a46c51a6784f-vr2;capacity=0;major=253;minor=16;
+minor_count=1;num_targets=1;
+target_type_name=verity;target_type_version=1.8.0;hash_failed=V;verity_version=1;
+data_device_name=8:49;hash_device_name=8:33;verity_algorithm=sha256;
+root_digest=6dbfd48cd67e5c94df25db02f15c621595675cceb39e1e88a8ccd773e408decc;
+salt=daab90c9f8a164c02c59f494fa7d5cde91c415ebe0b0fb9b068c2c9d3b57a787;
+ignore_zero_blocks=n;check_at_most_once=n;
diff --git a/Documentation/admin-guide/device-mapper/index.rst b/Documentation/admin-guide/device-mapper/index.rst
index 6cf8adc86fa8..cde52cc09645 100644
--- a/Documentation/admin-guide/device-mapper/index.rst
+++ b/Documentation/admin-guide/device-mapper/index.rst
@@ -13,6 +13,7 @@ Device Mapper
     dm-dust
     dm-ebs
     dm-flakey
+    dm-ima
     dm-init
     dm-integrity
     dm-io
-- 
2.17.1


--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-05-26  1:10 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-26  0:59 [dm-devel] [RFC 0/7] device mapper target measurements using IMA Tushar Sugandhi
2021-05-26  0:59 ` [dm-devel] [RFC 1/7] dm: measure data on table load Tushar Sugandhi
2021-05-26  0:59 ` [dm-devel] [RFC 2/7] dm: measure data on device resume Tushar Sugandhi
2021-05-26  0:59 ` [dm-devel] [RFC 3/7] dm: measure data on device remove Tushar Sugandhi
2021-05-26  0:59 ` [dm-devel] [RFC 4/7] dm: measure data on table clear Tushar Sugandhi
2021-05-26  0:59 ` [dm-devel] [RFC 5/7] dm: measure data on device rename Tushar Sugandhi
2021-05-26  0:59 ` [dm-devel] [RFC 6/7] dm: update target specific status functions to measure data Tushar Sugandhi
2021-05-26  0:59 ` [dm-devel] [RFC 7/7] dm: add documentation for IMA measurement support Tushar Sugandhi

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.