diff --git a/security/loadpin/Kconfig b/security/loadpin/Kconfig
index 91be65dec2ab..20681dc4b8a5 100644
--- a/security/loadpin/Kconfig
+++ b/security/loadpin/Kconfig
@@ -18,3 +18,19 @@ config SECURITY_LOADPIN_ENFORCE
 	  If selected, LoadPin will enforce pinning at boot. If not
 	  selected, it can be enabled at boot with the kernel parameter
 	  "loadpin.enforce=1".
+
+config SECURITY_LOADPIN_VERITY
+	bool "Allow reading files from certain other filesystems that use dm-verity"
+	depends on DM_VERITY=y && SYSCTL
+	help
+	  If selected LoadPin can allow reading files from filesystems
+	  that use dm-verity. LoadPin maintains a list of verity root
+	  digests it considers trusted. A verity backed filesystem is
+	  considered trusted if its root digest is found in the list
+	  of trusted digests.
+
+	  Userspace can populate the list of trusted digests by writing
+	  the path of a file with the digests to the syctl file
+	  'trusted_verity_root_digests_path'. The file must be located
+	  on the pinned root and contain a comma separated list of
+	  digests.
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index b12f7d986b1e..db10b7ff6efd 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -18,6 +18,8 @@
 #include <linux/path.h>
 #include <linux/sched.h>	/* current */
 #include <linux/string_helpers.h>
+#include <linux/device-mapper.h>
+#include <linux/dm-verity-loadpin.h>
 
 static void report_load(const char *origin, struct file *file, char *operation)
 {
@@ -43,6 +45,10 @@ static char *exclude_read_files[READING_MAX_ID];
 static int ignore_read_file_id[READING_MAX_ID] __ro_after_init;
 static struct super_block *pinned_root;
 static DEFINE_SPINLOCK(pinned_root_spinlock);
+#ifdef CONFIG_SECURITY_LOADPIN_VERITY
+static LIST_HEAD(trusted_verity_root_digests);
+static const char *verity_digests_path;
+#endif
 
 #ifdef CONFIG_SYSCTL
 
@@ -65,6 +71,176 @@ static struct ctl_table loadpin_sysctl_table[] = {
 	{ }
 };
 
+#ifdef CONFIG_SECURITY_LOADPIN_VERITY
+
+static int loadpin_read_file(struct file *file, enum kernel_read_file_id id,
+			     bool contents);
+
+static int read_trusted_verity_root_digests(struct file *file)
+{
+	void *data;
+	char *p, *d;
+	int err, rc;
+
+	data = kzalloc(SZ_4K, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	rc = kernel_read_file(file, 0, &data, SZ_4K - 1, NULL, READING_POLICY);
+	if (rc < 0)
+		return rc;
+
+	((char *)data)[rc] = '\0';
+
+	p = strim(data);
+	while ((d = strsep(&p, ",")) != NULL) {
+		int len = strlen(d);
+		struct trusted_root_digest *trd;
+
+		if (len % 2) {
+			err = -EPROTO;
+			goto free_mem;
+		}
+
+		len /= 2;
+
+		trd = kzalloc(sizeof(*trd), GFP_KERNEL);
+		if (!trd) {
+			err = -ENOMEM;
+			goto free_mem;
+		}
+
+		trd->data = kzalloc(len, GFP_KERNEL);
+		if (!trd->data) {
+			kfree(trd);
+			err = -ENOMEM;
+			goto free_mem;
+		}
+
+		if (hex2bin(trd->data, d, len)) {
+			kfree(trd);
+			err = -EPROTO;
+			goto free_mem;
+		}
+
+		list_add_tail(&trd->node, &trusted_verity_root_digests);
+
+		trd->len = len;
+	}
+
+	kfree(data);
+
+	return 0;
+
+free_mem:
+	kfree(data);
+
+	{
+		struct trusted_root_digest *trd, *tmp;
+
+		list_for_each_entry_safe(trd, tmp, &trusted_verity_root_digests, node) {
+			kfree(trd->data);
+			list_del(&trd->node);
+			kfree(trd);
+		}
+	}
+
+	return err;
+}
+
+static int proc_verity_digests(struct ctl_table *table, int write,
+			       void *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct ctl_table tbl = *table;
+
+	if (write) {
+		int rc;
+		char *digests_path;
+		struct file *file;
+
+		if (*ppos)
+			return -EINVAL;
+
+		if (verity_digests_path != NULL)
+			return -EPERM;
+
+		digests_path = kzalloc(tbl.maxlen, GFP_KERNEL);
+		if (!digests_path)
+			return -ENOMEM;
+
+		tbl.data = digests_path;
+
+		rc = proc_dostring(&tbl, write, buffer, lenp, ppos);
+		if (rc) {
+			kfree(digests_path);
+			return rc;
+		}
+
+		/* only absolute paths are allowed */
+		if (digests_path[0] != '/') {
+			kfree(digests_path);
+			return -EINVAL;
+		}
+
+		file = filp_open(digests_path, O_RDONLY, 0);
+		if (IS_ERR(file)) {
+			int err = PTR_ERR(file);
+
+			if (err == -ENOENT) {
+				kfree(digests_path);
+				return -EINVAL;
+			}
+
+			return err;
+		}
+
+		/* verify the root digests stem from a trusted file system */
+		if (loadpin_read_file(file, READING_POLICY, true)) {
+			fput(file);
+			kfree(digests_path);
+			return -EPERM;
+		}
+
+		rc = read_trusted_verity_root_digests(file);
+		fput(file);
+		if (rc) {
+			kfree(digests_path);
+			return rc;
+		}
+
+		verity_digests_path = digests_path;
+	} else {
+		if (verity_digests_path) {
+			tbl.data = kzalloc(strlen(verity_digests_path) + 1, GFP_KERNEL);
+			strcpy(tbl.data, verity_digests_path);
+		} else {
+			tbl.data = kzalloc(1, GFP_KERNEL);
+		}
+
+		proc_dostring(&tbl, write, buffer, lenp, ppos);
+		kfree(tbl.data);
+	}
+
+	return 0;
+}
+
+static struct ctl_table loadpin_sysctl_table_verity_digests[] = {
+	{
+		.procname       = "trusted_verity_root_digests_path",
+		.maxlen         = SZ_256,
+		.mode           = 0644,
+		.proc_handler   = proc_verity_digests,
+	},
+
+	{ }
+};
+
+#else
+
+static struct ctl_table loadpin_sysctl_table_verity_digests[] = {};
+
+#endif /* CONFIG_SECURITY_LOADPIN_VERITY */
+
 /*
  * This must be called after early kernel init, since then the rootdev
  * is available.
@@ -118,6 +294,20 @@ static void loadpin_sb_free_security(struct super_block *mnt_sb)
 	}
 }
 
+static bool loadpin_is_fs_trusted(struct super_block *sb)
+{
+	struct mapped_device *md = dm_get_md(sb->s_bdev->bd_dev);
+	bool trusted;
+
+	if (!md)
+		return false;
+
+	trusted = dm_verity_loadpin_is_md_trusted(md);
+	dm_put(md);
+
+	return trusted;
+}
+
 static int loadpin_read_file(struct file *file, enum kernel_read_file_id id,
 			     bool contents)
 {
@@ -174,7 +364,8 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id,
 		spin_unlock(&pinned_root_spinlock);
 	}
 
-	if (IS_ERR_OR_NULL(pinned_root) || load_root != pinned_root) {
+	if (IS_ERR_OR_NULL(pinned_root) ||
+	    ((load_root != pinned_root) && !loadpin_is_fs_trusted(load_root))) {
 		if (unlikely(!enforce)) {
 			report_load(origin, file, "pinning-ignored");
 			return 0;
@@ -240,6 +431,13 @@ static int __init loadpin_init(void)
 		enforce ? "" : "not ");
 	parse_exclude();
 	security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
+
+	if (IS_ENABLED(CONFIG_SECURITY_LOADPIN_VERITY)) {
+		if (!register_sysctl_paths(loadpin_sysctl_path,
+					   loadpin_sysctl_table_verity_digests))
+			pr_notice("sysctl registration failed!\n");
+	}
+
 	return 0;
 }
 
