Blob Blame History Raw
From b5b19869f015d7d67c5284b68be6641bb591ac20 Mon Sep 17 00:00:00 2001
From: Michal Suchanek <msuchanek@suse.de>
Date: Thu, 7 May 2020 17:19:43 +0200
Subject: [PATCH] libnvdimm: cover up nvdimm_security_ops changes

References: bsc#1171742
Patch-mainline: never, kabi

nvdimm->sec.ops->get_state returning enum changed to
nvdimm->sec.ops->get_flags returning unsigned long bitfield.
THe function is wrapped in nvdimm_security_flags inline function and
never called directly.

Added conversion from the enum to bitfield. Unfortunately, the format is
not perfectly compatible. When an old driver reports that security is
disabled it has the same numerical value as security unsupported in the
new driver. These states are interpreted as securty disabled.
Specification says that device that does not support security should
abort all security commands. Drivers without security support won't even
provide the security operations.

Signed-off-by: Michal Suchanek <msuchanek@suse.de>
---
 drivers/nvdimm/nd-core.h  | 13 ++++++++
 include/linux/libnvdimm.h | 23 +++++++++++++-
 3 files changed, 99 insertions(+), 1 deletion(-)

diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h
index ae935194c3df..2be6b966c565 100644
--- a/drivers/nvdimm/nd-core.h
+++ b/drivers/nvdimm/nd-core.h
@@ -65,6 +65,19 @@ static inline unsigned long nvdimm_security_flags(
 		return 0;
 
 	flags = nvdimm->sec.ops->get_flags(nvdimm, ptype);
+	/*
+	 * The old function returns 0 for disabled and < 0 for error.
+	 * The new function returns 0 for error and has disabled flag.
+	 * This interprets unsupported security state as disabled. The
+	 * specification states that the device should abort all security
+	 * related commands in this case.
+	 */
+	if (flags & (1 << 31)) /* 32bit sign */
+		flags = 0;
+	/* Convert old enum value into flags */
+	flags &= UINT_MAX;
+	if (flags < (1 << NVDIMM_SECURITY_DISABLED))
+		flags = 1 << (flags + NVDIMM_SECURITY_DISABLED);
 	/* disabled, locked, unlocked, and overwrite are mutually exclusive */
 	dev_WARN_ONCE(&nvdimm->dev, hweight64(flags & state_flags) > 1,
 			"reported invalid security state: %#llx\n",
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index aa4b79d68d79..24ee67756994 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -162,18 +162,34 @@ static inline struct nd_blk_region_desc *to_blk_region_desc(
 
 }
 
+enum nvdimm_security_state {
+	NVDIMM_SECURITY_ERROR = -1,
+#ifdef __GENKSYMS__
+	NVDIMM_SECURITY_DISABLED,
+	NVDIMM_SECURITY_UNLOCKED,
+	NVDIMM_SECURITY_LOCKED,
+	NVDIMM_SECURITY_FROZEN,
+	NVDIMM_SECURITY_OVERWRITE,
+#endif
+};
 /*
  * Note that separate bits for locked + unlocked are defined so that
  * 'flags == 0' corresponds to an error / not-supported state.
  */
 enum nvdimm_security_bits {
-	NVDIMM_SECURITY_DISABLED,
+	NVDIMM_SECURITY_DISABLED = 3,
 	NVDIMM_SECURITY_UNLOCKED,
 	NVDIMM_SECURITY_LOCKED,
 	NVDIMM_SECURITY_FROZEN,
 	NVDIMM_SECURITY_OVERWRITE,
+	NVDIMM_SECURITY_NFLAGS
 };
 
+static inline void nvdimm_security_bits_check(void)
+{
+    BUILD_BUG_ON(NVDIMM_SECURITY_NFLAGS >= 30);
+}
+
 #define NVDIMM_PASSPHRASE_LEN		32
 #define NVDIMM_KEY_DESC_LEN		22
 
@@ -187,8 +203,13 @@ enum nvdimm_passphrase_type {
 };
 
 struct nvdimm_security_ops {
+#ifdef __GENKSYMS__
+	enum nvdimm_security_state (*state)(struct nvdimm *nvdimm,
+			enum nvdimm_passphrase_type pass_type);
+#else
 	unsigned long (*get_flags)(struct nvdimm *nvdimm,
 			enum nvdimm_passphrase_type pass_type);
+#endif
 	int (*freeze)(struct nvdimm *nvdimm);
 	int (*change_key)(struct nvdimm *nvdimm,
 			const struct nvdimm_key_data *old_data,
-- 
2.26.2