[PATCH v3 0/3] sed-opal: keyrings, discovery, revert, key store

STALE1386d

Revision v3 of 6 in this series.

16 messages, 3 authors, 2022-12-02 · open the first message on its own page

[PATCH v3 0/3] sed-opal: keyrings, discovery, revert, key store

From: <hidden>
Date: 2022-11-29 23:25:28

From: Greg Joyce <redacted>

TCG SED Opal is a specification from The Trusted Computing Group
that allows self encrypting storage devices (SED) to be locked at
power on and require an authentication key to unlock the drive.

The current SED Opal implementation in the block driver
requires that authentication keys be provided in an ioctl
so that they can be presented to the underlying SED
capable drive. Currently, the key is typically entered by
a user with an application like sedutil or sedcli. While
this process works, it does not lend itself to automation
like unlock by a udev rule.

The SED block driver has been extended so it can alternatively
obtain a key from a sed-opal kernel keyring. The SED ioctls
will indicate the source of the key, either directly in the
ioctl data or from the keyring.

Two new SED ioctls have also been added. These are:
  1) IOC_OPAL_REVERT_LSP to revert LSP state
  2) IOC_OPAL_DISCOVERY to discover drive capabilities/state

change log:
	- rebase to 6.x
	- added latest reviews
        - removed platform functions for persistent key storage
        - replaced key update logic with key_create_or_update()
        - minor bracing and padding changes
        - add error returns
        - opal_key structure is application provided but kernel
          verified
        - added brief description of TCG SED Opal


Greg Joyce (3):
  block: sed-opal: Implement IOC_OPAL_DISCOVERY
  block: sed-opal: Implement IOC_OPAL_REVERT_LSP
  block: sed-opal: keyring support for SED keys

 block/Kconfig                 |   1 +
 block/opal_proto.h            |   4 +
 block/sed-opal.c              | 252 +++++++++++++++++++++++++++++++++-
 include/linux/sed-opal.h      |   5 +
 include/uapi/linux/sed-opal.h |  25 +++-
 5 files changed, 281 insertions(+), 6 deletions(-)

Signed-off-by: Greg Joyce <redacted>
base-commit: 59d0d52c30d4991ac4b329f049cc37118e00f5b0
-- 
gjoyce@linux.vnet.ibm.com

[PATCH v3 1/3] block: sed-opal: Implement IOC_OPAL_DISCOVERY

From: <hidden>
Date: 2022-11-29 23:25:29

From: Greg Joyce <redacted>

Add IOC_OPAL_DISCOVERY ioctl to return raw discovery data to a SED Opal
application. This allows the application to display drive capabilities
and state.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
 block/sed-opal.c              | 38 ++++++++++++++++++++++++++++++++---
 include/linux/sed-opal.h      |  1 +
 include/uapi/linux/sed-opal.h |  6 ++++++
 3 files changed, 42 insertions(+), 3 deletions(-)
diff --git a/block/sed-opal.c b/block/sed-opal.c
index 9bdb833e5817..0e65ac0cd69e 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -457,8 +457,11 @@ static int execute_steps(struct opal_dev *dev,
 	return error;
 }
 
-static int opal_discovery0_end(struct opal_dev *dev)
+static int opal_discovery0_end(struct opal_dev *dev, void *data)
 {
+	struct opal_discovery *discv_out = data; /* may be NULL */
+	u8 __user *buf_out;
+	u64 len_out;
 	bool found_com_id = false, supported = true, single_user = false;
 	const struct d0_header *hdr = (struct d0_header *)dev->resp;
 	const u8 *epos = dev->resp, *cpos = dev->resp;
@@ -474,6 +477,15 @@ static int opal_discovery0_end(struct opal_dev *dev)
 		return -EFAULT;
 	}
 
+	if (discv_out) {
+		buf_out = (u8 __user *)(uintptr_t)discv_out->data;
+		len_out = min_t(u64, discv_out->size, hlen);
+		if (buf_out && copy_to_user(buf_out, dev->resp, len_out))
+			return -EFAULT;
+
+		discv_out->size = hlen; /* actual size of data */
+	}
+
 	epos += hlen; /* end of buffer */
 	cpos += sizeof(*hdr); /* current position on buffer */
 
@@ -557,13 +569,13 @@ static int opal_discovery0(struct opal_dev *dev, void *data)
 	if (ret)
 		return ret;
 
-	return opal_discovery0_end(dev);
+	return opal_discovery0_end(dev, data);
 }
 
 static int opal_discovery0_step(struct opal_dev *dev)
 {
 	const struct opal_step discovery0_step = {
-		opal_discovery0,
+		opal_discovery0, NULL
 	};
 
 	return execute_step(dev, &discovery0_step, 0);
@@ -2245,6 +2257,22 @@ static int opal_secure_erase_locking_range(struct opal_dev *dev,
 	return ret;
 }
 
+static int opal_get_discv(struct opal_dev *dev, struct opal_discovery *discv)
+{
+	const struct opal_step discovery0_step = {
+		opal_discovery0, discv
+	};
+	int ret = 0;
+
+	mutex_lock(&dev->dev_lock);
+	setup_opal_dev(dev);
+	ret = execute_step(dev, &discovery0_step, 0);
+	mutex_unlock(&dev->dev_lock);
+	if (ret)
+		return ret;
+	return discv->size; /* modified to actual length of data */
+}
+
 static int opal_erase_locking_range(struct opal_dev *dev,
 				    struct opal_session_info *opal_session)
 {
@@ -2773,6 +2801,10 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
 	case IOC_OPAL_GET_STATUS:
 		ret = opal_get_status(dev, arg);
 		break;
+	case IOC_OPAL_DISCOVERY:
+		ret = opal_get_discv(dev, p);
+		break;
+
 	default:
 		break;
 	}
diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
index 6f837bb6c715..ef62e9292b27 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -44,6 +44,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
 	case IOC_OPAL_WRITE_SHADOW_MBR:
 	case IOC_OPAL_GENERIC_TABLE_RW:
 	case IOC_OPAL_GET_STATUS:
+	case IOC_OPAL_DISCOVERY:
 		return true;
 	}
 	return false;
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
index 2573772e2fb3..fb6f7fa1e3fd 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -144,6 +144,11 @@ struct opal_status {
 	__u32 reserved;
 };
 
+struct opal_discovery {
+	__u64 data;
+	__u64 size;
+};
+
 #define IOC_OPAL_SAVE		    _IOW('p', 220, struct opal_lock_unlock)
 #define IOC_OPAL_LOCK_UNLOCK	    _IOW('p', 221, struct opal_lock_unlock)
 #define IOC_OPAL_TAKE_OWNERSHIP	    _IOW('p', 222, struct opal_key)
@@ -161,5 +166,6 @@ struct opal_status {
 #define IOC_OPAL_WRITE_SHADOW_MBR   _IOW('p', 234, struct opal_shadow_mbr)
 #define IOC_OPAL_GENERIC_TABLE_RW   _IOW('p', 235, struct opal_read_write_table)
 #define IOC_OPAL_GET_STATUS         _IOR('p', 236, struct opal_status)
+#define IOC_OPAL_DISCOVERY          _IOW('p', 237, struct opal_discovery)
 
 #endif /* _UAPI_SED_OPAL_H */
-- 
gjoyce@linux.vnet.ibm.com

[PATCH v3 2/3] block: sed-opal: Implement IOC_OPAL_REVERT_LSP

From: <hidden>
Date: 2022-11-29 23:25:30

From: Greg Joyce <redacted>

This is used in conjunction with IOC_OPAL_REVERT_TPR to return a drive to
Original Factory State without erasing the data. If IOC_OPAL_REVERT_LSP
is called with opal_revert_lsp.options bit OPAL_PRESERVE set prior
to calling IOC_OPAL_REVERT_TPR, the drive global locking range will not
be erased.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
 block/opal_proto.h            |  4 ++++
 block/sed-opal.c              | 40 +++++++++++++++++++++++++++++++++++
 include/linux/sed-opal.h      |  1 +
 include/uapi/linux/sed-opal.h | 11 ++++++++++
 4 files changed, 56 insertions(+)
diff --git a/block/opal_proto.h b/block/opal_proto.h
index 7152aa1f1a49..c3b5bff0b9e4 100644
--- a/block/opal_proto.h
+++ b/block/opal_proto.h
@@ -215,6 +215,10 @@ enum opal_parameter {
 	OPAL_SUM_SET_LIST = 0x060000,
 };
 
+enum opal_revertlsp {
+	OPAL_KEEP_GLOBAL_RANGE_KEY = 0x060000,
+};
+
 /* Packets derived from:
  * TCG_Storage_Architecture_Core_Spec_v2.01_r1.00
  * Secion: 3.2.3 ComPackets, Packets & Subpackets
diff --git a/block/sed-opal.c b/block/sed-opal.c
index 0e65ac0cd69e..993b2b7cc4c2 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -1632,6 +1632,26 @@ static int internal_activate_user(struct opal_dev *dev, void *data)
 	return finalize_and_send(dev, parse_and_check_status);
 }
 
+static int revert_lsp(struct opal_dev *dev, void *data)
+{
+	struct opal_revert_lsp *rev = data;
+	int err;
+
+	err = cmd_start(dev, opaluid[OPAL_THISSP_UID],
+			opalmethod[OPAL_REVERTSP]);
+	add_token_u8(&err, dev, OPAL_STARTNAME);
+	add_token_u64(&err, dev, OPAL_KEEP_GLOBAL_RANGE_KEY);
+	add_token_u8(&err, dev, (rev->options & OPAL_PRESERVE) ?
+			OPAL_TRUE : OPAL_FALSE);
+	add_token_u8(&err, dev, OPAL_ENDNAME);
+	if (err) {
+		pr_debug("Error building REVERT SP command.\n");
+		return err;
+	}
+
+	return finalize_and_send(dev, parse_and_check_status);
+}
+
 static int erase_locking_range(struct opal_dev *dev, void *data)
 {
 	struct opal_session_info *session = data;
@@ -2273,6 +2293,23 @@ static int opal_get_discv(struct opal_dev *dev, struct opal_discovery *discv)
 	return discv->size; /* modified to actual length of data */
 }
 
+static int opal_revertlsp(struct opal_dev *dev, struct opal_revert_lsp *rev)
+{
+	/* controller will terminate session */
+	const struct opal_step steps[] = {
+		{ start_admin1LSP_opal_session, &rev->key },
+		{ revert_lsp, rev }
+	};
+	int ret;
+
+	mutex_lock(&dev->dev_lock);
+	setup_opal_dev(dev);
+	ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
+	mutex_unlock(&dev->dev_lock);
+
+	return ret;
+}
+
 static int opal_erase_locking_range(struct opal_dev *dev,
 				    struct opal_session_info *opal_session)
 {
@@ -2801,6 +2838,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
 	case IOC_OPAL_GET_STATUS:
 		ret = opal_get_status(dev, arg);
 		break;
+	case IOC_OPAL_REVERT_LSP:
+		ret = opal_revertlsp(dev, p);
+		break;
 	case IOC_OPAL_DISCOVERY:
 		ret = opal_get_discv(dev, p);
 		break;
diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
index ef62e9292b27..7131d7f0eec2 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -45,6 +45,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
 	case IOC_OPAL_GENERIC_TABLE_RW:
 	case IOC_OPAL_GET_STATUS:
 	case IOC_OPAL_DISCOVERY:
+	case IOC_OPAL_REVERT_LSP:
 		return true;
 	}
 	return false;
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
index fb6f7fa1e3fd..fccde168e90c 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -51,6 +51,10 @@ struct opal_key {
 	__u8 key[OPAL_KEY_MAX];
 };
 
+enum opal_revert_lsp_opts {
+	OPAL_PRESERVE = 0x01,
+};
+
 struct opal_lr_act {
 	struct opal_key key;
 	__u32 sum;
@@ -149,6 +153,12 @@ struct opal_discovery {
 	__u64 size;
 };
 
+struct opal_revert_lsp {
+	struct opal_key key;
+	__u32 options;
+	__u32 __pad;
+};
+
 #define IOC_OPAL_SAVE		    _IOW('p', 220, struct opal_lock_unlock)
 #define IOC_OPAL_LOCK_UNLOCK	    _IOW('p', 221, struct opal_lock_unlock)
 #define IOC_OPAL_TAKE_OWNERSHIP	    _IOW('p', 222, struct opal_key)
@@ -167,5 +177,6 @@ struct opal_discovery {
 #define IOC_OPAL_GENERIC_TABLE_RW   _IOW('p', 235, struct opal_read_write_table)
 #define IOC_OPAL_GET_STATUS         _IOR('p', 236, struct opal_status)
 #define IOC_OPAL_DISCOVERY          _IOW('p', 237, struct opal_discovery)
+#define IOC_OPAL_REVERT_LSP         _IOW('p', 238, struct opal_revert_lsp)
 
 #endif /* _UAPI_SED_OPAL_H */
-- 
gjoyce@linux.vnet.ibm.com

[PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: <hidden>
Date: 2022-11-29 23:25:30

From: Greg Joyce <redacted>

Extend the SED block driver so it can alternatively
obtain a key from a sed-opal kernel keyring. The SED
ioctls will indicate the source of the key, either
directly in the ioctl data or from the keyring.

This allows the use of SED commands in scripts such as
udev scripts so that drives may be automatically unlocked
as they become available.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
 block/Kconfig                 |   1 +
 block/sed-opal.c              | 174 +++++++++++++++++++++++++++++++++-
 include/linux/sed-opal.h      |   3 +
 include/uapi/linux/sed-opal.h |   8 +-
 4 files changed, 183 insertions(+), 3 deletions(-)
diff --git a/block/Kconfig b/block/Kconfig
index 444c5ab3b67e..b46f93ac8405 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -181,6 +181,7 @@ config BLK_DEBUG_FS_ZONED
 
 config BLK_SED_OPAL
 	bool "Logic for interfacing with Opal enabled SEDs"
+	depends on KEYS
 	help
 	Builds Logic for interfacing with Opal enabled controllers.
 	Enabling this option enables users to setup/unlock/lock
diff --git a/block/sed-opal.c b/block/sed-opal.c
index 993b2b7cc4c2..a8729892178b 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -20,6 +20,9 @@
 #include <linux/sed-opal.h>
 #include <linux/string.h>
 #include <linux/kdev_t.h>
+#include <linux/key.h>
+#include <linux/key-type.h>
+#include <keys/user-type.h>
 
 #include "opal_proto.h"
 
@@ -29,6 +32,8 @@
 /* Number of bytes needed by cmd_finalize. */
 #define CMD_FINALIZE_BYTES_NEEDED 7
 
+static struct key *sed_opal_keyring;
+
 struct opal_step {
 	int (*fn)(struct opal_dev *dev, void *data);
 	void *data;
@@ -265,6 +270,101 @@ static void print_buffer(const u8 *ptr, u32 length)
 #endif
 }
 
+/*
+ * Allocate/update a SED Opal key and add it to the SED Opal keyring.
+ */
+static int update_sed_opal_key(const char *desc, u_char *key_data, int keylen)
+{
+	key_ref_t kr;
+
+	if (!sed_opal_keyring)
+		return -ENOKEY;
+
+	kr = key_create_or_update(make_key_ref(sed_opal_keyring, true), "user",
+				  desc, (const void *)key_data, keylen,
+				  KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_WRITE,
+				  KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN |
+					KEY_ALLOC_BYPASS_RESTRICTION);
+	if (IS_ERR(kr)) {
+		pr_err("Error adding SED key (%ld)\n", PTR_ERR(kr));
+		return PTR_ERR(kr);
+	}
+
+	return 0;
+}
+
+/*
+ * Read a SED Opal key from the SED Opal keyring.
+ */
+static int read_sed_opal_key(const char *key_name, u_char *buffer, int buflen)
+{
+	int ret;
+	key_ref_t kref;
+	struct key *key;
+
+	if (!sed_opal_keyring)
+		return -ENOKEY;
+
+	kref = keyring_search(make_key_ref(sed_opal_keyring, true),
+			      &key_type_user, key_name, true);
+
+	if (IS_ERR(kref))
+		ret = PTR_ERR(kref);
+
+	key = key_ref_to_ptr(kref);
+	down_read(&key->sem);
+	ret = key_validate(key);
+	if (ret == 0) {
+		if (buflen > key->datalen)
+			buflen = key->datalen;
+
+		ret = key->type->read(key, (char *)buffer, buflen);
+	}
+	up_read(&key->sem);
+
+	key_ref_put(kref);
+
+	return ret;
+}
+
+static int opal_get_key(struct opal_dev *dev, struct opal_key *key)
+{
+	int ret = 0;
+
+	switch (key->key_type) {
+	case OPAL_INCLUDED:
+		/* the key is ready to use */
+		break;
+	case OPAL_KEYRING:
+		/* the key is in the keyring */
+		ret = read_sed_opal_key(OPAL_AUTH_KEY, key->key, OPAL_KEY_MAX);
+		if (ret > 0) {
+			if (ret > 255) {
+				ret = -ENOSPC;
+				goto error;
+			}
+			key->key_len = ret;
+			key->key_type = OPAL_INCLUDED;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret < 0)
+		goto error;
+
+	/* must have a PEK by now or it's an error */
+	if (key->key_type != OPAL_INCLUDED || key->key_len == 0) {
+		ret = -EINVAL;
+		goto error;
+	}
+	return 0;
+error:
+	pr_debug("Error getting password: %d\n", ret);
+	return ret;
+}
+
 static bool check_tper(const void *data)
 {
 	const struct d0_tper_features *tper = data;
@@ -2269,6 +2369,9 @@ static int opal_secure_erase_locking_range(struct opal_dev *dev,
 	};
 	int ret;
 
+	ret = opal_get_key(dev, &opal_session->opal_key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2302,6 +2405,9 @@ static int opal_revertlsp(struct opal_dev *dev, struct opal_revert_lsp *rev)
 	};
 	int ret;
 
+	ret = opal_get_key(dev, &rev->key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
@@ -2320,6 +2426,9 @@ static int opal_erase_locking_range(struct opal_dev *dev,
 	};
 	int ret;
 
+	ret = opal_get_key(dev, &opal_session->opal_key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2348,6 +2457,9 @@ static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
 	    opal_mbr->enable_disable != OPAL_MBR_DISABLE)
 		return -EINVAL;
 
+	ret = opal_get_key(dev, &opal_mbr->key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
@@ -2373,6 +2485,9 @@ static int opal_set_mbr_done(struct opal_dev *dev,
 	    mbr_done->done_flag != OPAL_MBR_NOT_DONE)
 		return -EINVAL;
 
+	ret = opal_get_key(dev, &mbr_done->key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
@@ -2394,6 +2509,9 @@ static int opal_write_shadow_mbr(struct opal_dev *dev,
 	if (info->size == 0)
 		return 0;
 
+	ret = opal_get_key(dev, &info->key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
@@ -2450,6 +2568,9 @@ static int opal_add_user_to_lr(struct opal_dev *dev,
 		return -EINVAL;
 	}
 
+	ret = opal_get_key(dev, &lk_unlk->session.opal_key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
@@ -2472,6 +2593,10 @@ static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal, bool psi
 
 	int ret;
 
+	ret = opal_get_key(dev, opal);
+
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	if (psid)
@@ -2534,6 +2659,9 @@ static int opal_lock_unlock(struct opal_dev *dev,
 	if (lk_unlk->session.who > OPAL_USER9)
 		return -EINVAL;
 
+	ret = opal_get_key(dev, &lk_unlk->session.opal_key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	ret = __opal_lock_unlock(dev, lk_unlk);
 	mutex_unlock(&dev->dev_lock);
@@ -2556,6 +2684,9 @@ static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
 	if (!dev)
 		return -ENODEV;
 
+	ret = opal_get_key(dev, opal);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps));
@@ -2578,6 +2709,9 @@ static int opal_activate_lsp(struct opal_dev *dev,
 	if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
 		return -EINVAL;
 
+	ret = opal_get_key(dev, &opal_lr_act->key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps));
@@ -2596,6 +2730,9 @@ static int opal_setup_locking_range(struct opal_dev *dev,
 	};
 	int ret;
 
+	ret = opal_get_key(dev, &opal_lrs->session.opal_key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
@@ -2622,6 +2759,14 @@ static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
 	ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
 	mutex_unlock(&dev->dev_lock);
 
+	if (ret)
+		return ret;
+
+	/* update keyring with new password */
+	ret = update_sed_opal_key(OPAL_AUTH_KEY,
+				  opal_pw->new_user_pw.opal_key.key,
+				  opal_pw->new_user_pw.opal_key.key_len);
+
 	return ret;
 }
 
@@ -2642,6 +2787,9 @@ static int opal_activate_user(struct opal_dev *dev,
 		return -EINVAL;
 	}
 
+	ret = opal_get_key(dev, &opal_session->opal_key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 	ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps));
@@ -2728,6 +2876,9 @@ static int opal_generic_read_write_table(struct opal_dev *dev,
 {
 	int ret, bit_set;
 
+	ret = opal_get_key(dev, &rw_tbl->key);
+	if (ret)
+		return ret;
 	mutex_lock(&dev->dev_lock);
 	setup_opal_dev(dev);
 
@@ -2776,9 +2927,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 	if (!dev)
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 	if (!(dev->flags & OPAL_FL_SUPPORTED))
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
 
 	if (cmd & IOC_IN) {
 		p = memdup_user(arg, _IOC_SIZE(cmd));
@@ -2854,3 +3005,22 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
 	return ret;
 }
 EXPORT_SYMBOL_GPL(sed_ioctl);
+
+static int __init sed_opal_init(void)
+{
+	struct key *kr;
+
+	kr = keyring_alloc(".sed_opal",
+			   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
+			   (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW |
+			   KEY_USR_READ | KEY_USR_SEARCH | KEY_USR_WRITE,
+			   KEY_ALLOC_NOT_IN_QUOTA,
+			   NULL, NULL);
+	if (IS_ERR(kr))
+		return PTR_ERR(kr);
+
+	sed_opal_keyring = kr;
+
+	return 0;
+}
+late_initcall(sed_opal_init);
diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
index 7131d7f0eec2..57d483506b4a 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -24,6 +24,9 @@ bool opal_unlock_from_suspend(struct opal_dev *dev);
 struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv);
 int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *ioctl_ptr);
 
+#define	OPAL_AUTH_KEY           "opal-boot-pin"
+#define	OPAL_AUTH_KEY_PREV      "opal-boot-pin-prev"
+
 static inline bool is_sed_ioctl(unsigned int cmd)
 {
 	switch (cmd) {
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
index fccde168e90c..6b79cdcf9518 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -44,10 +44,16 @@ enum opal_lock_state {
 	OPAL_LK = 0x04, /* 0100 */
 };
 
+enum opal_key_type {
+	OPAL_INCLUDED = 0,	/* key[] is the key */
+	OPAL_KEYRING,		/* key is in keyring */
+};
+
 struct opal_key {
 	__u8 lr;
 	__u8 key_len;
-	__u8 __align[6];
+	__u8 key_type;
+	__u8 __align[5];
 	__u8 key[OPAL_KEY_MAX];
 };
 
-- 
gjoyce@linux.vnet.ibm.com

Re: [PATCH v3 1/3] block: sed-opal: Implement IOC_OPAL_DISCOVERY

From: Hannes Reinecke <hare@suse.de>
Date: 2022-11-30 06:52:47

On 11/30/22 00:25, gjoyce@linux.vnet.ibm.com wrote:
From: Greg Joyce <redacted>

Add IOC_OPAL_DISCOVERY ioctl to return raw discovery data to a SED Opal
application. This allows the application to display drive capabilities
and state.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
  block/sed-opal.c              | 38 ++++++++++++++++++++++++++++++++---
  include/linux/sed-opal.h      |  1 +
  include/uapi/linux/sed-opal.h |  6 ++++++
  3 files changed, 42 insertions(+), 3 deletions(-)
Reviewed-by: Hannes Reinecke <hare@suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare@suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman

Re: [PATCH v3 2/3] block: sed-opal: Implement IOC_OPAL_REVERT_LSP

From: Hannes Reinecke <hare@suse.de>
Date: 2022-11-30 06:53:37

On 11/30/22 00:25, gjoyce@linux.vnet.ibm.com wrote:
From: Greg Joyce <redacted>

This is used in conjunction with IOC_OPAL_REVERT_TPR to return a drive to
Original Factory State without erasing the data. If IOC_OPAL_REVERT_LSP
is called with opal_revert_lsp.options bit OPAL_PRESERVE set prior
to calling IOC_OPAL_REVERT_TPR, the drive global locking range will not
be erased.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
  block/opal_proto.h            |  4 ++++
  block/sed-opal.c              | 40 +++++++++++++++++++++++++++++++++++
  include/linux/sed-opal.h      |  1 +
  include/uapi/linux/sed-opal.h | 11 ++++++++++
  4 files changed, 56 insertions(+)
Reviewed-by: Hannes Reinecke <hare@suse.de>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare@suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Hannes Reinecke <hare@suse.de>
Date: 2022-11-30 07:00:48

On 11/30/22 00:25, gjoyce@linux.vnet.ibm.com wrote:
quoted hunk
From: Greg Joyce <redacted>

Extend the SED block driver so it can alternatively
obtain a key from a sed-opal kernel keyring. The SED
ioctls will indicate the source of the key, either
directly in the ioctl data or from the keyring.

This allows the use of SED commands in scripts such as
udev scripts so that drives may be automatically unlocked
as they become available.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
  block/Kconfig                 |   1 +
  block/sed-opal.c              | 174 +++++++++++++++++++++++++++++++++-
  include/linux/sed-opal.h      |   3 +
  include/uapi/linux/sed-opal.h |   8 +-
  4 files changed, 183 insertions(+), 3 deletions(-)
diff --git a/block/Kconfig b/block/Kconfig
index 444c5ab3b67e..b46f93ac8405 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -181,6 +181,7 @@ config BLK_DEBUG_FS_ZONED
  
  config BLK_SED_OPAL
  	bool "Logic for interfacing with Opal enabled SEDs"
+	depends on KEYS
  	help
  	Builds Logic for interfacing with Opal enabled controllers.
  	Enabling this option enables users to setup/unlock/lock
diff --git a/block/sed-opal.c b/block/sed-opal.c
index 993b2b7cc4c2..a8729892178b 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -20,6 +20,9 @@
  #include <linux/sed-opal.h>
  #include <linux/string.h>
  #include <linux/kdev_t.h>
+#include <linux/key.h>
+#include <linux/key-type.h>
+#include <keys/user-type.h>
  
  #include "opal_proto.h"
  
@@ -29,6 +32,8 @@
  /* Number of bytes needed by cmd_finalize. */
  #define CMD_FINALIZE_BYTES_NEEDED 7
  
+static struct key *sed_opal_keyring;
+
  struct opal_step {
  	int (*fn)(struct opal_dev *dev, void *data);
  	void *data;
@@ -265,6 +270,101 @@ static void print_buffer(const u8 *ptr, u32 length)
  #endif
  }
  
+/*
+ * Allocate/update a SED Opal key and add it to the SED Opal keyring.
+ */
+static int update_sed_opal_key(const char *desc, u_char *key_data, int keylen)
+{
+	key_ref_t kr;
+
+	if (!sed_opal_keyring)
+		return -ENOKEY;
+
+	kr = key_create_or_update(make_key_ref(sed_opal_keyring, true), "user",
+				  desc, (const void *)key_data, keylen,
+				  KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_WRITE,
+				  KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_BUILT_IN |
+					KEY_ALLOC_BYPASS_RESTRICTION);
+	if (IS_ERR(kr)) {
+		pr_err("Error adding SED key (%ld)\n", PTR_ERR(kr));
+		return PTR_ERR(kr);
+	}
+
+	return 0;
+}
+
+/*
+ * Read a SED Opal key from the SED Opal keyring.
+ */
+static int read_sed_opal_key(const char *key_name, u_char *buffer, int buflen)
+{
+	int ret;
+	key_ref_t kref;
+	struct key *key;
+
+	if (!sed_opal_keyring)
+		return -ENOKEY;
+
+	kref = keyring_search(make_key_ref(sed_opal_keyring, true),
+			      &key_type_user, key_name, true);
+
+	if (IS_ERR(kref))
+		ret = PTR_ERR(kref);
+
+	key = key_ref_to_ptr(kref);
+	down_read(&key->sem);
+	ret = key_validate(key);
+	if (ret == 0) {
+		if (buflen > key->datalen)
+			buflen = key->datalen;
+
+		ret = key->type->read(key, (char *)buffer, buflen);
+	}
+	up_read(&key->sem);
+
+	key_ref_put(kref);
+
+	return ret;
+}
+
+static int opal_get_key(struct opal_dev *dev, struct opal_key *key)
+{
+	int ret = 0;
+
+	switch (key->key_type) {
+	case OPAL_INCLUDED:
+		/* the key is ready to use */
+		break;
+	case OPAL_KEYRING:
+		/* the key is in the keyring */
+		ret = read_sed_opal_key(OPAL_AUTH_KEY, key->key, OPAL_KEY_MAX);
+		if (ret > 0) {
+			if (ret > 255) {
Why is a key longer than 255 an error?
If this is a requirement, why not move the check into
read_sed_opal_key() such that one only has to check for
ret < 0 on errors?
quoted hunk
+				ret = -ENOSPC;
+				goto error;
+			}
+			key->key_len = ret;
+			key->key_type = OPAL_INCLUDED;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret < 0)
+		goto error;
+
+	/* must have a PEK by now or it's an error */
+	if (key->key_type != OPAL_INCLUDED || key->key_len == 0) {
+		ret = -EINVAL;
+		goto error;
+	}
+	return 0;
+error:
+	pr_debug("Error getting password: %d\n", ret);
+	return ret;
+}
+
  static bool check_tper(const void *data)
  {
  	const struct d0_tper_features *tper = data;
@@ -2269,6 +2369,9 @@ static int opal_secure_erase_locking_range(struct opal_dev *dev,
  	};
  	int ret;
  
+	ret = opal_get_key(dev, &opal_session->opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2302,6 +2405,9 @@ static int opal_revertlsp(struct opal_dev *dev, struct opal_revert_lsp *rev)
  	};
  	int ret;
  
+	ret = opal_get_key(dev, &rev->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
@@ -2320,6 +2426,9 @@ static int opal_erase_locking_range(struct opal_dev *dev,
  	};
  	int ret;
  
+	ret = opal_get_key(dev, &opal_session->opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2348,6 +2457,9 @@ static int opal_enable_disable_shadow_mbr(struct opal_dev *dev,
  	    opal_mbr->enable_disable != OPAL_MBR_DISABLE)
  		return -EINVAL;
  
+	ret = opal_get_key(dev, &opal_mbr->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
@@ -2373,6 +2485,9 @@ static int opal_set_mbr_done(struct opal_dev *dev,
  	    mbr_done->done_flag != OPAL_MBR_NOT_DONE)
  		return -EINVAL;
  
+	ret = opal_get_key(dev, &mbr_done->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
@@ -2394,6 +2509,9 @@ static int opal_write_shadow_mbr(struct opal_dev *dev,
  	if (info->size == 0)
  		return 0;
  
+	ret = opal_get_key(dev, &info->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
@@ -2450,6 +2568,9 @@ static int opal_add_user_to_lr(struct opal_dev *dev,
  		return -EINVAL;
  	}
  
+	ret = opal_get_key(dev, &lk_unlk->session.opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
@@ -2472,6 +2593,10 @@ static int opal_reverttper(struct opal_dev *dev, struct opal_key *opal, bool psi
  
  	int ret;
  
+	ret = opal_get_key(dev, opal);
+
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	if (psid)
@@ -2534,6 +2659,9 @@ static int opal_lock_unlock(struct opal_dev *dev,
  	if (lk_unlk->session.who > OPAL_USER9)
  		return -EINVAL;
  
+	ret = opal_get_key(dev, &lk_unlk->session.opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	ret = __opal_lock_unlock(dev, lk_unlk);
  	mutex_unlock(&dev->dev_lock);
@@ -2556,6 +2684,9 @@ static int opal_take_ownership(struct opal_dev *dev, struct opal_key *opal)
  	if (!dev)
  		return -ENODEV;
  
+	ret = opal_get_key(dev, opal);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps));
@@ -2578,6 +2709,9 @@ static int opal_activate_lsp(struct opal_dev *dev,
  	if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs > OPAL_MAX_LRS)
  		return -EINVAL;
  
+	ret = opal_get_key(dev, &opal_lr_act->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, active_steps, ARRAY_SIZE(active_steps));
@@ -2596,6 +2730,9 @@ static int opal_setup_locking_range(struct opal_dev *dev,
  	};
  	int ret;
  
+	ret = opal_get_key(dev, &opal_lrs->session.opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
@@ -2622,6 +2759,14 @@ static int opal_set_new_pw(struct opal_dev *dev, struct opal_new_pw *opal_pw)
  	ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
  	mutex_unlock(&dev->dev_lock);
  
+	if (ret)
+		return ret;
+
+	/* update keyring with new password */
+	ret = update_sed_opal_key(OPAL_AUTH_KEY,
+				  opal_pw->new_user_pw.opal_key.key,
+				  opal_pw->new_user_pw.opal_key.key_len);
+
  	return ret;
  }
  
What about key revocation?
You only allow to set a new key, but what happens with the old ones?
quoted hunk
@@ -2642,6 +2787,9 @@ static int opal_activate_user(struct opal_dev *dev,
  		return -EINVAL;
  	}
  
+	ret = opal_get_key(dev, &opal_session->opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps));
@@ -2728,6 +2876,9 @@ static int opal_generic_read_write_table(struct opal_dev *dev,
  {
  	int ret, bit_set;
  
+	ret = opal_get_key(dev, &rw_tbl->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  
@@ -2776,9 +2927,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
  	if (!dev)
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
  	if (!(dev->flags & OPAL_FL_SUPPORTED))
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
  
  	if (cmd & IOC_IN) {
  		p = memdup_user(arg, _IOC_SIZE(cmd));
@@ -2854,3 +3005,22 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *arg)
  	return ret;
  }
  EXPORT_SYMBOL_GPL(sed_ioctl);
+
+static int __init sed_opal_init(void)
+{
+	struct key *kr;
+
+	kr = keyring_alloc(".sed_opal",
+			   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
+			   (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW |
+			   KEY_USR_READ | KEY_USR_SEARCH | KEY_USR_WRITE,
+			   KEY_ALLOC_NOT_IN_QUOTA,
+			   NULL, NULL);
+	if (IS_ERR(kr))
+		return PTR_ERR(kr);
+
+	sed_opal_keyring = kr;
+
+	return 0;
+}
+late_initcall(sed_opal_init);
Shouldn't you free the keyring on exit?
quoted hunk
diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
index 7131d7f0eec2..57d483506b4a 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -24,6 +24,9 @@ bool opal_unlock_from_suspend(struct opal_dev *dev);
  struct opal_dev *init_opal_dev(void *data, sec_send_recv *send_recv);
  int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user *ioctl_ptr);
  
+#define	OPAL_AUTH_KEY           "opal-boot-pin"
+#define	OPAL_AUTH_KEY_PREV      "opal-boot-pin-prev"
+
  static inline bool is_sed_ioctl(unsigned int cmd)
  {
  	switch (cmd) {
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
index fccde168e90c..6b79cdcf9518 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -44,10 +44,16 @@ enum opal_lock_state {
  	OPAL_LK = 0x04, /* 0100 */
  };
  
+enum opal_key_type {
+	OPAL_INCLUDED = 0,	/* key[] is the key */
+	OPAL_KEYRING,		/* key is in keyring */
+};
+
  struct opal_key {
  	__u8 lr;
  	__u8 key_len;
-	__u8 __align[6];
+	__u8 key_type;
+	__u8 __align[5];
  	__u8 key[OPAL_KEY_MAX];
  };
  
Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare@suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Greg Joyce <hidden>
Date: 2022-11-30 15:19:52

On Wed, 2022-11-30 at 08:00 +0100, Hannes Reinecke wrote:
On 11/30/22 00:25, gjoyce@linux.vnet.ibm.com wrote:
quoted
From: Greg Joyce <redacted>

Extend the SED block driver so it can alternatively
obtain a key from a sed-opal kernel keyring. The SED
ioctls will indicate the source of the key, either
directly in the ioctl data or from the keyring.

This allows the use of SED commands in scripts such as
udev scripts so that drives may be automatically unlocked
as they become available.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
  block/Kconfig                 |   1 +
  block/sed-opal.c              | 174
+++++++++++++++++++++++++++++++++-
  include/linux/sed-opal.h      |   3 +
  include/uapi/linux/sed-opal.h |   8 +-
  4 files changed, 183 insertions(+), 3 deletions(-)
diff --git a/block/Kconfig b/block/Kconfig
index 444c5ab3b67e..b46f93ac8405 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -181,6 +181,7 @@ config BLK_DEBUG_FS_ZONED
  
  config BLK_SED_OPAL
  	bool "Logic for interfacing with Opal enabled SEDs"
+	depends on KEYS
  	help
  	Builds Logic for interfacing with Opal enabled controllers.
  	Enabling this option enables users to setup/unlock/lock
diff --git a/block/sed-opal.c b/block/sed-opal.c
index 993b2b7cc4c2..a8729892178b 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -20,6 +20,9 @@
  #include <linux/sed-opal.h>
  #include <linux/string.h>
  #include <linux/kdev_t.h>
+#include <linux/key.h>
+#include <linux/key-type.h>
+#include <keys/user-type.h>
  
  #include "opal_proto.h"
  
@@ -29,6 +32,8 @@
  /* Number of bytes needed by cmd_finalize. */
  #define CMD_FINALIZE_BYTES_NEEDED 7
  
+static struct key *sed_opal_keyring;
+
  struct opal_step {
  	int (*fn)(struct opal_dev *dev, void *data);
  	void *data;
@@ -265,6 +270,101 @@ static void print_buffer(const u8 *ptr, u32
length)
  #endif
  }
  
+/*
+ * Allocate/update a SED Opal key and add it to the SED Opal
keyring.
+ */
+static int update_sed_opal_key(const char *desc, u_char *key_data,
int keylen)
+{
+	key_ref_t kr;
+
+	if (!sed_opal_keyring)
+		return -ENOKEY;
+
+	kr = key_create_or_update(make_key_ref(sed_opal_keyring, true),
"user",
+				  desc, (const void *)key_data, keylen,
+				  KEY_USR_VIEW | KEY_USR_SEARCH |
KEY_USR_WRITE,
+				  KEY_ALLOC_NOT_IN_QUOTA |
KEY_ALLOC_BUILT_IN |
+					KEY_ALLOC_BYPASS_RESTRICTION);
+	if (IS_ERR(kr)) {
+		pr_err("Error adding SED key (%ld)\n", PTR_ERR(kr));
+		return PTR_ERR(kr);
+	}
+
+	return 0;
+}
+
+/*
+ * Read a SED Opal key from the SED Opal keyring.
+ */
+static int read_sed_opal_key(const char *key_name, u_char *buffer,
int buflen)
+{
+	int ret;
+	key_ref_t kref;
+	struct key *key;
+
+	if (!sed_opal_keyring)
+		return -ENOKEY;
+
+	kref = keyring_search(make_key_ref(sed_opal_keyring, true),
+			      &key_type_user, key_name, true);
+
+	if (IS_ERR(kref))
+		ret = PTR_ERR(kref);
+
+	key = key_ref_to_ptr(kref);
+	down_read(&key->sem);
+	ret = key_validate(key);
+	if (ret == 0) {
+		if (buflen > key->datalen)
+			buflen = key->datalen;
+
+		ret = key->type->read(key, (char *)buffer, buflen);
+	}
+	up_read(&key->sem);
+
+	key_ref_put(kref);
+
+	return ret;
+}
+
+static int opal_get_key(struct opal_dev *dev, struct opal_key
*key)
+{
+	int ret = 0;
+
+	switch (key->key_type) {
+	case OPAL_INCLUDED:
+		/* the key is ready to use */
+		break;
+	case OPAL_KEYRING:
+		/* the key is in the keyring */
+		ret = read_sed_opal_key(OPAL_AUTH_KEY, key->key,
OPAL_KEY_MAX);
+		if (ret > 0) {
+			if (ret > 255) {
Why is a key longer than 255 an error?
If this is a requirement, why not move the check into
read_sed_opal_key() such that one only has to check for
ret < 0 on errors?
The check is done here because the SED Opal spec stipulates 255 as the
maximum key length. The key length (key->key_len) in the existing data
structures is __u8, so a length greater than 255 can not be conveyed.
For defensive purposes, I though it best to check here.
quoted
+				ret = -ENOSPC;
+				goto error;
+			}
+			key->key_len = ret;
+			key->key_type = OPAL_INCLUDED;
+		}
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	if (ret < 0)
+		goto error;
+
+	/* must have a PEK by now or it's an error */
+	if (key->key_type != OPAL_INCLUDED || key->key_len == 0) {
+		ret = -EINVAL;
+		goto error;
+	}
+	return 0;
+error:
+	pr_debug("Error getting password: %d\n", ret);
+	return ret;
+}
+
  static bool check_tper(const void *data)
  {
  	const struct d0_tper_features *tper = data;
@@ -2269,6 +2369,9 @@ static int
opal_secure_erase_locking_range(struct opal_dev *dev,
  	};
  	int ret;
  
+	ret = opal_get_key(dev, &opal_session->opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2302,6 +2405,9 @@ static int opal_revertlsp(struct opal_dev
*dev, struct opal_revert_lsp *rev)
  	};
  	int ret;
  
+	ret = opal_get_key(dev, &rev->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
@@ -2320,6 +2426,9 @@ static int opal_erase_locking_range(struct
opal_dev *dev,
  	};
  	int ret;
  
+	ret = opal_get_key(dev, &opal_session->opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2348,6 +2457,9 @@ static int
opal_enable_disable_shadow_mbr(struct opal_dev *dev,
  	    opal_mbr->enable_disable != OPAL_MBR_DISABLE)
  		return -EINVAL;
  
+	ret = opal_get_key(dev, &opal_mbr->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
@@ -2373,6 +2485,9 @@ static int opal_set_mbr_done(struct opal_dev
*dev,
  	    mbr_done->done_flag != OPAL_MBR_NOT_DONE)
  		return -EINVAL;
  
+	ret = opal_get_key(dev, &mbr_done->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
@@ -2394,6 +2509,9 @@ static int opal_write_shadow_mbr(struct
opal_dev *dev,
  	if (info->size == 0)
  		return 0;
  
+	ret = opal_get_key(dev, &info->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, mbr_steps, ARRAY_SIZE(mbr_steps));
@@ -2450,6 +2568,9 @@ static int opal_add_user_to_lr(struct
opal_dev *dev,
  		return -EINVAL;
  	}
  
+	ret = opal_get_key(dev, &lk_unlk->session.opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
@@ -2472,6 +2593,10 @@ static int opal_reverttper(struct opal_dev
*dev, struct opal_key *opal, bool psi
  
  	int ret;
  
+	ret = opal_get_key(dev, opal);
+
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	if (psid)
@@ -2534,6 +2659,9 @@ static int opal_lock_unlock(struct opal_dev
*dev,
  	if (lk_unlk->session.who > OPAL_USER9)
  		return -EINVAL;
  
+	ret = opal_get_key(dev, &lk_unlk->session.opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	ret = __opal_lock_unlock(dev, lk_unlk);
  	mutex_unlock(&dev->dev_lock);
@@ -2556,6 +2684,9 @@ static int opal_take_ownership(struct
opal_dev *dev, struct opal_key *opal)
  	if (!dev)
  		return -ENODEV;
  
+	ret = opal_get_key(dev, opal);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, owner_steps, ARRAY_SIZE(owner_steps));
@@ -2578,6 +2709,9 @@ static int opal_activate_lsp(struct opal_dev
*dev,
  	if (!opal_lr_act->num_lrs || opal_lr_act->num_lrs >
OPAL_MAX_LRS)
  		return -EINVAL;
  
+	ret = opal_get_key(dev, &opal_lr_act->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, active_steps,
ARRAY_SIZE(active_steps));
@@ -2596,6 +2730,9 @@ static int opal_setup_locking_range(struct
opal_dev *dev,
  	};
  	int ret;
  
+	ret = opal_get_key(dev, &opal_lrs->session.opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
@@ -2622,6 +2759,14 @@ static int opal_set_new_pw(struct opal_dev
*dev, struct opal_new_pw *opal_pw)
  	ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
  	mutex_unlock(&dev->dev_lock);
  
+	if (ret)
+		return ret;
+
+	/* update keyring with new password */
+	ret = update_sed_opal_key(OPAL_AUTH_KEY,
+				  opal_pw->new_user_pw.opal_key.key,
+				  opal_pw-
quoted
new_user_pw.opal_key.key_len);
+
  	return ret;
  }
  
What about key revocation?
You only allow to set a new key, but what happens with the old ones?
quoted
@@ -2642,6 +2787,9 @@ static int opal_activate_user(struct opal_dev
*dev,
  		return -EINVAL;
  	}
  
+	ret = opal_get_key(dev, &opal_session->opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, act_steps, ARRAY_SIZE(act_steps));
@@ -2728,6 +2876,9 @@ static int
opal_generic_read_write_table(struct opal_dev *dev,
  {
  	int ret, bit_set;
  
+	ret = opal_get_key(dev, &rw_tbl->key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  
@@ -2776,9 +2927,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned
int cmd, void __user *arg)
  	if (!capable(CAP_SYS_ADMIN))
  		return -EACCES;
  	if (!dev)
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
  	if (!(dev->flags & OPAL_FL_SUPPORTED))
-		return -ENOTSUPP;
+		return -EOPNOTSUPP;
  
  	if (cmd & IOC_IN) {
  		p = memdup_user(arg, _IOC_SIZE(cmd));
@@ -2854,3 +3005,22 @@ int sed_ioctl(struct opal_dev *dev, unsigned
int cmd, void __user *arg)
  	return ret;
  }
  EXPORT_SYMBOL_GPL(sed_ioctl);
+
+static int __init sed_opal_init(void)
+{
+	struct key *kr;
+
+	kr = keyring_alloc(".sed_opal",
+			   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
current_cred(),
+			   (KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW |
+			   KEY_USR_READ | KEY_USR_SEARCH |
KEY_USR_WRITE,
+			   KEY_ALLOC_NOT_IN_QUOTA,
+			   NULL, NULL);
+	if (IS_ERR(kr))
+		return PTR_ERR(kr);
+
+	sed_opal_keyring = kr;
+
+	return 0;
+}
+late_initcall(sed_opal_init);
Shouldn't you free the keyring on exit?
quoted
diff --git a/include/linux/sed-opal.h b/include/linux/sed-opal.h
index 7131d7f0eec2..57d483506b4a 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -24,6 +24,9 @@ bool opal_unlock_from_suspend(struct opal_dev
*dev);
  struct opal_dev *init_opal_dev(void *data, sec_send_recv
*send_recv);
  int sed_ioctl(struct opal_dev *dev, unsigned int cmd, void __user
*ioctl_ptr);
  
+#define	OPAL_AUTH_KEY           "opal-boot-pin"
+#define	OPAL_AUTH_KEY_PREV      "opal-boot-pin-prev"
+
  static inline bool is_sed_ioctl(unsigned int cmd)
  {
  	switch (cmd) {
diff --git a/include/uapi/linux/sed-opal.h
b/include/uapi/linux/sed-opal.h
index fccde168e90c..6b79cdcf9518 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -44,10 +44,16 @@ enum opal_lock_state {
  	OPAL_LK = 0x04, /* 0100 */
  };
  
+enum opal_key_type {
+	OPAL_INCLUDED = 0,	/* key[] is the key */
+	OPAL_KEYRING,		/* key is in keyring */
+};
+
  struct opal_key {
  	__u8 lr;
  	__u8 key_len;
-	__u8 __align[6];
+	__u8 key_type;
+	__u8 __align[5];
  	__u8 key[OPAL_KEY_MAX];
  };
  
Cheers,

Hannes

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Ben Boeckel <hidden>
Date: 2022-12-01 03:47:51

On Wed, Nov 30, 2022 at 09:19:25 -0600, Greg Joyce wrote:
On Wed, 2022-11-30 at 08:00 +0100, Hannes Reinecke wrote:
quoted
On 11/30/22 00:25, gjoyce@linux.vnet.ibm.com wrote:
quoted
+	case OPAL_KEYRING:
+		/* the key is in the keyring */
+		ret = read_sed_opal_key(OPAL_AUTH_KEY, key->key,
OPAL_KEY_MAX);
+		if (ret > 0) {
+			if (ret > 255) {
Why is a key longer than 255 an error?
If this is a requirement, why not move the check into
read_sed_opal_key() such that one only has to check for
ret < 0 on errors?
The check is done here because the SED Opal spec stipulates 255 as the
maximum key length. The key length (key->key_len) in the existing data
structures is __u8, so a length greater than 255 can not be conveyed.
For defensive purposes, I though it best to check here.
Perhaps naming it `OPAL_MAX_KEY_LEN` would help clarify this?

--Ben

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Greg Joyce <hidden>
Date: 2022-12-01 15:36:26

On Wed, 2022-11-30 at 22:46 -0500, Ben Boeckel wrote:
On Wed, Nov 30, 2022 at 09:19:25 -0600, Greg Joyce wrote:
quoted
On Wed, 2022-11-30 at 08:00 +0100, Hannes Reinecke wrote:
quoted
On 11/30/22 00:25, gjoyce@linux.vnet.ibm.com wrote:
quoted
+	case OPAL_KEYRING:
+		/* the key is in the keyring */
+		ret = read_sed_opal_key(OPAL_AUTH_KEY, key-
quoted
key,
OPAL_KEY_MAX);
+		if (ret > 0) {
+			if (ret > 255) {
Why is a key longer than 255 an error?
If this is a requirement, why not move the check into
read_sed_opal_key() such that one only has to check for
ret < 0 on errors?
The check is done here because the SED Opal spec stipulates 255 as
the
maximum key length. The key length (key->key_len) in the existing
data
structures is __u8, so a length greater than 255 can not be
conveyed.
For defensive purposes, I though it best to check here.
Perhaps naming it `OPAL_MAX_KEY_LEN` would help clarify this?

--Ben
I'm not averse to changing it because it would be clearer. My concern
is that it's been OPAL_KEY_MAX for 5+ years (the original SED Opal
commit). Unless there is strong consensus to change it, I'm going to
leave it as the original name.

-Greg

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Ben Boeckel <hidden>
Date: 2022-12-01 16:13:15

On Thu, Dec 01, 2022 at 09:29:36 -0600, Greg Joyce wrote:
On Wed, 2022-11-30 at 22:46 -0500, Ben Boeckel wrote:
quoted
Perhaps naming it `OPAL_MAX_KEY_LEN` would help clarify this?
I'm not averse to changing it because it would be clearer. My concern
is that it's been OPAL_KEY_MAX for 5+ years (the original SED Opal
commit). Unless there is strong consensus to change it, I'm going to
leave it as the original name.
I don't care about the name (very much in the peanut gallery), just it
not being a magic number :) .

--Ben

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Greg Joyce <hidden>
Date: 2022-12-01 16:58:48

On Thu, 2022-12-01 at 11:12 -0500, Ben Boeckel wrote:
On Thu, Dec 01, 2022 at 09:29:36 -0600, Greg Joyce wrote:
quoted
On Wed, 2022-11-30 at 22:46 -0500, Ben Boeckel wrote:
quoted
Perhaps naming it `OPAL_MAX_KEY_LEN` would help clarify this?
I'm not averse to changing it because it would be clearer. My
concern
is that it's been OPAL_KEY_MAX for 5+ years (the original SED Opal
commit). Unless there is strong consensus to change it, I'm going
to
leave it as the original name.
I don't care about the name (very much in the peanut gallery), just
it
not being a magic number :) .

--Ben
Now I get you! I think that you mean changing to this:

                if (ret > 0) {
                        if (ret > sizeof(key->key_len)) {
                                ret = -ENOSPC;
                                goto error;
                        }
                        key->key_len = ret;
                        key->key_type = OPAL_INCLUDED;
                }

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Greg Joyce <hidden>
Date: 2022-12-01 17:01:28

On Thu, 2022-12-01 at 10:58 -0600, Greg Joyce wrote:
On Thu, 2022-12-01 at 11:12 -0500, Ben Boeckel wrote:
quoted
On Thu, Dec 01, 2022 at 09:29:36 -0600, Greg Joyce wrote:
quoted
On Wed, 2022-11-30 at 22:46 -0500, Ben Boeckel wrote:
quoted
Perhaps naming it `OPAL_MAX_KEY_LEN` would help clarify this?
I'm not averse to changing it because it would be clearer. My
concern
is that it's been OPAL_KEY_MAX for 5+ years (the original SED
Opal
commit). Unless there is strong consensus to change it, I'm going
to
leave it as the original name.
I don't care about the name (very much in the peanut gallery), just
it
not being a magic number :) .

--Ben
Now I get you! I think that you mean changing to this:

                if (ret > 0) {
                        if (ret > sizeof(key->key_len)) {
                                ret = -ENOSPC;
                                goto error;
                        }
                        key->key_len = ret;
                        key->key_type = OPAL_INCLUDED;
                }
Sorry, that's incorrect. I think that you just meant removing the 255.

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Greg Joyce <hidden>
Date: 2022-12-01 18:04:24

On Wed, 2022-11-30 at 08:00 +0100, Hannes Reinecke wrote:
On 11/30/22 00:25, gjoyce@linux.vnet.ibm.com wrote:
quoted
From: Greg Joyce <redacted>

Extend the SED block driver so it can alternatively
obtain a key from a sed-opal kernel keyring. The SED
ioctls will indicate the source of the key, either
directly in the ioctl data or from the keyring.

This allows the use of SED commands in scripts such as
udev scripts so that drives may be automatically unlocked
as they become available.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
  block/Kconfig                 |   1 +
  block/sed-opal.c              | 174
+++++++++++++++++++++++++++++++++-
  include/linux/sed-opal.h      |   3 +
  include/uapi/linux/sed-opal.h |   8 +-
  4 files changed, 183 insertions(+), 3 deletions(-)
 
+	ret = opal_get_key(dev, &opal_lrs->session.opal_key);
+	if (ret)
+		return ret;
  	mutex_lock(&dev->dev_lock);
  	setup_opal_dev(dev);
  	ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
@@ -2622,6 +2759,14 @@ static int opal_set_new_pw(struct opal_dev
*dev, struct opal_new_pw *opal_pw)
  	ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
  	mutex_unlock(&dev->dev_lock);
  
+	if (ret)
+		return ret;
+
+	/* update keyring with new password */
+	ret = update_sed_opal_key(OPAL_AUTH_KEY,
+				  opal_pw->new_user_pw.opal_key.key,
+				  opal_pw-
quoted
new_user_pw.opal_key.key_len);
+
  	return ret;
  }
  
What about key revocation?
You only allow to set a new key, but what happens with the old ones?
My understanding was that key_create_or_update() would not allow
duplicates so there shouldn't be old ones. Is that incorrect?
quoted
+static int __init sed_opal_init(void)
+{
+	struct key *kr;
+
+	kr = keyring_alloc(".sed_opal",
+			   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
current_cred(),
+			   (KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW |
+			   KEY_USR_READ | KEY_USR_SEARCH |
KEY_USR_WRITE,
+			   KEY_ALLOC_NOT_IN_QUOTA,
+			   NULL, NULL);
+	if (IS_ERR(kr))
+		return PTR_ERR(kr);
+
+	sed_opal_keyring = kr;
+
+	return 0;
+}
+late_initcall(sed_opal_init);
Shouldn't you free the keyring on exit?
The SED Opal driver is part of the block driver and does not build as a
module so it will not exit. I had looked at "blacklist" as an example
and saw that it allocated but did not free its keyring.
Cheers,

Hannes
Thanks for the comments on the keyring. I'm not very familiar with the
keyring code, so I'd appreciate suggestions on code changes if any are
needed for your two comments.

-Greg

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Hannes Reinecke <hare@suse.de>
Date: 2022-12-02 06:56:55

On 12/1/22 19:03, Greg Joyce wrote:
On Wed, 2022-11-30 at 08:00 +0100, Hannes Reinecke wrote:
quoted
On 11/30/22 00:25, gjoyce@linux.vnet.ibm.com wrote:
quoted
From: Greg Joyce <redacted>

Extend the SED block driver so it can alternatively
obtain a key from a sed-opal kernel keyring. The SED
ioctls will indicate the source of the key, either
directly in the ioctl data or from the keyring.

This allows the use of SED commands in scripts such as
udev scripts so that drives may be automatically unlocked
as they become available.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
   block/Kconfig                 |   1 +
   block/sed-opal.c              | 174
+++++++++++++++++++++++++++++++++-
   include/linux/sed-opal.h      |   3 +
   include/uapi/linux/sed-opal.h |   8 +-
   4 files changed, 183 insertions(+), 3 deletions(-)
  
+	ret = opal_get_key(dev, &opal_lrs->session.opal_key);
+	if (ret)
+		return ret;
   	mutex_lock(&dev->dev_lock);
   	setup_opal_dev(dev);
   	ret = execute_steps(dev, lr_steps, ARRAY_SIZE(lr_steps));
@@ -2622,6 +2759,14 @@ static int opal_set_new_pw(struct opal_dev
*dev, struct opal_new_pw *opal_pw)
   	ret = execute_steps(dev, pw_steps, ARRAY_SIZE(pw_steps));
   	mutex_unlock(&dev->dev_lock);
   
+	if (ret)
+		return ret;
+
+	/* update keyring with new password */
+	ret = update_sed_opal_key(OPAL_AUTH_KEY,
+				  opal_pw->new_user_pw.opal_key.key,
+				  opal_pw-
quoted
new_user_pw.opal_key.key_len);
+
   	return ret;
   }
   
What about key revocation?
You only allow to set a new key, but what happens with the old ones?
My understanding was that key_create_or_update() would not allow
duplicates so there shouldn't be old ones. Is that incorrect?
Ah, right, you only have one key.
But still, you might want to revoke that one, too, no?
(Think of decommissioning old drives ...)

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                Kernel Storage Architect
hare@suse.de                              +49 911 74053 688
SUSE Software Solutions GmbH, Maxfeldstr. 5, 90409 Nürnberg
HRB 36809 (AG Nürnberg), Geschäftsführer: Ivo Totev, Andrew
Myers, Andrew McDonald, Martje Boudien Moerman

Re: [PATCH v3 3/3] block: sed-opal: keyring support for SED keys

From: Greg Joyce <hidden>
Date: 2022-12-02 15:19:21

On Fri, 2022-12-02 at 07:56 +0100, Hannes Reinecke wrote:
On 12/1/22 19:03, Greg Joyce wrote:
quoted
On Wed, 2022-11-30 at 08:00 +0100, Hannes Reinecke wrote:
quoted
On 11/30/22 00:25, gjoyce@linux.vnet.ibm.com wrote:
quoted
From: Greg Joyce <redacted>

Extend the SED block driver so it can alternatively
obtain a key from a sed-opal kernel keyring. The SED
ioctls will indicate the source of the key, either
directly in the ioctl data or from the keyring.

This allows the use of SED commands in scripts such as
udev scripts so that drives may be automatically unlocked
as they become available.

Signed-off-by: Greg Joyce <redacted>
Reviewed-by: Jonathan Derrick <jonathan.derrick@linux.dev>
---
   block/Kconfig                 |   1 +
   block/sed-opal.c              | 174
+++++++++++++++++++++++++++++++++-
   include/linux/sed-opal.h      |   3 +
   include/uapi/linux/sed-opal.h |   8 +-
   4 files changed, 183 insertions(+), 3 deletions(-)
  
+	ret = opal_get_key(dev, &opal_lrs->session.opal_key);
+	if (ret)
+		return ret;
   	mutex_lock(&dev->dev_lock);
   	setup_opal_dev(dev);
   	ret = execute_steps(dev, lr_steps,
ARRAY_SIZE(lr_steps));
@@ -2622,6 +2759,14 @@ static int opal_set_new_pw(struct
opal_dev
*dev, struct opal_new_pw *opal_pw)
   	ret = execute_steps(dev, pw_steps,
ARRAY_SIZE(pw_steps));
   	mutex_unlock(&dev->dev_lock);
   
+	if (ret)
+		return ret;
+
+	/* update keyring with new password */
+	ret = update_sed_opal_key(OPAL_AUTH_KEY,
+				  opal_pw-
quoted
new_user_pw.opal_key.key,
+				  opal_pw-
quoted
new_user_pw.opal_key.key_len);
+
   	return ret;
   }
   
What about key revocation?
You only allow to set a new key, but what happens with the old
ones?
My understanding was that key_create_or_update() would not allow
duplicates so there shouldn't be old ones. Is that incorrect?
Ah, right, you only have one key.
But still, you might want to revoke that one, too, no?
(Think of decommissioning old drives ...)

Cheers,
 
Hannes
SED Opal allows for disabling locking on a SED drive. Both sedcli and
sedutil have commands to support this. This is the method for drive
decommisioning (un-provisioning). There is also a mechanism to
cryptographically erase the data on the drive if that is desired.

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help