[PATCH v8 0/3] generic and PowerPC SED Opal keystore

2023-10-04 Thread gjoyce
From: Greg Joyce 

This patchset has gone through numerous rounds of review and
all comments/suggetions have been addressed. The reviews have
covered all relevant areas including reviews by block and keyring
developers as well as the SED Opal maintainer.

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.

PowerPC/pseries versions of key functions provide read/write access
to SED Opal keys in the PLPKS keystore.

The SED block driver has been modified to read the SED Opal
keystore to populate a key in the SED Opal keyring. Changes to the
SED Opal key will be written to the SED Opal keystore.


Changelog
v8: - rebased to 6.6-rc4
- fixed issues using clang (thanks Nathan Chancellor and Nick
  Desaulniers)
- fixed crash if PLPKS is not present for pseries (thanks Michael
  Ellerman)

v7: - rebased to for-6.5/block

v6: - squashed two commits (suggested by Andrew Donnellan)

v5: - updated to reflect changes in PLPKS API

v4:
- scope reduced to cover just SED Opal keys
- base SED Opal keystore is now in SED block driver
- removed use of enum to indicate type
- refactored common code into common function that read and
  write use
- removed cast to void
- added use of SED Opal keystore functions to SED block driver

v3:
- No code changes, but per reviewer requests, adding additional
  mailing lists(keyring, EFI) for wider review.

v2:
- Include feedback from Gregory Joyce, Eric Richter and
  Murilo Opsfelder Araujo.
- Include suggestions from Michael Ellerman.
- Moved a dependency from generic SED code to this patchset.
  This patchset now builds of its own.




Greg Joyce (3):
  block:sed-opal: SED Opal keystore
  block: sed-opal: keystore access for SED Opal keys
  powerpc/pseries: PLPKS SED Opal keystore support

 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 131 ++
 block/Kconfig |   1 +
 block/sed-opal.c  |  18 ++-
 include/linux/sed-opal-key.h  |  26 
 6 files changed, 181 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c
 create mode 100644 include/linux/sed-opal-key.h

-- 
gjo...@linux.vnet.ibm.com



[PATCH v8 1/3] block:sed-opal: SED Opal keystore

2023-10-04 Thread gjoyce
From: Greg Joyce 

Add read and write functions that allow SED Opal keys to stored
in a permanent keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 include/linux/sed-opal-key.h | 26 ++
 1 file changed, 26 insertions(+)
 create mode 100644 include/linux/sed-opal-key.h

diff --git a/include/linux/sed-opal-key.h b/include/linux/sed-opal-key.h
new file mode 100644
index ..0ca03054e8f6
--- /dev/null
+++ b/include/linux/sed-opal-key.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2023 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+
+#ifdef CONFIG_PSERIES_PLPKS_SED
+int sed_read_key(char *keyname, char *key, u_int *keylen);
+int sed_write_key(char *keyname, char *key, u_int keylen);
+#else
+static inline
+int sed_read_key(char *keyname, char *key, u_int *keylen) {
+   return -EOPNOTSUPP;
+}
+static inline
+int sed_write_key(char *keyname, char *key, u_int keylen) {
+   return -EOPNOTSUPP;
+}
+#endif
-- 
gjo...@linux.vnet.ibm.com



[PATCH v8 3/3] powerpc/pseries: PLPKS SED Opal keystore support

2023-10-04 Thread gjoyce
From: Greg Joyce 

Define operations for SED Opal to read/write keys
from POWER LPAR Platform KeyStore(PLPKS). This allows
non-volatile storage of SED Opal keys.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 131 ++
 block/Kconfig |   1 +
 4 files changed, 139 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c

diff --git a/arch/powerpc/platforms/pseries/Kconfig 
b/arch/powerpc/platforms/pseries/Kconfig
index 4ebf2ef2845d..afc0f6a61337 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -164,6 +164,12 @@ config PSERIES_PLPKS
# This option is selected by in-kernel consumers that require
# access to the PKS.
 
+config PSERIES_PLPKS_SED
+   depends on PPC_PSERIES
+   bool
+   # This option is selected by in-kernel consumers that require
+   # access to the SED PKS keystore.
+
 config PAPR_SCM
depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM
tristate "Support for the PAPR Storage Class Memory interface"
diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 53c3b91af2f7..1476c5e4433c 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_SVM) += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS)+= plpks.o
 obj-$(CONFIG_PPC_SECURE_BOOT)  += plpks-secvar.o
+obj-$(CONFIG_PSERIES_PLPKS_SED)+= plpks_sed_ops.o
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
 
diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c 
b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
new file mode 100644
index ..7c873c9589ef
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform specific code for non-volatile SED key access
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for SED Opal to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * Self Encrypting Drives(SED) key storage using PLPKS
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static bool plpks_sed_initialized = false;
+static bool plpks_sed_available = false;
+
+/*
+ * structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+#define PLPKS_SED_OBJECT_DATA_V00
+#define PLPKS_SED_MANGLED_LABEL "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+#define PLPKS_SED_KEY   "opal-boot-pin"
+
+/*
+ * authority is admin1 and range is global
+ */
+#define PLPKS_SED_AUTHORITY  0x000900010001
+#define PLPKS_SED_RANGE  0x08020001
+
+static void plpks_init_var(struct plpks_var *var, char *keyname)
+{
+   if (!plpks_sed_initialized) {
+   plpks_sed_initialized = true;
+   plpks_sed_available = plpks_is_available();
+   if (!plpks_sed_available)
+   pr_err("SED: plpks not available\n");
+   }
+
+   var->name = keyname;
+   var->namelen = strlen(keyname);
+   if (strcmp(PLPKS_SED_KEY, keyname) == 0) {
+   var->name = PLPKS_SED_MANGLED_LABEL;
+   var->namelen = strlen(keyname);
+   }
+   var->policy = PLPKS_WORLDREADABLE;
+   var->os = PLPKS_VAR_COMMON;
+   var->data = NULL;
+   var->datalen = 0;
+   var->component = PLPKS_SED_COMPONENT;
+}
+
+/*
+ * Read the SED Opal key from PLPKS given the label
+ */
+int sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   int ret;
+   u_int len;
+
+   plpks_init_var(, keyname);
+
+   if (!plpks_sed_available)
+   return -EOPNOTSUPP;
+
+   var.data = (u8 *)
+   var.datalen = sizeof(data);
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   len = min_t(u16, be32_to_cpu(data.key_len), var.datalen);
+   memcpy(key, data.key, len);
+   key[len] = '\0';
+   *keylen = len;
+
+   return 0;
+}
+
+/*
+ * Write the SED Opal key to PLPKS given the label
+ */
+int sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   plpks_init_var(, keyname);
+
+   if (!plpks_sed_available)
+   return -EOPNOTSUPP;
+
+   var.datalen = sizeof(struct plpks_sed_object_data);
+   

[PATCH v8 2/3] block: sed-opal: keystore access for SED Opal keys

2023-10-04 Thread gjoyce
From: Greg Joyce 

Allow for permanent SED authentication keys by
reading/writing to the SED Opal non-volatile keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/sed-opal.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/block/sed-opal.c b/block/sed-opal.c
index 6d7f25d1711b..fa23a6a60485 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -3019,7 +3020,13 @@ static int opal_set_new_pw(struct opal_dev *dev, struct 
opal_new_pw *opal_pw)
if (ret)
return ret;
 
-   /* update keyring with new password */
+   /* update keyring and key store with new password */
+   ret = sed_write_key(OPAL_AUTH_KEY,
+   opal_pw->new_user_pw.opal_key.key,
+   opal_pw->new_user_pw.opal_key.key_len);
+   if (ret != -EOPNOTSUPP)
+   pr_warn("error updating SED key: %d\n", ret);
+
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);
@@ -3292,6 +3299,8 @@ EXPORT_SYMBOL_GPL(sed_ioctl);
 static int __init sed_opal_init(void)
 {
struct key *kr;
+   char init_sed_key[OPAL_KEY_MAX];
+   int keylen = OPAL_KEY_MAX - 1;
 
kr = keyring_alloc(".sed_opal",
   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
@@ -3304,6 +3313,11 @@ static int __init sed_opal_init(void)
 
sed_opal_keyring = kr;
 
-   return 0;
+   if (sed_read_key(OPAL_AUTH_KEY, init_sed_key, ) < 0) {
+   memset(init_sed_key, '\0', sizeof(init_sed_key));
+   keylen = OPAL_KEY_MAX - 1;
+   }
+
+   return update_sed_opal_key(OPAL_AUTH_KEY, init_sed_key, keylen);
 }
 late_initcall(sed_opal_init);
-- 
gjo...@linux.vnet.ibm.com



[PATCH v7 0/3 RESEND] generic and PowerPC SED Opal keystore

2023-09-08 Thread gjoyce
From: Greg Joyce 

This patchset extends the capabilites incorporated into for-6.6/block
(https://git.kernel.dk/cgit/linux/commit/?h=for-6.6/block=3bfeb61256643281ac4be5b8a57e9d9da3db4335)
 by allowing the SED Opal key to be seeded into
the keyring from a secure permanent keystore.

It has gone through numerous rounds of review and all comments/suggetions
have been addressed. The reviews have covered all relevant areas including
reviews by block and keyring developers as well as the SED Opal
maintainer. The last patchset submission has not solicited any responses
in the six weeks since it was last distributed. The changes are
generally useful and ready for inclusion.

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.

Generic functions have been defined for accessing SED Opal keys.
The generic functions are defined as weak so that they may be superseded
by keystore specific versions.

PowerPC/pseries versions of these functions provide read/write access
to SED Opal keys in the PLPKS keystore.

The SED block driver has been modified to read the SED Opal
keystore to populate a key in the SED Opal keyring. Changes to the
SED Opal key will be written to the SED Opal keystore.

Changelog
v7: - rebased to for-6.5/block

v6: - squashed two commits (suggested by Andrew Donnellan)

v5: - updated to reflect changes in PLPKS API

v4:
- scope reduced to cover just SED Opal keys
- base SED Opal keystore is now in SED block driver
- removed use of enum to indicate type
- refactored common code into common function that read and
  write use
- removed cast to void
- added use of SED Opal keystore functions to SED block driver

v3:
- No code changes, but per reviewer requests, adding additional
  mailing lists(keyring, EFI) for wider review.

v2:
- Include feedback from Gregory Joyce, Eric Richter and
  Murilo Opsfelder Araujo.
- Include suggestions from Michael Ellerman.
- Moved a dependency from generic SED code to this patchset.
  This patchset now builds of its own.



Greg Joyce (3):
  block:sed-opal: SED Opal keystore
  block: sed-opal: keystore access for SED Opal keys
  powerpc/pseries: PLPKS SED Opal keystore support

 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 114 ++
 block/Kconfig |   1 +
 block/Makefile|   2 +-
 block/sed-opal-key.c  |  24 
 block/sed-opal.c  |  18 ++-
 include/linux/sed-opal-key.h  |  15 +++
 8 files changed, 178 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h


base-commit: 1341c7d2ccf42ed91aea80b8579d35bc1ea381e2
-- 
gjo...@linux.vnet.ibm.com



[PATCH v7 3/3 RESEND] powerpc/pseries: PLPKS SED Opal keystore support

2023-09-08 Thread gjoyce
From: Greg Joyce 

Define operations for SED Opal to read/write keys
from POWER LPAR Platform KeyStore(PLPKS). This allows
non-volatile storage of SED Opal keys.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
Reviewed-by: Hannes Reinecke 
---
 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 114 ++
 block/Kconfig |   1 +
 4 files changed, 122 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c

diff --git a/arch/powerpc/platforms/pseries/Kconfig 
b/arch/powerpc/platforms/pseries/Kconfig
index 4ebf2ef2845d..afc0f6a61337 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -164,6 +164,12 @@ config PSERIES_PLPKS
# This option is selected by in-kernel consumers that require
# access to the PKS.
 
+config PSERIES_PLPKS_SED
+   depends on PPC_PSERIES
+   bool
+   # This option is selected by in-kernel consumers that require
+   # access to the SED PKS keystore.
+
 config PAPR_SCM
depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM
tristate "Support for the PAPR Storage Class Memory interface"
diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 53c3b91af2f7..1476c5e4433c 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_SVM) += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS)+= plpks.o
 obj-$(CONFIG_PPC_SECURE_BOOT)  += plpks-secvar.o
+obj-$(CONFIG_PSERIES_PLPKS_SED)+= plpks_sed_ops.o
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
 
diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c 
b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
new file mode 100644
index ..c1d08075e850
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform specific code for non-volatile SED key access
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for SED Opal to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * Self Encrypting Drives(SED) key storage using PLPKS
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+#define PLPKS_SED_OBJECT_DATA_V00
+#define PLPKS_SED_MANGLED_LABEL "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+#define PLPKS_SED_KEY   "opal-boot-pin"
+
+/*
+ * authority is admin1 and range is global
+ */
+#define PLPKS_SED_AUTHORITY  0x000900010001
+#define PLPKS_SED_RANGE  0x08020001
+
+void plpks_init_var(struct plpks_var *var, char *keyname)
+{
+   var->name = keyname;
+   var->namelen = strlen(keyname);
+   if (strcmp(PLPKS_SED_KEY, keyname) == 0) {
+   var->name = PLPKS_SED_MANGLED_LABEL;
+   var->namelen = strlen(keyname);
+   }
+   var->policy = PLPKS_WORLDREADABLE;
+   var->os = PLPKS_VAR_COMMON;
+   var->data = NULL;
+   var->datalen = 0;
+   var->component = PLPKS_SED_COMPONENT;
+}
+
+/*
+ * Read the SED Opal key from PLPKS given the label
+ */
+int sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   int ret;
+   u_int len;
+
+   plpks_init_var(, keyname);
+   var.data = (u8 *)
+   var.datalen = sizeof(data);
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   len = min_t(u16, be32_to_cpu(data.key_len), var.datalen);
+   memcpy(key, data.key, len);
+   key[len] = '\0';
+   *keylen = len;
+
+   return 0;
+}
+
+/*
+ * Write the SED Opal key to PLPKS given the label
+ */
+int sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   plpks_init_var(, keyname);
+
+   var.datalen = sizeof(struct plpks_sed_object_data);
+   var.data = (u8 *)
+
+   /* initialize SED object */
+   data.version = PLPKS_SED_OBJECT_DATA_V0;
+   data.authority = cpu_to_be64(PLPKS_SED_AUTHORITY);
+   data.range = cpu_to_be64(PLPKS_SED_RANGE);
+   memset(, '\0', sizeof(data.pad1));
+   data.key_len = cpu_to_be32(keylen);
+   memcpy(data.key, (char *)key, keylen);
+
+   /*
+* Key update requires remove first. The return value
+* is ignored since it's okay if the 

[PATCH v7 2/3 RESEND] block: sed-opal: keystore access for SED Opal keys

2023-09-08 Thread gjoyce
From: Greg Joyce 

Allow for permanent SED authentication keys by
reading/writing to the SED Opal non-volatile keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/sed-opal.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/block/sed-opal.c b/block/sed-opal.c
index 6d7f25d1711b..fa23a6a60485 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -3019,7 +3020,13 @@ static int opal_set_new_pw(struct opal_dev *dev, struct 
opal_new_pw *opal_pw)
if (ret)
return ret;
 
-   /* update keyring with new password */
+   /* update keyring and key store with new password */
+   ret = sed_write_key(OPAL_AUTH_KEY,
+   opal_pw->new_user_pw.opal_key.key,
+   opal_pw->new_user_pw.opal_key.key_len);
+   if (ret != -EOPNOTSUPP)
+   pr_warn("error updating SED key: %d\n", ret);
+
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);
@@ -3292,6 +3299,8 @@ EXPORT_SYMBOL_GPL(sed_ioctl);
 static int __init sed_opal_init(void)
 {
struct key *kr;
+   char init_sed_key[OPAL_KEY_MAX];
+   int keylen = OPAL_KEY_MAX - 1;
 
kr = keyring_alloc(".sed_opal",
   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
@@ -3304,6 +3313,11 @@ static int __init sed_opal_init(void)
 
sed_opal_keyring = kr;
 
-   return 0;
+   if (sed_read_key(OPAL_AUTH_KEY, init_sed_key, ) < 0) {
+   memset(init_sed_key, '\0', sizeof(init_sed_key));
+   keylen = OPAL_KEY_MAX - 1;
+   }
+
+   return update_sed_opal_key(OPAL_AUTH_KEY, init_sed_key, keylen);
 }
 late_initcall(sed_opal_init);
-- 
gjo...@linux.vnet.ibm.com



[PATCH v7 1/3 RESEND] block:sed-opal: SED Opal keystore

2023-09-08 Thread gjoyce
From: Greg Joyce 

Add read and write functions that allow SED Opal keys to stored
in a permanent keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/Makefile   |  2 +-
 block/sed-opal-key.c | 24 
 include/linux/sed-opal-key.h | 15 +++
 3 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

diff --git a/block/Makefile b/block/Makefile
index 46ada9dc8bbf..ea07d80402a6 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_BLK_DEV_ZONED)   += blk-zoned.o
 obj-$(CONFIG_BLK_WBT)  += blk-wbt.o
 obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
 obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
-obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
+obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o sed-opal-key.o
 obj-$(CONFIG_BLK_PM)   += blk-pm.o
 obj-$(CONFIG_BLK_INLINE_ENCRYPTION)+= blk-crypto.o blk-crypto-profile.o \
   blk-crypto-sysfs.o
diff --git a/block/sed-opal-key.c b/block/sed-opal-key.c
new file mode 100644
index ..16f380164c44
--- /dev/null
+++ b/block/sed-opal-key.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+int __weak sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   return -EOPNOTSUPP;
+}
+
+int __weak sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   return -EOPNOTSUPP;
+}
diff --git a/include/linux/sed-opal-key.h b/include/linux/sed-opal-key.h
new file mode 100644
index ..c9b1447986d8
--- /dev/null
+++ b/include/linux/sed-opal-key.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+
+int sed_read_key(char *keyname, char *key, u_int *keylen);
+int sed_write_key(char *keyname, char *key, u_int keylen);
-- 
gjo...@linux.vnet.ibm.com



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

2023-07-21 Thread gjoyce
From: Greg Joyce 

This patchset has gone through numerous rounds of review and
all comments/suggetions have been addressed. The reviews have
covered all relevant areas including reviews by block and keyring
developers as well as the SED Opal maintainer. The last
patchset submission has not solicited any responses in the
six weeks since it was last distributed. The changes are
generally useful and ready for inclusion.

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 v5:
- rebase to for-6.5/block

change log v4:
- rebase to 6.3-rc7
- replaced "255" magic number with U8_MAX

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 |   2 +
 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, 282 insertions(+), 6 deletions(-)


base-commit: 1341c7d2ccf42ed91aea80b8579d35bc1ea381e2
-- 
gjo...@linux.vnet.ibm.com



[PATCH v7 3/3 RESEND] powerpc/pseries: PLPKS SED Opal keystore support

2023-07-21 Thread gjoyce
From: Greg Joyce 

Define operations for SED Opal to read/write keys
from POWER LPAR Platform KeyStore(PLPKS). This allows
non-volatile storage of SED Opal keys.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 114 ++
 block/Kconfig |   1 +
 4 files changed, 122 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c

diff --git a/arch/powerpc/platforms/pseries/Kconfig 
b/arch/powerpc/platforms/pseries/Kconfig
index 4ebf2ef2845d..afc0f6a61337 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -164,6 +164,12 @@ config PSERIES_PLPKS
# This option is selected by in-kernel consumers that require
# access to the PKS.
 
+config PSERIES_PLPKS_SED
+   depends on PPC_PSERIES
+   bool
+   # This option is selected by in-kernel consumers that require
+   # access to the SED PKS keystore.
+
 config PAPR_SCM
depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM
tristate "Support for the PAPR Storage Class Memory interface"
diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 53c3b91af2f7..1476c5e4433c 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_SVM) += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS)+= plpks.o
 obj-$(CONFIG_PPC_SECURE_BOOT)  += plpks-secvar.o
+obj-$(CONFIG_PSERIES_PLPKS_SED)+= plpks_sed_ops.o
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
 
diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c 
b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
new file mode 100644
index ..c1d08075e850
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform specific code for non-volatile SED key access
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for SED Opal to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * Self Encrypting Drives(SED) key storage using PLPKS
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+#define PLPKS_SED_OBJECT_DATA_V00
+#define PLPKS_SED_MANGLED_LABEL "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+#define PLPKS_SED_KEY   "opal-boot-pin"
+
+/*
+ * authority is admin1 and range is global
+ */
+#define PLPKS_SED_AUTHORITY  0x000900010001
+#define PLPKS_SED_RANGE  0x08020001
+
+void plpks_init_var(struct plpks_var *var, char *keyname)
+{
+   var->name = keyname;
+   var->namelen = strlen(keyname);
+   if (strcmp(PLPKS_SED_KEY, keyname) == 0) {
+   var->name = PLPKS_SED_MANGLED_LABEL;
+   var->namelen = strlen(keyname);
+   }
+   var->policy = PLPKS_WORLDREADABLE;
+   var->os = PLPKS_VAR_COMMON;
+   var->data = NULL;
+   var->datalen = 0;
+   var->component = PLPKS_SED_COMPONENT;
+}
+
+/*
+ * Read the SED Opal key from PLPKS given the label
+ */
+int sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   int ret;
+   u_int len;
+
+   plpks_init_var(, keyname);
+   var.data = (u8 *)
+   var.datalen = sizeof(data);
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   len = min_t(u16, be32_to_cpu(data.key_len), var.datalen);
+   memcpy(key, data.key, len);
+   key[len] = '\0';
+   *keylen = len;
+
+   return 0;
+}
+
+/*
+ * Write the SED Opal key to PLPKS given the label
+ */
+int sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   plpks_init_var(, keyname);
+
+   var.datalen = sizeof(struct plpks_sed_object_data);
+   var.data = (u8 *)
+
+   /* initialize SED object */
+   data.version = PLPKS_SED_OBJECT_DATA_V0;
+   data.authority = cpu_to_be64(PLPKS_SED_AUTHORITY);
+   data.range = cpu_to_be64(PLPKS_SED_RANGE);
+   memset(, '\0', sizeof(data.pad1));
+   data.key_len = cpu_to_be32(keylen);
+   memcpy(data.key, (char *)key, keylen);
+
+   /*
+* Key update requires remove first. The return value
+* is ignored since it's okay if the key doesn't exist.
+*/
+ 

[PATCH v7 2/3 RESEND] block: sed-opal: keystore access for SED Opal keys

2023-07-21 Thread gjoyce
From: Greg Joyce 

Allow for permanent SED authentication keys by
reading/writing to the SED Opal non-volatile keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/sed-opal.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/block/sed-opal.c b/block/sed-opal.c
index 6d7f25d1711b..fa23a6a60485 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -3019,7 +3020,13 @@ static int opal_set_new_pw(struct opal_dev *dev, struct 
opal_new_pw *opal_pw)
if (ret)
return ret;
 
-   /* update keyring with new password */
+   /* update keyring and key store with new password */
+   ret = sed_write_key(OPAL_AUTH_KEY,
+   opal_pw->new_user_pw.opal_key.key,
+   opal_pw->new_user_pw.opal_key.key_len);
+   if (ret != -EOPNOTSUPP)
+   pr_warn("error updating SED key: %d\n", ret);
+
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);
@@ -3292,6 +3299,8 @@ EXPORT_SYMBOL_GPL(sed_ioctl);
 static int __init sed_opal_init(void)
 {
struct key *kr;
+   char init_sed_key[OPAL_KEY_MAX];
+   int keylen = OPAL_KEY_MAX - 1;
 
kr = keyring_alloc(".sed_opal",
   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
@@ -3304,6 +3313,11 @@ static int __init sed_opal_init(void)
 
sed_opal_keyring = kr;
 
-   return 0;
+   if (sed_read_key(OPAL_AUTH_KEY, init_sed_key, ) < 0) {
+   memset(init_sed_key, '\0', sizeof(init_sed_key));
+   keylen = OPAL_KEY_MAX - 1;
+   }
+
+   return update_sed_opal_key(OPAL_AUTH_KEY, init_sed_key, keylen);
 }
 late_initcall(sed_opal_init);
-- 
gjo...@linux.vnet.ibm.com



[PATCH v7 0/3 RESEND] generic and PowerPC SED Opal keystore

2023-07-21 Thread gjoyce
From: Greg Joyce 

This patchset has gone through numerous rounds of review and
all comments/suggetions have been addressed. The reviews have
covered all relevant areas including reviews by block and keyring
developers as well as the SED Opal maintainer. The last
patchset submission has not solicited any responses in the
six weeks since it was last distributed. The changes are
generally useful and ready for inclusion.

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.

Generic functions have been defined for accessing SED Opal keys.
The generic functions are defined as weak so that they may be superseded
by keystore specific versions.

PowerPC/pseries versions of these functions provide read/write access
to SED Opal keys in the PLPKS keystore.

The SED block driver has been modified to read the SED Opal
keystore to populate a key in the SED Opal keyring. Changes to the
SED Opal key will be written to the SED Opal keystore.

Patch 3 "keystore access for SED Opal keys" is dependent on:

https://lore.kernel.org/keyrings/20220818143045.680972-4-gjo...@linux.vnet.ibm.com/T/#u

Changelog
v7: - rebased to for-6.5/block

v6: - squashed two commits (suggested by Andrew Donnellan)

v5: - updated to reflect changes in PLPKS API

v4:
- scope reduced to cover just SED Opal keys
- base SED Opal keystore is now in SED block driver
- removed use of enum to indicate type
- refactored common code into common function that read and
  write use
- removed cast to void
- added use of SED Opal keystore functions to SED block driver

v3:
- No code changes, but per reviewer requests, adding additional
  mailing lists(keyring, EFI) for wider review.

v2:
- Include feedback from Gregory Joyce, Eric Richter and
  Murilo Opsfelder Araujo.
- Include suggestions from Michael Ellerman.
- Moved a dependency from generic SED code to this patchset.
  This patchset now builds of its own.



Greg Joyce (3):
  block:sed-opal: SED Opal keystore
  block: sed-opal: keystore access for SED Opal keys
  powerpc/pseries: PLPKS SED Opal keystore support

 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 114 ++
 block/Kconfig |   1 +
 block/Makefile|   2 +-
 block/sed-opal-key.c  |  24 
 block/sed-opal.c  |  18 ++-
 include/linux/sed-opal-key.h  |  15 +++
 8 files changed, 178 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h


base-commit: 1341c7d2ccf42ed91aea80b8579d35bc1ea381e2
-- 
gjo...@linux.vnet.ibm.com



[PATCH v7 1/3 RESEND] block:sed-opal: SED Opal keystore

2023-07-21 Thread gjoyce
From: Greg Joyce 

Add read and write functions that allow SED Opal keys to stored
in a permanent keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/Makefile   |  2 +-
 block/sed-opal-key.c | 24 
 include/linux/sed-opal-key.h | 15 +++
 3 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

diff --git a/block/Makefile b/block/Makefile
index 46ada9dc8bbf..ea07d80402a6 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_BLK_DEV_ZONED)   += blk-zoned.o
 obj-$(CONFIG_BLK_WBT)  += blk-wbt.o
 obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
 obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
-obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
+obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o sed-opal-key.o
 obj-$(CONFIG_BLK_PM)   += blk-pm.o
 obj-$(CONFIG_BLK_INLINE_ENCRYPTION)+= blk-crypto.o blk-crypto-profile.o \
   blk-crypto-sysfs.o
diff --git a/block/sed-opal-key.c b/block/sed-opal-key.c
new file mode 100644
index ..16f380164c44
--- /dev/null
+++ b/block/sed-opal-key.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+int __weak sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   return -EOPNOTSUPP;
+}
+
+int __weak sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   return -EOPNOTSUPP;
+}
diff --git a/include/linux/sed-opal-key.h b/include/linux/sed-opal-key.h
new file mode 100644
index ..c9b1447986d8
--- /dev/null
+++ b/include/linux/sed-opal-key.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+
+int sed_read_key(char *keyname, char *key, u_int *keylen);
+int sed_write_key(char *keyname, char *key, u_int keylen);
-- 
gjo...@linux.vnet.ibm.com



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

2023-07-21 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Jonathan Derrick 
---
 block/Kconfig |   2 +
 block/sed-opal.c  | 174 +-
 include/linux/sed-opal.h  |   3 +
 include/uapi/linux/sed-opal.h |   8 +-
 4 files changed, 184 insertions(+), 3 deletions(-)

diff --git a/block/Kconfig b/block/Kconfig
index 86122e459fe0..77f72175eb72 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -183,6 +183,8 @@ config BLK_DEBUG_FS_ZONED
 
 config BLK_SED_OPAL
bool "Logic for interfacing with Opal enabled SEDs"
+   depends on KEYS
+   select PSERIES_PLPKS if PPC_PSERIES
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 e2aed7f4ebdf..6d7f25d1711b 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -20,6 +20,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #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;
@@ -269,6 +274,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),
+ _type_user, key_name, true);
+
+   if (IS_ERR(kref))
+   ret = PTR_ERR(kref);
+
+   key = key_ref_to_ptr(kref);
+   down_read(>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(>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 > U8_MAX) {
+   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;
@@ -2459,6 +2559,9 @@ static int opal_secure_erase_locking_range(struct 
opal_dev *dev,
};
int ret;
 
+   ret = opal_get_key(dev, _session->opal_key);
+   if (ret)
+   return ret;
mutex_lock(>dev_lock);
setup_opal_dev(dev);
ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2492,6 +2595,9 @@ static int opal_revertlsp(struct opal_dev 

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

2023-07-21 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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 a4e56845dd82..dec7ce3a3edb 100644
--- a/block/opal_proto.h
+++ b/block/opal_proto.h
@@ -225,6 +225,10 @@ enum opal_parameter {
OPAL_SUM_SET_LIST = 0x06,
 };
 
+enum opal_revertlsp {
+   OPAL_KEEP_GLOBAL_RANGE_KEY = 0x06,
+};
+
 /* 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 67c6c4f2b4b0..e2aed7f4ebdf 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -1769,6 +1769,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(, dev, OPAL_STARTNAME);
+   add_token_u64(, dev, OPAL_KEEP_GLOBAL_RANGE_KEY);
+   add_token_u8(, dev, (rev->options & OPAL_PRESERVE) ?
+   OPAL_TRUE : OPAL_FALSE);
+   add_token_u8(, 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;
@@ -2463,6 +2483,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, >key },
+   { revert_lsp, rev }
+   };
+   int ret;
+
+   mutex_lock(>dev_lock);
+   setup_opal_dev(dev);
+   ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
+   mutex_unlock(>dev_lock);
+
+   return ret;
+}
+
 static int opal_erase_locking_range(struct opal_dev *dev,
struct opal_session_info *opal_session)
 {
@@ -3084,6 +3121,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, 
void __user *arg)
case IOC_OPAL_GET_GEOMETRY:
ret = opal_get_geometry(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 ef65f589fbeb..2f189546e133 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -48,6 +48,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
case IOC_OPAL_GET_LR_STATUS:
case IOC_OPAL_GET_GEOMETRY:
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 7f5732c5bdc5..4e10675751b4 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -56,6 +56,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;
@@ -178,6 +182,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)
@@ -198,5 +208,6 @@ struct opal_discovery {
 #define IOC_OPAL_GET_LR_STATUS  _IOW('p', 237, struct opal_lr_status)
 #define IOC_OPAL_GET_GEOMETRY   _IOR('p', 238, struct opal_geometry)
 #define IOC_OPAL_DISCOVERY  _IOW('p', 239, struct opal_discovery)
+#define IOC_OPAL_REVERT_LSP _IOW('p', 240, struct opal_revert_lsp)
 
 #endif /* _UAPI_SED_OPAL_H */
-- 

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

2023-07-21 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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 c18339446ef3..67c6c4f2b4b0 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -463,8 +463,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;
@@ -480,6 +483,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 */
 
@@ -565,13 +577,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, _step, 0);
@@ -2435,6 +2447,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_lock);
+   setup_opal_dev(dev);
+   ret = execute_step(dev, _step, 0);
+   mutex_unlock(>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)
 {
@@ -3056,6 +3084,10 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, 
void __user *arg)
case IOC_OPAL_GET_GEOMETRY:
ret = opal_get_geometry(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 bbae1e52ab4f..ef65f589fbeb 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -47,6 +47,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
case IOC_OPAL_GET_STATUS:
case IOC_OPAL_GET_LR_STATUS:
case IOC_OPAL_GET_GEOMETRY:
+   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 dc2efd345133..7f5732c5bdc5 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -173,6 +173,11 @@ struct opal_geometry {
__u8  __align[3];
 };
 
+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)
@@ -192,5 +197,6 @@ struct opal_geometry {
 #define IOC_OPAL_GET_STATUS _IOR('p', 236, struct opal_status)
 #define IOC_OPAL_GET_LR_STATUS  _IOW('p', 237, struct opal_lr_status)
 #define IOC_OPAL_GET_GEOMETRY   _IOR('p', 238, struct opal_geometry)
+#define IOC_OPAL_DISCOVERY  _IOW('p', 239, struct opal_discovery)
 
 #endif /* _UAPI_SED_OPAL_H */
-- 
gjo...@linux.vnet.ibm.com



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

2023-06-08 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Jonathan Derrick 
---
 block/Kconfig |   2 +
 block/sed-opal.c  | 174 +-
 include/linux/sed-opal.h  |   3 +
 include/uapi/linux/sed-opal.h |   8 +-
 4 files changed, 184 insertions(+), 3 deletions(-)

diff --git a/block/Kconfig b/block/Kconfig
index 86122e459fe0..77f72175eb72 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -183,6 +183,8 @@ config BLK_DEBUG_FS_ZONED
 
 config BLK_SED_OPAL
bool "Logic for interfacing with Opal enabled SEDs"
+   depends on KEYS
+   select PSERIES_PLPKS if PPC_PSERIES
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 e2aed7f4ebdf..6d7f25d1711b 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -20,6 +20,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #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;
@@ -269,6 +274,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),
+ _type_user, key_name, true);
+
+   if (IS_ERR(kref))
+   ret = PTR_ERR(kref);
+
+   key = key_ref_to_ptr(kref);
+   down_read(>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(>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 > U8_MAX) {
+   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;
@@ -2459,6 +2559,9 @@ static int opal_secure_erase_locking_range(struct 
opal_dev *dev,
};
int ret;
 
+   ret = opal_get_key(dev, _session->opal_key);
+   if (ret)
+   return ret;
mutex_lock(>dev_lock);
setup_opal_dev(dev);
ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2492,6 +2595,9 @@ static int opal_revertlsp(struct opal_dev 

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

2023-06-08 Thread gjoyce
From: Greg Joyce 

Patchset rebased to for-6.5/block

This patchset has gone through numerous rounds of review and
all comments/suggetions have been addressed. I believe that
this patchset is ready for inclusion.

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 v5:
- rebase to for-6.5/block

change log v4:
- rebase to 6.3-rc7
- replaced "255" magic number with U8_MAX

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 |   2 +
 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, 282 insertions(+), 6 deletions(-)


base-commit: 1341c7d2ccf42ed91aea80b8579d35bc1ea381e2
-- 
gjo...@linux.vnet.ibm.com



[PATCH v7 3/3] powerpc/pseries: PLPKS SED Opal keystore support

2023-06-08 Thread gjoyce
From: Greg Joyce 

Define operations for SED Opal to read/write keys
from POWER LPAR Platform KeyStore(PLPKS). This allows
non-volatile storage of SED Opal keys.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 114 ++
 block/Kconfig |   1 +
 4 files changed, 122 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c

diff --git a/arch/powerpc/platforms/pseries/Kconfig 
b/arch/powerpc/platforms/pseries/Kconfig
index 4ebf2ef2845d..afc0f6a61337 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -164,6 +164,12 @@ config PSERIES_PLPKS
# This option is selected by in-kernel consumers that require
# access to the PKS.
 
+config PSERIES_PLPKS_SED
+   depends on PPC_PSERIES
+   bool
+   # This option is selected by in-kernel consumers that require
+   # access to the SED PKS keystore.
+
 config PAPR_SCM
depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM
tristate "Support for the PAPR Storage Class Memory interface"
diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 53c3b91af2f7..1476c5e4433c 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_SVM) += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS)+= plpks.o
 obj-$(CONFIG_PPC_SECURE_BOOT)  += plpks-secvar.o
+obj-$(CONFIG_PSERIES_PLPKS_SED)+= plpks_sed_ops.o
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
 
diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c 
b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
new file mode 100644
index ..c1d08075e850
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform specific code for non-volatile SED key access
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for SED Opal to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * Self Encrypting Drives(SED) key storage using PLPKS
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+#define PLPKS_SED_OBJECT_DATA_V00
+#define PLPKS_SED_MANGLED_LABEL "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+#define PLPKS_SED_KEY   "opal-boot-pin"
+
+/*
+ * authority is admin1 and range is global
+ */
+#define PLPKS_SED_AUTHORITY  0x000900010001
+#define PLPKS_SED_RANGE  0x08020001
+
+void plpks_init_var(struct plpks_var *var, char *keyname)
+{
+   var->name = keyname;
+   var->namelen = strlen(keyname);
+   if (strcmp(PLPKS_SED_KEY, keyname) == 0) {
+   var->name = PLPKS_SED_MANGLED_LABEL;
+   var->namelen = strlen(keyname);
+   }
+   var->policy = PLPKS_WORLDREADABLE;
+   var->os = PLPKS_VAR_COMMON;
+   var->data = NULL;
+   var->datalen = 0;
+   var->component = PLPKS_SED_COMPONENT;
+}
+
+/*
+ * Read the SED Opal key from PLPKS given the label
+ */
+int sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   int ret;
+   u_int len;
+
+   plpks_init_var(, keyname);
+   var.data = (u8 *)
+   var.datalen = sizeof(data);
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   len = min_t(u16, be32_to_cpu(data.key_len), var.datalen);
+   memcpy(key, data.key, len);
+   key[len] = '\0';
+   *keylen = len;
+
+   return 0;
+}
+
+/*
+ * Write the SED Opal key to PLPKS given the label
+ */
+int sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   plpks_init_var(, keyname);
+
+   var.datalen = sizeof(struct plpks_sed_object_data);
+   var.data = (u8 *)
+
+   /* initialize SED object */
+   data.version = PLPKS_SED_OBJECT_DATA_V0;
+   data.authority = cpu_to_be64(PLPKS_SED_AUTHORITY);
+   data.range = cpu_to_be64(PLPKS_SED_RANGE);
+   memset(, '\0', sizeof(data.pad1));
+   data.key_len = cpu_to_be32(keylen);
+   memcpy(data.key, (char *)key, keylen);
+
+   /*
+* Key update requires remove first. The return value
+* is ignored since it's okay if the key doesn't exist.
+*/
+ 

[PATCH v7 1/3] block:sed-opal: SED Opal keystore

2023-06-08 Thread gjoyce
From: Greg Joyce 

Add read and write functions that allow SED Opal keys to stored
in a permanent keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/Makefile   |  2 +-
 block/sed-opal-key.c | 24 
 include/linux/sed-opal-key.h | 15 +++
 3 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

diff --git a/block/Makefile b/block/Makefile
index 46ada9dc8bbf..ea07d80402a6 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_BLK_DEV_ZONED)   += blk-zoned.o
 obj-$(CONFIG_BLK_WBT)  += blk-wbt.o
 obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
 obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
-obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
+obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o sed-opal-key.o
 obj-$(CONFIG_BLK_PM)   += blk-pm.o
 obj-$(CONFIG_BLK_INLINE_ENCRYPTION)+= blk-crypto.o blk-crypto-profile.o \
   blk-crypto-sysfs.o
diff --git a/block/sed-opal-key.c b/block/sed-opal-key.c
new file mode 100644
index ..16f380164c44
--- /dev/null
+++ b/block/sed-opal-key.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+int __weak sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   return -EOPNOTSUPP;
+}
+
+int __weak sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   return -EOPNOTSUPP;
+}
diff --git a/include/linux/sed-opal-key.h b/include/linux/sed-opal-key.h
new file mode 100644
index ..c9b1447986d8
--- /dev/null
+++ b/include/linux/sed-opal-key.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+
+int sed_read_key(char *keyname, char *key, u_int *keylen);
+int sed_write_key(char *keyname, char *key, u_int keylen);
-- 
gjo...@linux.vnet.ibm.com



[PATCH v7 0/3] generic and PowerPC SED Opal keystore

2023-06-08 Thread gjoyce
From: Greg Joyce 

Patchset rebase to for-6.5/block

This patchset has gone through numerous rounds of review and
all comments/suggetions have been addressed. I believe that
this patchset is ready for inclusion.

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.

Generic functions have been defined for accessing SED Opal keys.
The generic functions are defined as weak so that they may be superseded
by keystore specific versions.

PowerPC/pseries versions of these functions provide read/write access
to SED Opal keys in the PLPKS keystore.

The SED block driver has been modified to read the SED Opal
keystore to populate a key in the SED Opal keyring. Changes to the
SED Opal key will be written to the SED Opal keystore.

Patch 3 "keystore access for SED Opal keys" is dependent on:

https://lore.kernel.org/keyrings/20220818143045.680972-4-gjo...@linux.vnet.ibm.com/T/#u

Changelog
v7: - rebased to for-6.5/block

v6: - squashed two commits (suggested by Andrew Donnellan)

v5: - updated to reflect changes in PLPKS API

v4:
- scope reduced to cover just SED Opal keys
- base SED Opal keystore is now in SED block driver
- removed use of enum to indicate type
- refactored common code into common function that read and
  write use
- removed cast to void
- added use of SED Opal keystore functions to SED block driver

v3:
- No code changes, but per reviewer requests, adding additional
  mailing lists(keyring, EFI) for wider review.

v2:
- Include feedback from Gregory Joyce, Eric Richter and
  Murilo Opsfelder Araujo.
- Include suggestions from Michael Ellerman.
- Moved a dependency from generic SED code to this patchset.
  This patchset now builds of its own.



Greg Joyce (3):
  block:sed-opal: SED Opal keystore
  block: sed-opal: keystore access for SED Opal keys
  powerpc/pseries: PLPKS SED Opal keystore support

 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 114 ++
 block/Kconfig |   1 +
 block/Makefile|   2 +-
 block/sed-opal-key.c  |  24 
 block/sed-opal.c  |  18 ++-
 include/linux/sed-opal-key.h  |  15 +++
 8 files changed, 178 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h


base-commit: 1341c7d2ccf42ed91aea80b8579d35bc1ea381e2
-- 
gjo...@linux.vnet.ibm.com



[PATCH v7 2/3] block: sed-opal: keystore access for SED Opal keys

2023-06-08 Thread gjoyce
From: Greg Joyce 

Allow for permanent SED authentication keys by
reading/writing to the SED Opal non-volatile keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/sed-opal.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/block/sed-opal.c b/block/sed-opal.c
index 6d7f25d1711b..fa23a6a60485 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -3019,7 +3020,13 @@ static int opal_set_new_pw(struct opal_dev *dev, struct 
opal_new_pw *opal_pw)
if (ret)
return ret;
 
-   /* update keyring with new password */
+   /* update keyring and key store with new password */
+   ret = sed_write_key(OPAL_AUTH_KEY,
+   opal_pw->new_user_pw.opal_key.key,
+   opal_pw->new_user_pw.opal_key.key_len);
+   if (ret != -EOPNOTSUPP)
+   pr_warn("error updating SED key: %d\n", ret);
+
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);
@@ -3292,6 +3299,8 @@ EXPORT_SYMBOL_GPL(sed_ioctl);
 static int __init sed_opal_init(void)
 {
struct key *kr;
+   char init_sed_key[OPAL_KEY_MAX];
+   int keylen = OPAL_KEY_MAX - 1;
 
kr = keyring_alloc(".sed_opal",
   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
@@ -3304,6 +3313,11 @@ static int __init sed_opal_init(void)
 
sed_opal_keyring = kr;
 
-   return 0;
+   if (sed_read_key(OPAL_AUTH_KEY, init_sed_key, ) < 0) {
+   memset(init_sed_key, '\0', sizeof(init_sed_key));
+   keylen = OPAL_KEY_MAX - 1;
+   }
+
+   return update_sed_opal_key(OPAL_AUTH_KEY, init_sed_key, keylen);
 }
 late_initcall(sed_opal_init);
-- 
gjo...@linux.vnet.ibm.com



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

2023-06-08 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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 c18339446ef3..67c6c4f2b4b0 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -463,8 +463,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;
@@ -480,6 +483,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 */
 
@@ -565,13 +577,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, _step, 0);
@@ -2435,6 +2447,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_lock);
+   setup_opal_dev(dev);
+   ret = execute_step(dev, _step, 0);
+   mutex_unlock(>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)
 {
@@ -3056,6 +3084,10 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, 
void __user *arg)
case IOC_OPAL_GET_GEOMETRY:
ret = opal_get_geometry(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 bbae1e52ab4f..ef65f589fbeb 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -47,6 +47,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
case IOC_OPAL_GET_STATUS:
case IOC_OPAL_GET_LR_STATUS:
case IOC_OPAL_GET_GEOMETRY:
+   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 dc2efd345133..7f5732c5bdc5 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -173,6 +173,11 @@ struct opal_geometry {
__u8  __align[3];
 };
 
+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)
@@ -192,5 +197,6 @@ struct opal_geometry {
 #define IOC_OPAL_GET_STATUS _IOR('p', 236, struct opal_status)
 #define IOC_OPAL_GET_LR_STATUS  _IOW('p', 237, struct opal_lr_status)
 #define IOC_OPAL_GET_GEOMETRY   _IOR('p', 238, struct opal_geometry)
+#define IOC_OPAL_DISCOVERY  _IOW('p', 239, struct opal_discovery)
 
 #endif /* _UAPI_SED_OPAL_H */
-- 
gjo...@linux.vnet.ibm.com



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

2023-06-08 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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 a4e56845dd82..dec7ce3a3edb 100644
--- a/block/opal_proto.h
+++ b/block/opal_proto.h
@@ -225,6 +225,10 @@ enum opal_parameter {
OPAL_SUM_SET_LIST = 0x06,
 };
 
+enum opal_revertlsp {
+   OPAL_KEEP_GLOBAL_RANGE_KEY = 0x06,
+};
+
 /* 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 67c6c4f2b4b0..e2aed7f4ebdf 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -1769,6 +1769,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(, dev, OPAL_STARTNAME);
+   add_token_u64(, dev, OPAL_KEEP_GLOBAL_RANGE_KEY);
+   add_token_u8(, dev, (rev->options & OPAL_PRESERVE) ?
+   OPAL_TRUE : OPAL_FALSE);
+   add_token_u8(, 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;
@@ -2463,6 +2483,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, >key },
+   { revert_lsp, rev }
+   };
+   int ret;
+
+   mutex_lock(>dev_lock);
+   setup_opal_dev(dev);
+   ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
+   mutex_unlock(>dev_lock);
+
+   return ret;
+}
+
 static int opal_erase_locking_range(struct opal_dev *dev,
struct opal_session_info *opal_session)
 {
@@ -3084,6 +3121,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, 
void __user *arg)
case IOC_OPAL_GET_GEOMETRY:
ret = opal_get_geometry(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 ef65f589fbeb..2f189546e133 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -48,6 +48,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
case IOC_OPAL_GET_LR_STATUS:
case IOC_OPAL_GET_GEOMETRY:
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 7f5732c5bdc5..4e10675751b4 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -56,6 +56,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;
@@ -178,6 +182,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)
@@ -198,5 +208,6 @@ struct opal_discovery {
 #define IOC_OPAL_GET_LR_STATUS  _IOW('p', 237, struct opal_lr_status)
 #define IOC_OPAL_GET_GEOMETRY   _IOR('p', 238, struct opal_geometry)
 #define IOC_OPAL_DISCOVERY  _IOW('p', 239, struct opal_discovery)
+#define IOC_OPAL_REVERT_LSP _IOW('p', 240, struct opal_revert_lsp)
 
 #endif /* _UAPI_SED_OPAL_H */
-- 

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

2023-06-01 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Jonathan Derrick 
---
 block/Kconfig |   2 +
 block/sed-opal.c  | 174 +-
 include/linux/sed-opal.h  |   3 +
 include/uapi/linux/sed-opal.h |   8 +-
 4 files changed, 184 insertions(+), 3 deletions(-)

diff --git a/block/Kconfig b/block/Kconfig
index 941b2dca70db..76b23114fdeb 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -180,6 +180,8 @@ config BLK_DEBUG_FS_ZONED
 
 config BLK_SED_OPAL
bool "Logic for interfacing with Opal enabled SEDs"
+   depends on KEYS
+   select PSERIES_PLPKS if PPC_PSERIES
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 5b277eaabbc7..7f5f235a9048 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -20,6 +20,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #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),
+ _type_user, key_name, true);
+
+   if (IS_ERR(kref))
+   ret = PTR_ERR(kref);
+
+   key = key_ref_to_ptr(kref);
+   down_read(>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(>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 > U8_MAX) {
+   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;
@@ -2271,6 +2371,9 @@ static int opal_secure_erase_locking_range(struct 
opal_dev *dev,
};
int ret;
 
+   ret = opal_get_key(dev, _session->opal_key);
+   if (ret)
+   return ret;
mutex_lock(>dev_lock);
setup_opal_dev(dev);
ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2304,6 +2407,9 @@ static int opal_revertlsp(struct opal_dev 

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

2023-06-01 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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 = 0x06,
 };
 
+enum opal_revertlsp {
+   OPAL_KEEP_GLOBAL_RANGE_KEY = 0x06,
+};
+
 /* 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 b55a8eb29f5b..5b277eaabbc7 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -1634,6 +1634,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(, dev, OPAL_STARTNAME);
+   add_token_u64(, dev, OPAL_KEEP_GLOBAL_RANGE_KEY);
+   add_token_u8(, dev, (rev->options & OPAL_PRESERVE) ?
+   OPAL_TRUE : OPAL_FALSE);
+   add_token_u8(, 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;
@@ -2275,6 +2295,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, >key },
+   { revert_lsp, rev }
+   };
+   int ret;
+
+   mutex_lock(>dev_lock);
+   setup_opal_dev(dev);
+   ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
+   mutex_unlock(>dev_lock);
+
+   return ret;
+}
+
 static int opal_erase_locking_range(struct opal_dev *dev,
struct opal_session_info *opal_session)
 {
@@ -2842,6 +2879,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 8e824ab908e9..bf2f9d7e11eb 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -46,6 +46,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 98f216cf2241..720725f1c42a 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -56,6 +56,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;
@@ -156,6 +160,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)
@@ -174,5 +184,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 */
-- 

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

2023-06-01 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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 c320093c14f1..b55a8eb29f5b 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 */
 
@@ -559,13 +571,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, _step, 0);
@@ -2247,6 +2259,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_lock);
+   setup_opal_dev(dev);
+   ret = execute_step(dev, _step, 0);
+   mutex_unlock(>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)
 {
@@ -2814,6 +2842,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 31ac562a17d7..8e824ab908e9 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_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 d7a1524023db..98f216cf2241 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -151,6 +151,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)
@@ -168,5 +173,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 */
-- 
gjo...@linux.vnet.ibm.com



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

2023-06-01 Thread gjoyce
From: Greg Joyce 

This patchset has gone through numerous rounds of review and
all comments/suggetions have been addressed. I believe that
this patchset is ready for inclusion.

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 v4:
- rebase to 6.3-rc7
- replaced "255" magic number with U8_MAX

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 |   2 +
 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, 282 insertions(+), 6 deletions(-)

Signed-off-by: Greg Joyce 
base-commit: 6a8f57ae2eb07ab39a6f0ccad60c760743051026
-- 
gjo...@linux.vnet.ibm.com



[PATCH v6 0/4] generic and PowerPC SED Opal keystore

2023-06-01 Thread gjoyce
From: Greg Joyce 

This patchset has gone through numerous rounds of review and
all comments/suggetions have been addressed. I believe that
this patchset is ready for inclusion.

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.

Generic functions have been defined for accessing SED Opal keys.
The generic functions are defined as weak so that they may be superseded
by keystore specific versions.

PowerPC/pseries versions of these functions provide read/write access
to SED Opal keys in the PLPKS keystore.

The SED block driver has been modified to read the SED Opal
keystore to populate a key in the SED Opal keyring. Changes to the
SED Opal key will be written to the SED Opal keystore.

Patch 3 "keystore access for SED Opal keys" is dependent on:

https://lore.kernel.org/keyrings/20220818143045.680972-4-gjo...@linux.vnet.ibm.com/T/#u

Changelog
v6: - squashed two commits (suggested by Andrew Donnellan)

v5: - updated to reflect changes in PLPKS API

v4:
- scope reduced to cover just SED Opal keys
- base SED Opal keystore is now in SED block driver
- removed use of enum to indicate type
- refactored common code into common function that read and
  write use
- removed cast to void
- added use of SED Opal keystore functions to SED block driver

v3:
- No code changes, but per reviewer requests, adding additional
  mailing lists(keyring, EFI) for wider review.

v2:
- Include feedback from Gregory Joyce, Eric Richter and
  Murilo Opsfelder Araujo.
- Include suggestions from Michael Ellerman.
- Moved a dependency from generic SED code to this patchset.
  This patchset now builds of its own.



Greg Joyce (3):
  block:sed-opal: SED Opal keystore
  block: sed-opal: keystore access for SED Opal keys
  powerpc/pseries: PLPKS SED Opal keystore support

 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 114 ++
 block/Kconfig |   1 +
 block/Makefile|   2 +-
 block/sed-opal-key.c  |  24 
 block/sed-opal.c  |  18 ++-
 include/linux/sed-opal-key.h  |  15 +++
 8 files changed, 178 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

-- 
gjo...@linux.vnet.ibm.com



[PATCH v6 1/3] block:sed-opal: SED Opal keystore

2023-06-01 Thread gjoyce
From: Greg Joyce 

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.

Add read and write functions that allow SED Opal authentication keys
to be stored in a permanent keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/Makefile   |  2 +-
 block/sed-opal-key.c | 24 
 include/linux/sed-opal-key.h | 15 +++
 3 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

diff --git a/block/Makefile b/block/Makefile
index 4e01bb71ad6e..464a9f209552 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -35,7 +35,7 @@ obj-$(CONFIG_BLK_DEV_ZONED)   += blk-zoned.o
 obj-$(CONFIG_BLK_WBT)  += blk-wbt.o
 obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
 obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
-obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
+obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o sed-opal-key.o
 obj-$(CONFIG_BLK_PM)   += blk-pm.o
 obj-$(CONFIG_BLK_INLINE_ENCRYPTION)+= blk-crypto.o blk-crypto-profile.o \
   blk-crypto-sysfs.o
diff --git a/block/sed-opal-key.c b/block/sed-opal-key.c
new file mode 100644
index ..16f380164c44
--- /dev/null
+++ b/block/sed-opal-key.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+int __weak sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   return -EOPNOTSUPP;
+}
+
+int __weak sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   return -EOPNOTSUPP;
+}
diff --git a/include/linux/sed-opal-key.h b/include/linux/sed-opal-key.h
new file mode 100644
index ..c9b1447986d8
--- /dev/null
+++ b/include/linux/sed-opal-key.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+
+int sed_read_key(char *keyname, char *key, u_int *keylen);
+int sed_write_key(char *keyname, char *key, u_int keylen);
-- 
gjo...@linux.vnet.ibm.com



[PATCH v6 3/3] powerpc/pseries: PLPKS SED Opal keystore support

2023-06-01 Thread gjoyce
From: Greg Joyce 

Define operations for SED Opal to read/write keys
from POWER LPAR Platform KeyStore(PLPKS). This allows
non-volatile storage of SED Opal keys.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 

---
 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 114 ++
 block/Kconfig |   1 +
 4 files changed, 122 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c

diff --git a/arch/powerpc/platforms/pseries/Kconfig 
b/arch/powerpc/platforms/pseries/Kconfig
index 21b22bf16ce6..c2f8a29e7b9b 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -163,6 +163,12 @@ config PSERIES_PLPKS
# This option is selected by in-kernel consumers that require
# access to the PKS.
 
+config PSERIES_PLPKS_SED
+   depends on PPC_PSERIES
+   bool
+   # This option is selected by in-kernel consumers that require
+   # access to the SED PKS keystore.
+
 config PAPR_SCM
depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM
tristate "Support for the PAPR Storage Class Memory interface"
diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 53c3b91af2f7..1476c5e4433c 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_SVM) += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS)+= plpks.o
 obj-$(CONFIG_PPC_SECURE_BOOT)  += plpks-secvar.o
+obj-$(CONFIG_PSERIES_PLPKS_SED)+= plpks_sed_ops.o
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
 
diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c 
b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
new file mode 100644
index ..c1d08075e850
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform specific code for non-volatile SED key access
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for SED Opal to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * Self Encrypting Drives(SED) key storage using PLPKS
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+#define PLPKS_SED_OBJECT_DATA_V00
+#define PLPKS_SED_MANGLED_LABEL "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+#define PLPKS_SED_KEY   "opal-boot-pin"
+
+/*
+ * authority is admin1 and range is global
+ */
+#define PLPKS_SED_AUTHORITY  0x000900010001
+#define PLPKS_SED_RANGE  0x08020001
+
+void plpks_init_var(struct plpks_var *var, char *keyname)
+{
+   var->name = keyname;
+   var->namelen = strlen(keyname);
+   if (strcmp(PLPKS_SED_KEY, keyname) == 0) {
+   var->name = PLPKS_SED_MANGLED_LABEL;
+   var->namelen = strlen(keyname);
+   }
+   var->policy = PLPKS_WORLDREADABLE;
+   var->os = PLPKS_VAR_COMMON;
+   var->data = NULL;
+   var->datalen = 0;
+   var->component = PLPKS_SED_COMPONENT;
+}
+
+/*
+ * Read the SED Opal key from PLPKS given the label
+ */
+int sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   int ret;
+   u_int len;
+
+   plpks_init_var(, keyname);
+   var.data = (u8 *)
+   var.datalen = sizeof(data);
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   len = min_t(u16, be32_to_cpu(data.key_len), var.datalen);
+   memcpy(key, data.key, len);
+   key[len] = '\0';
+   *keylen = len;
+
+   return 0;
+}
+
+/*
+ * Write the SED Opal key to PLPKS given the label
+ */
+int sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   plpks_init_var(, keyname);
+
+   var.datalen = sizeof(struct plpks_sed_object_data);
+   var.data = (u8 *)
+
+   /* initialize SED object */
+   data.version = PLPKS_SED_OBJECT_DATA_V0;
+   data.authority = cpu_to_be64(PLPKS_SED_AUTHORITY);
+   data.range = cpu_to_be64(PLPKS_SED_RANGE);
+   memset(, '\0', sizeof(data.pad1));
+   data.key_len = cpu_to_be32(keylen);
+   memcpy(data.key, (char *)key, keylen);
+
+   /*
+* Key update requires remove first. The return value
+* is ignored since it's okay if the key doesn't exist.
+*/

[PATCH v6 2/3] block/sed-opal: keystore access for SED Opal keys

2023-06-01 Thread gjoyce
From: Greg Joyce 

Allow for permanent SED Opal authentication keys by
reading/writing to the SED Opal non-volatile keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/sed-opal.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/block/sed-opal.c b/block/sed-opal.c
index 7f5f235a9048..1e8cfa00b609 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2803,7 +2804,13 @@ static int opal_set_new_pw(struct opal_dev *dev, struct 
opal_new_pw *opal_pw)
if (ret)
return ret;
 
-   /* update keyring with new password */
+   /* update keyring and key store with new password */
+   ret = sed_write_key(OPAL_AUTH_KEY,
+   opal_pw->new_user_pw.opal_key.key,
+   opal_pw->new_user_pw.opal_key.key_len);
+   if (ret != -EOPNOTSUPP)
+   pr_warn("error updating SED key: %d\n", ret);
+
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);
@@ -3050,6 +3057,8 @@ EXPORT_SYMBOL_GPL(sed_ioctl);
 static int __init sed_opal_init(void)
 {
struct key *kr;
+   char init_sed_key[OPAL_KEY_MAX];
+   int keylen = OPAL_KEY_MAX - 1;
 
kr = keyring_alloc(".sed_opal",
   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
@@ -3062,6 +3071,11 @@ static int __init sed_opal_init(void)
 
sed_opal_keyring = kr;
 
-   return 0;
+   if (sed_read_key(OPAL_AUTH_KEY, init_sed_key, ) < 0) {
+   memset(init_sed_key, '\0', sizeof(init_sed_key));
+   keylen = OPAL_KEY_MAX - 1;
+   }
+
+   return update_sed_opal_key(OPAL_AUTH_KEY, init_sed_key, keylen);
 }
 late_initcall(sed_opal_init);
-- 
gjo...@linux.vnet.ibm.com



[PATCH v5 0/4] generic and PowerPC SED Opal keystore

2023-05-05 Thread gjoyce
From: Greg Joyce 

Generic functions have been defined for accessing SED Opal keys.
The generic functions are defined as weak so that they may be superseded
by keystore specific versions.

PowerPC/pseries versions of these functions provide read/write access
to SED Opal keys in the PLPKS keystore.

The SED block driver has been modified to read the SED Opal
keystore to populate a key in the SED Opal keyring. Changes to the
SED Opal key will be written to the SED Opal keystore.

Patch 3 "keystore access for SED Opal keys" is dependent on:

https://lore.kernel.org/keyrings/20220818143045.680972-4-gjo...@linux.vnet.ibm.com/T/#u

Changelog
v5: - updated to reflect changes in PLPKS API

v4:
- scope reduced to cover just SED Opal keys
- base SED Opal keystore is now in SED block driver
- removed use of enum to indicate type
- refactored common code into common function that read and
  write use
- removed cast to void
- added use of SED Opal keystore functions to SED block driver

v3:
- No code changes, but per reviewer requests, adding additional
  mailing lists(keyring, EFI) for wider review.

v2:
- Include feedback from Gregory Joyce, Eric Richter and
  Murilo Opsfelder Araujo.
- Include suggestions from Michael Ellerman.
- Moved a dependency from generic SED code to this patchset.
  This patchset now builds of its own.



Greg Joyce (4):
  block:sed-opal: SED Opal keystore
  powerpc/pseries: PLPKS SED Opal keystore support
  block: sed-opal: keystore access for SED Opal keys
  powerpc/pseries: update SED for PLPKS api changes

 arch/powerpc/platforms/pseries/Kconfig|   6 +
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 114 ++
 block/Kconfig |   1 +
 block/Makefile|   2 +-
 block/sed-opal-key.c  |  24 
 block/sed-opal.c  |  18 ++-
 include/linux/sed-opal-key.h  |  15 +++
 8 files changed, 178 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h


base-commit: 6a8f57ae2eb07ab39a6f0ccad60c760743051026
-- 
gjo...@linux.vnet.ibm.com



[PATCH 2/4] powerpc/pseries: PLPKS SED Opal keystore support

2023-05-05 Thread gjoyce
From: Greg Joyce 

Define operations for SED Opal to read/write keys
from POWER LPAR Platform KeyStore(PLPKS). This allows
non-volatile storage of SED Opal keys.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 126 ++
 2 files changed, 127 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c

diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 53c3b91af2f7..4242aed0d5d3 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_SVM) += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS)+= plpks.o
 obj-$(CONFIG_PPC_SECURE_BOOT)  += plpks-secvar.o
+obj-$(CONFIG_PSERIES_PLPKS_SED)+= plpks-sed.o
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
 
diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c 
b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
new file mode 100644
index ..086934b319a9
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform specific code for non-volatile SED key access
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for SED Opal to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * Self Encrypting Drives(SED) key storage using PLPKS
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "plpks.h"
+
+/*
+ * structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+#define PLPKS_PLATVAR_POLICYWORLDREADABLE
+#define PLPKS_PLATVAR_OS_COMMON 4
+
+#define PLPKS_SED_OBJECT_DATA_V00
+#define PLPKS_SED_MANGLED_LABEL "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+#define PLPKS_SED_KEY   "opal-boot-pin"
+
+/*
+ * authority is admin1 and range is global
+ */
+#define PLPKS_SED_AUTHORITY  0x000900010001
+#define PLPKS_SED_RANGE  0x08020001
+
+void plpks_init_var(struct plpks_var *var, char *keyname)
+{
+   var->name = keyname;
+   var->namelen = strlen(keyname);
+   if (strcmp(PLPKS_SED_KEY, keyname) == 0) {
+   var->name = PLPKS_SED_MANGLED_LABEL;
+   var->namelen = strlen(keyname);
+   }
+   var->policy = PLPKS_PLATVAR_POLICY;
+   var->os = PLPKS_PLATVAR_OS_COMMON;
+   var->data = NULL;
+   var->datalen = 0;
+   var->component = PLPKS_SED_COMPONENT;
+}
+
+/*
+ * Read the SED Opal key from PLPKS given the label
+ */
+int sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   u_int offset;
+   int ret;
+   u_int len;
+
+   plpks_init_var(, keyname);
+   var.data = 
+   var.datalen = sizeof(data);
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   offset = offsetof(struct plpks_sed_object_data, key);
+   if (offset > var.datalen) {
+   return -EINVAL;
+   }
+
+   len = min(be32_to_cpu(data.key_len), *keylen);
+
+   memcpy(key, data.key, len);
+   kfree(var.data);
+
+   key[len] = '\0';
+   *keylen = len;
+
+   return 0;
+}
+
+/*
+ * Write the SED Opal key to PLPKS given the label
+ */
+int sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   plpks_init_var(, keyname);
+
+   var.datalen = sizeof(struct plpks_sed_object_data);
+   var.data = (u8 *)
+
+   /* initialize SED object */
+   data.version = PLPKS_SED_OBJECT_DATA_V0;
+   data.authority = cpu_to_be64(PLPKS_SED_AUTHORITY);
+   data.range = cpu_to_be64(PLPKS_SED_RANGE);
+   memset(, '\0', sizeof(data.pad1));
+   data.key_len = cpu_to_be32(keylen);
+   memcpy(data.key, (char *)key, keylen);
+
+   /*
+* Key update requires remove first. The return value
+* is ignored since it's okay if the key doesn't exist.
+*/
+   vname.namelen = var.namelen;
+   vname.name = var.name;
+   plpks_remove_var(var.component, var.os, vname);
+
+   return plpks_write_var(var);
+}
-- 
gjo...@linux.vnet.ibm.com



[PATCH 4/4] powerpc/pseries: update SED for PLPKS api changes

2023-05-05 Thread gjoyce
From: Greg Joyce 

Changes to the PLPKS API require minor updates to the SED Opal
PLPKS keystore code.

Signed-off-by: Greg Joyce 
---
 arch/powerpc/platforms/pseries/Kconfig|  6 +
 arch/powerpc/platforms/pseries/Makefile   |  2 +-
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 22 +--
 block/Kconfig |  1 +
 4 files changed, 13 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/Kconfig 
b/arch/powerpc/platforms/pseries/Kconfig
index 21b22bf16ce6..c2f8a29e7b9b 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -163,6 +163,12 @@ config PSERIES_PLPKS
# This option is selected by in-kernel consumers that require
# access to the PKS.
 
+config PSERIES_PLPKS_SED
+   depends on PPC_PSERIES
+   bool
+   # This option is selected by in-kernel consumers that require
+   # access to the SED PKS keystore.
+
 config PAPR_SCM
depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM
tristate "Support for the PAPR Storage Class Memory interface"
diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 4242aed0d5d3..1476c5e4433c 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,7 +29,7 @@ obj-$(CONFIG_PPC_SVM) += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS)+= plpks.o
 obj-$(CONFIG_PPC_SECURE_BOOT)  += plpks-secvar.o
-obj-$(CONFIG_PSERIES_PLPKS_SED)+= plpks-sed.o
+obj-$(CONFIG_PSERIES_PLPKS_SED)+= plpks_sed_ops.o
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
 
diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c 
b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
index 086934b319a9..c1d08075e850 100644
--- a/arch/powerpc/platforms/pseries/plpks_sed_ops.c
+++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
@@ -14,7 +14,7 @@
 #include 
 #include 
 #include 
-#include "plpks.h"
+#include 
 
 /*
  * structure that contains all SED data
@@ -28,9 +28,6 @@ struct plpks_sed_object_data {
u_char key[32];
 };
 
-#define PLPKS_PLATVAR_POLICYWORLDREADABLE
-#define PLPKS_PLATVAR_OS_COMMON 4
-
 #define PLPKS_SED_OBJECT_DATA_V00
 #define PLPKS_SED_MANGLED_LABEL "/default/pri"
 #define PLPKS_SED_COMPONENT "sed-opal"
@@ -50,8 +47,8 @@ void plpks_init_var(struct plpks_var *var, char *keyname)
var->name = PLPKS_SED_MANGLED_LABEL;
var->namelen = strlen(keyname);
}
-   var->policy = PLPKS_PLATVAR_POLICY;
-   var->os = PLPKS_PLATVAR_OS_COMMON;
+   var->policy = PLPKS_WORLDREADABLE;
+   var->os = PLPKS_VAR_COMMON;
var->data = NULL;
var->datalen = 0;
var->component = PLPKS_SED_COMPONENT;
@@ -64,28 +61,19 @@ int sed_read_key(char *keyname, char *key, u_int *keylen)
 {
struct plpks_var var;
struct plpks_sed_object_data data;
-   u_int offset;
int ret;
u_int len;
 
plpks_init_var(, keyname);
-   var.data = 
+   var.data = (u8 *)
var.datalen = sizeof(data);
 
ret = plpks_read_os_var();
if (ret != 0)
return ret;
 
-   offset = offsetof(struct plpks_sed_object_data, key);
-   if (offset > var.datalen) {
-   return -EINVAL;
-   }
-
-   len = min(be32_to_cpu(data.key_len), *keylen);
-
+   len = min_t(u16, be32_to_cpu(data.key_len), var.datalen);
memcpy(key, data.key, len);
-   kfree(var.data);
-
key[len] = '\0';
*keylen = len;
 
diff --git a/block/Kconfig b/block/Kconfig
index 76b23114fdeb..75d4db34df5a 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -182,6 +182,7 @@ config BLK_SED_OPAL
bool "Logic for interfacing with Opal enabled SEDs"
depends on KEYS
select PSERIES_PLPKS if PPC_PSERIES
+   select PSERIES_PLPKS_SED if PPC_PSERIES
help
Builds Logic for interfacing with Opal enabled controllers.
Enabling this option enables users to setup/unlock/lock
-- 
gjo...@linux.vnet.ibm.com



[PATCH 3/4] block: sed-opal: keystore access for SED Opal keys

2023-05-05 Thread gjoyce
From: Greg Joyce 

Allow for permanent SED authentication keys by
reading/writing to the SED Opal non-volatile keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/sed-opal.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/block/sed-opal.c b/block/sed-opal.c
index 7f5f235a9048..1e8cfa00b609 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2803,7 +2804,13 @@ static int opal_set_new_pw(struct opal_dev *dev, struct 
opal_new_pw *opal_pw)
if (ret)
return ret;
 
-   /* update keyring with new password */
+   /* update keyring and key store with new password */
+   ret = sed_write_key(OPAL_AUTH_KEY,
+   opal_pw->new_user_pw.opal_key.key,
+   opal_pw->new_user_pw.opal_key.key_len);
+   if (ret != -EOPNOTSUPP)
+   pr_warn("error updating SED key: %d\n", ret);
+
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);
@@ -3050,6 +3057,8 @@ EXPORT_SYMBOL_GPL(sed_ioctl);
 static int __init sed_opal_init(void)
 {
struct key *kr;
+   char init_sed_key[OPAL_KEY_MAX];
+   int keylen = OPAL_KEY_MAX - 1;
 
kr = keyring_alloc(".sed_opal",
   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
@@ -3062,6 +3071,11 @@ static int __init sed_opal_init(void)
 
sed_opal_keyring = kr;
 
-   return 0;
+   if (sed_read_key(OPAL_AUTH_KEY, init_sed_key, ) < 0) {
+   memset(init_sed_key, '\0', sizeof(init_sed_key));
+   keylen = OPAL_KEY_MAX - 1;
+   }
+
+   return update_sed_opal_key(OPAL_AUTH_KEY, init_sed_key, keylen);
 }
 late_initcall(sed_opal_init);
-- 
gjo...@linux.vnet.ibm.com



[PATCH 1/4] block:sed-opal: SED Opal keystore

2023-05-05 Thread gjoyce
From: Greg Joyce 

Add read and write functions that allow SED Opal keys to stored
in a permanent keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/Makefile   |  2 +-
 block/sed-opal-key.c | 24 
 include/linux/sed-opal-key.h | 15 +++
 3 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

diff --git a/block/Makefile b/block/Makefile
index 4e01bb71ad6e..464a9f209552 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -35,7 +35,7 @@ obj-$(CONFIG_BLK_DEV_ZONED)   += blk-zoned.o
 obj-$(CONFIG_BLK_WBT)  += blk-wbt.o
 obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
 obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
-obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
+obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o sed-opal-key.o
 obj-$(CONFIG_BLK_PM)   += blk-pm.o
 obj-$(CONFIG_BLK_INLINE_ENCRYPTION)+= blk-crypto.o blk-crypto-profile.o \
   blk-crypto-sysfs.o
diff --git a/block/sed-opal-key.c b/block/sed-opal-key.c
new file mode 100644
index ..16f380164c44
--- /dev/null
+++ b/block/sed-opal-key.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+int __weak sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   return -EOPNOTSUPP;
+}
+
+int __weak sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   return -EOPNOTSUPP;
+}
diff --git a/include/linux/sed-opal-key.h b/include/linux/sed-opal-key.h
new file mode 100644
index ..c9b1447986d8
--- /dev/null
+++ b/include/linux/sed-opal-key.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+
+int sed_read_key(char *keyname, char *key, u_int *keylen);
+int sed_write_key(char *keyname, char *key, u_int keylen);
-- 
gjo...@linux.vnet.ibm.com



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

2023-05-05 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Jonathan Derrick 
---
 block/Kconfig |   2 +
 block/sed-opal.c  | 174 +-
 include/linux/sed-opal.h  |   3 +
 include/uapi/linux/sed-opal.h |   8 +-
 4 files changed, 184 insertions(+), 3 deletions(-)

diff --git a/block/Kconfig b/block/Kconfig
index 941b2dca70db..76b23114fdeb 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -180,6 +180,8 @@ config BLK_DEBUG_FS_ZONED
 
 config BLK_SED_OPAL
bool "Logic for interfacing with Opal enabled SEDs"
+   depends on KEYS
+   select PSERIES_PLPKS if PPC_PSERIES
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 5b277eaabbc7..7f5f235a9048 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -20,6 +20,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #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),
+ _type_user, key_name, true);
+
+   if (IS_ERR(kref))
+   ret = PTR_ERR(kref);
+
+   key = key_ref_to_ptr(kref);
+   down_read(>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(>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 > U8_MAX) {
+   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;
@@ -2271,6 +2371,9 @@ static int opal_secure_erase_locking_range(struct 
opal_dev *dev,
};
int ret;
 
+   ret = opal_get_key(dev, _session->opal_key);
+   if (ret)
+   return ret;
mutex_lock(>dev_lock);
setup_opal_dev(dev);
ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2304,6 +2407,9 @@ static int opal_revertlsp(struct opal_dev 

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

2023-05-05 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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 c320093c14f1..b55a8eb29f5b 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 */
 
@@ -559,13 +571,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, _step, 0);
@@ -2247,6 +2259,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_lock);
+   setup_opal_dev(dev);
+   ret = execute_step(dev, _step, 0);
+   mutex_unlock(>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)
 {
@@ -2814,6 +2842,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 31ac562a17d7..8e824ab908e9 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_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 d7a1524023db..98f216cf2241 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -151,6 +151,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)
@@ -168,5 +173,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 */
-- 
gjo...@linux.vnet.ibm.com



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

2023-05-05 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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 = 0x06,
 };
 
+enum opal_revertlsp {
+   OPAL_KEEP_GLOBAL_RANGE_KEY = 0x06,
+};
+
 /* 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 b55a8eb29f5b..5b277eaabbc7 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -1634,6 +1634,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(, dev, OPAL_STARTNAME);
+   add_token_u64(, dev, OPAL_KEEP_GLOBAL_RANGE_KEY);
+   add_token_u8(, dev, (rev->options & OPAL_PRESERVE) ?
+   OPAL_TRUE : OPAL_FALSE);
+   add_token_u8(, 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;
@@ -2275,6 +2295,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, >key },
+   { revert_lsp, rev }
+   };
+   int ret;
+
+   mutex_lock(>dev_lock);
+   setup_opal_dev(dev);
+   ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
+   mutex_unlock(>dev_lock);
+
+   return ret;
+}
+
 static int opal_erase_locking_range(struct opal_dev *dev,
struct opal_session_info *opal_session)
 {
@@ -2842,6 +2879,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 8e824ab908e9..bf2f9d7e11eb 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -46,6 +46,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 98f216cf2241..720725f1c42a 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -56,6 +56,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;
@@ -156,6 +160,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)
@@ -174,5 +184,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 */
-- 

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

2023-05-05 Thread gjoyce
From: Greg Joyce 

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 v4:
- rebase to 6.3-rc7
- replaced "255" magic number with U8_MAX

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 |   2 +
 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, 282 insertions(+), 6 deletions(-)

Signed-off-by: Greg Joyce 
base-commit: 6a8f57ae2eb07ab39a6f0ccad60c760743051026
-- 
gjo...@linux.vnet.ibm.com



[PATCH v5 0/3] generic and PowerPC SED Opal keystore

2022-11-30 Thread gjoyce
From: Greg Joyce 

Changelog v5:
- added check for key length based on review comment by
  "Elliott, Robert (Servers)" 

Changelog v4:
- scope reduced to cover just SED Opal keys
- base SED Opal keystore is now in SED block driver
- removed use of enum to indicate type
- refactored common code into common function that read and
  write use
- removed cast to void
- added use of SED Opal keystore functions to SED block driver

Generic functions have been defined for accessing SED Opal keys.
The generic functions are defined as weak so that they may be superseded
by keystore specific versions.

PowerPC/pseries versions of these functions provide read/write access
to SED Opal keys in the PLPKS keystore.

The SED block driver has been modified to read the SED Opal
keystore to populate a key in the SED Opal keyring. Changes to the
SED Opal key will be written to the SED Opal keystore.


Greg Joyce (3):
  block: sed-opal: SED Opal keystore
  powerpc/pseries: PLPKS SED Opal keystore support
  block: sed-opal: keystore access for SED Opal keys

 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 129 ++
 block/Makefile|   2 +-
 block/sed-opal-key.c  |  23 
 block/sed-opal.c  |  18 ++-
 include/linux/sed-opal-key.h  |  15 ++
 6 files changed, 185 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

-- 
gjo...@linux.vnet.ibm.com



[PATCH v5 3/3] block: sed-opal: keystore access for SED Opal keys

2022-11-30 Thread gjoyce
From: Greg Joyce 

Allow for permanent SED authentication keys by
reading/writing to the SED Opal non-volatile keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/sed-opal.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/block/sed-opal.c b/block/sed-opal.c
index a8729892178b..e280631b932e 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2762,7 +2763,13 @@ static int opal_set_new_pw(struct opal_dev *dev, struct 
opal_new_pw *opal_pw)
if (ret)
return ret;
 
-   /* update keyring with new password */
+   /* update keyring and key store with new password */
+   ret = sed_write_key(OPAL_AUTH_KEY,
+   opal_pw->new_user_pw.opal_key.key,
+   opal_pw->new_user_pw.opal_key.key_len);
+   if (ret != -EOPNOTSUPP)
+   pr_warn("error updating SED key: %d\n", ret);
+
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);
@@ -3009,6 +3016,8 @@ EXPORT_SYMBOL_GPL(sed_ioctl);
 static int __init sed_opal_init(void)
 {
struct key *kr;
+   char init_sed_key[OPAL_KEY_MAX];
+   int keylen = OPAL_KEY_MAX;
 
kr = keyring_alloc(".sed_opal",
   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
@@ -3021,6 +3030,11 @@ static int __init sed_opal_init(void)
 
sed_opal_keyring = kr;
 
-   return 0;
+   if (sed_read_key(OPAL_AUTH_KEY, init_sed_key, ) < 0) {
+   memset(init_sed_key, '\0', sizeof(init_sed_key));
+   keylen = OPAL_KEY_MAX;
+   }
+
+   return update_sed_opal_key(OPAL_AUTH_KEY, init_sed_key, keylen);
 }
 late_initcall(sed_opal_init);
-- 
gjo...@linux.vnet.ibm.com



[PATCH v5 2/3] powerpc/pseries: PLPKS SED Opal keystore support

2022-11-30 Thread gjoyce
From: Greg Joyce 

Define operations for SED Opal to read/write keys
from POWER LPAR Platform KeyStore(PLPKS). This allows
for non-volatile storage of SED Opal keys.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 129 ++
 2 files changed, 130 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c

diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 92310202bdd7..5bedc06ee2cc 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_PPC_SPLPAR)  += vphn.o
 obj-$(CONFIG_PPC_SVM)  += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
+obj-$(CONFIG_PSERIES_PLPKS) += plpks_sed_ops.o
 
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c 
b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
new file mode 100644
index ..cd1084d07716
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform specific code for non-volatile SED key access
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for SED Opal to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * Self Encrypting Drives(SED) key storage using PLPKS
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "plpks.h"
+
+/*
+ * structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+#define PLPKS_PLATVAR_POLICYWORLDREADABLE
+#define PLPKS_PLATVAR_OS_COMMON 4
+
+#define PLPKS_SED_OBJECT_DATA_V00
+#define PLPKS_SED_MANGLED_LABEL "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+#define PLPKS_SED_KEY   "opal-boot-pin"
+
+/*
+ * authority is admin1 and range is global
+ */
+#define PLPKS_SED_AUTHORITY  0x000900010001
+#define PLPKS_SED_RANGE  0x08020001
+
+void plpks_init_var(struct plpks_var *var, char *keyname)
+{
+   var->name = keyname;
+   var->namelen = strlen(keyname);
+   if (strcmp(PLPKS_SED_KEY, keyname) == 0) {
+   var->name = PLPKS_SED_MANGLED_LABEL;
+   var->namelen = strlen(keyname);
+   }
+   var->policy = PLPKS_PLATVAR_POLICY;
+   var->os = PLPKS_PLATVAR_OS_COMMON;
+   var->data = NULL;
+   var->datalen = 0;
+   var->component = PLPKS_SED_COMPONENT;
+}
+
+/*
+ * Read the SED Opal key from PLPKS given the label
+ */
+int sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data *data;
+   u_int offset;
+   int ret;
+   u_int len;
+
+   plpks_init_var(, keyname);
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   offset = offsetof(struct plpks_sed_object_data, key);
+   if (offset > var.datalen) {
+   kfree(var.data);
+   return -EINVAL;
+   }
+
+   data = (struct plpks_sed_object_data *)var.data;
+   len = min(be32_to_cpu(data->key_len), *keylen);
+
+   if (var.data) {
+   memcpy(key, data->key, len);
+   kfree(var.data);
+   } else
+   len = 0;
+
+   key[len] = '\0';
+   *keylen = len;
+
+   return 0;
+}
+
+/*
+ * Write the SED Opal key to PLPKS given the label
+ */
+int sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   plpks_init_var(, keyname);
+
+   var.datalen = sizeof(struct plpks_sed_object_data);
+   var.data = (u8 *)
+
+   /* initialize SED object */
+   data.version = PLPKS_SED_OBJECT_DATA_V0;
+   data.authority = cpu_to_be64(PLPKS_SED_AUTHORITY);
+   data.range = cpu_to_be64(PLPKS_SED_RANGE);
+   memset(, '\0', sizeof(data.pad1));
+   data.key_len = cpu_to_be32(keylen);
+   memcpy(data.key, (char *)key, keylen);
+
+   /*
+* Key update requires remove first. The return value
+* is ignored since it's okay if the key doesn't exist.
+*/
+   vname.namelen = var.namelen;
+   vname.name = var.name;
+   plpks_remove_var(var.component, var.os, vname);
+
+   return plpks_write_var(var);
+}
-- 
gjo...@linux.vnet.ibm.com



[PATCH v5 1/3] block: sed-opal: SED Opal keystore

2022-11-30 Thread gjoyce
From: Greg Joyce 

Add read and write functions that allow SED Opal keys to stored
in a permanent keystore.

Signed-off-by: Greg Joyce 
Reviewed-by: Jonathan Derrick 
---
 block/Makefile   |  2 +-
 block/sed-opal-key.c | 23 +++
 include/linux/sed-opal-key.h | 15 +++
 3 files changed, 39 insertions(+), 1 deletion(-)
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

diff --git a/block/Makefile b/block/Makefile
index 4e01bb71ad6e..464a9f209552 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -35,7 +35,7 @@ obj-$(CONFIG_BLK_DEV_ZONED)   += blk-zoned.o
 obj-$(CONFIG_BLK_WBT)  += blk-wbt.o
 obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
 obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
-obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
+obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o sed-opal-key.o
 obj-$(CONFIG_BLK_PM)   += blk-pm.o
 obj-$(CONFIG_BLK_INLINE_ENCRYPTION)+= blk-crypto.o blk-crypto-profile.o \
   blk-crypto-sysfs.o
diff --git a/block/sed-opal-key.c b/block/sed-opal-key.c
new file mode 100644
index ..32ef988cd53b
--- /dev/null
+++ b/block/sed-opal-key.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+#include 
+
+int __weak sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   return -EOPNOTSUPP;
+}
+
+int __weak sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   return -EOPNOTSUPP;
+}
diff --git a/include/linux/sed-opal-key.h b/include/linux/sed-opal-key.h
new file mode 100644
index ..c9b1447986d8
--- /dev/null
+++ b/include/linux/sed-opal-key.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+
+int sed_read_key(char *keyname, char *key, u_int *keylen);
+int sed_write_key(char *keyname, char *key, u_int keylen);
-- 
gjo...@linux.vnet.ibm.com



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

2022-11-29 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Jonathan Derrick 
---
 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 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #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),
+ _type_user, key_name, true);
+
+   if (IS_ERR(kref))
+   ret = PTR_ERR(kref);
+
+   key = key_ref_to_ptr(kref);
+   down_read(>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(>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, _session->opal_key);
+   if (ret)
+   return ret;
mutex_lock(>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)
};
 

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

2022-11-29 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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 = 0x06,
 };
 
+enum opal_revertlsp {
+   OPAL_KEEP_GLOBAL_RANGE_KEY = 0x06,
+};
+
 /* 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(, dev, OPAL_STARTNAME);
+   add_token_u64(, dev, OPAL_KEEP_GLOBAL_RANGE_KEY);
+   add_token_u8(, dev, (rev->options & OPAL_PRESERVE) ?
+   OPAL_TRUE : OPAL_FALSE);
+   add_token_u8(, 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, >key },
+   { revert_lsp, rev }
+   };
+   int ret;
+
+   mutex_lock(>dev_lock);
+   setup_opal_dev(dev);
+   ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
+   mutex_unlock(>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 */
-- 

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

2022-11-29 Thread gjoyce
From: Greg Joyce 

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 
Reviewed-by: Christoph Hellwig 
Reviewed-by: Jonathan Derrick 
---
 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, _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_lock);
+   setup_opal_dev(dev);
+   ret = execute_step(dev, _step, 0);
+   mutex_unlock(>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 */
-- 
gjo...@linux.vnet.ibm.com



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

2022-11-29 Thread gjoyce
From: Greg Joyce 

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 
base-commit: 59d0d52c30d4991ac4b329f049cc37118e00f5b0
-- 
gjo...@linux.vnet.ibm.com



[PATCH v4 3/3] block: sed-opal: keystore access for SED Opal keys

2022-08-19 Thread gjoyce
From: Greg Joyce 

Allow for permanent SED authentication keys by
reading/writing to the SED Opal non-volatile keystore.

Signed-off-by: Greg Joyce 
---
 block/sed-opal.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/block/sed-opal.c b/block/sed-opal.c
index 3bdb31cf3e7c..11b0eb3a656b 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2697,7 +2698,13 @@ static int opal_set_new_pw(struct opal_dev *dev, struct 
opal_new_pw *opal_pw)
if (ret)
return ret;
 
-   /* update keyring with new password */
+   /* update keyring and arch var with new password */
+   ret = sed_write_key(OPAL_AUTH_KEY,
+   opal_pw->new_user_pw.opal_key.key,
+   opal_pw->new_user_pw.opal_key.key_len);
+   if (ret != -EOPNOTSUPP)
+   pr_warn("error updating SED key: %d\n", ret);
+
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);
@@ -2920,6 +2927,8 @@ EXPORT_SYMBOL_GPL(sed_ioctl);
 static int __init sed_opal_init(void)
 {
struct key *kr;
+   char init_sed_key[OPAL_KEY_MAX];
+   int keylen = OPAL_KEY_MAX;
 
kr = keyring_alloc(".sed_opal",
   GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, current_cred(),
@@ -2932,6 +2941,11 @@ static int __init sed_opal_init(void)
 
sed_opal_keyring = kr;
 
-   return 0;
+   if (sed_read_key(OPAL_AUTH_KEY, init_sed_key, ) < 0) {
+   memset(init_sed_key, '\0', sizeof(init_sed_key));
+   keylen = OPAL_KEY_MAX;
+   }
+
+   return update_sed_opal_key(OPAL_AUTH_KEY, init_sed_key, keylen);
 }
 late_initcall(sed_opal_init);
-- 
gjo...@linux.vnet.ibm.com



[PATCH v4 2/3] powerpc/pseries: PLPKS SED Opal keystore support

2022-08-19 Thread gjoyce
From: Greg Joyce 

Define operations for SED Opal to read/write keys
from POWER LPAR Platform KeyStore(PLPKS). This allows
for non-volatile storage of SED Opal keys.

Signed-off-by: Greg Joyce 
---
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 124 ++
 2 files changed, 125 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c

diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 14e143b946a3..b7fea9e48a58 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_SPLPAR)  += vphn.o
 obj-$(CONFIG_PPC_SVM)  += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
+obj-$(CONFIG_PSERIES_PLPKS) += plpks_sed_ops.o
 
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
diff --git a/arch/powerpc/platforms/pseries/plpks_sed_ops.c 
b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
new file mode 100644
index ..833226738448
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_sed_ops.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform specific code for non-volatile SED key access
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for SED Opal to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * Self Encrypting Drives(SED) key storage using PLPKS
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "plpks.h"
+
+/*
+ * structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+#define PLPKS_PLATVAR_POLICYWORLDREADABLE
+#define PLPKS_PLATVAR_OS_COMMON 4
+
+#define PLPKS_SED_OBJECT_DATA_V00
+#define PLPKS_SED_MANGLED_LABEL "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+#define PLPKS_SED_KEY   "opal-boot-pin"
+
+/*
+ * authority is admin1 and range is global
+ */
+#define PLPKS_SED_AUTHORITY  0x000900010001
+#define PLPKS_SED_RANGE  0x08020001
+
+void plpks_init_var(struct plpks_var *var, char *keyname)
+{
+   var->name = keyname;
+   var->namelen = strlen(keyname);
+   if (strcmp(PLPKS_SED_KEY, keyname) == 0) {
+   var->name = PLPKS_SED_MANGLED_LABEL;
+   var->namelen = strlen(keyname);
+   }
+   var->policy = PLPKS_PLATVAR_POLICY;
+   var->os = PLPKS_PLATVAR_OS_COMMON;
+   var->data = NULL;
+   var->datalen = 0;
+   var->component = PLPKS_SED_COMPONENT;
+}
+
+/*
+ * Read the SED Opal key from PLPKS given the label
+ */
+int sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data *data;
+   u_int offset = 0;
+   int ret;
+
+   plpks_init_var(, keyname);
+
+   offset = offsetof(struct plpks_sed_object_data, key);
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   if (offset > var.datalen)
+   offset = 0;
+
+   data = (struct plpks_sed_object_data *)var.data;
+   *keylen = be32_to_cpu(data->key_len);
+
+   if (var.data) {
+   memcpy(key, var.data + offset, var.datalen - offset);
+   key[*keylen] = '\0';
+   kfree(var.data);
+   }
+
+   return 0;
+}
+
+/*
+ * Write the SED Opal key to PLPKS given the label
+ */
+int sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   plpks_init_var(, keyname);
+
+   var.datalen = sizeof(struct plpks_sed_object_data);
+   var.data = (u8 *)
+
+   /* initialize SED object */
+   data.version = PLPKS_SED_OBJECT_DATA_V0;
+   data.authority = cpu_to_be64(PLPKS_SED_AUTHORITY);
+   data.range = cpu_to_be64(PLPKS_SED_RANGE);
+   memset(, '\0', sizeof(data.pad1));
+   data.key_len = cpu_to_be32(keylen);
+   memcpy(data.key, (char *)key, keylen);
+
+   /*
+* Key update requires remove first. The return value
+* is ignored since it's okay if the key doesn't exist.
+*/
+   vname.namelen = var.namelen;
+   vname.name = var.name;
+   plpks_remove_var(var.component, var.os, vname);
+
+   return plpks_write_var(var);
+}
-- 
gjo...@linux.vnet.ibm.com



[PATCH v4 0/3] generic and PowerPC SED Opal keystore

2022-08-19 Thread gjoyce
From: Greg Joyce 

Generic functions have been defined for accessing SED Opal keys.
The generic functions are defined as weak so that they may be superseded
by keystore specific versions.

PowerPC/pseries versions of these functions provide read/write access
to SED Opal keys in the PLPKS keystore.

The SED block driver has been modified to read the SED Opal
keystore to populate a key in the SED Opal keyring. Changes to the
SED Opal key will be written to the SED Opal keystore.

Patch 3 "keystore access for SED Opal keys" is dependent on:

https://lore.kernel.org/keyrings/20220818143045.680972-4-gjo...@linux.vnet.ibm.com/T/#u

Changelog
v4:
- scope reduced to cover just SED Opal keys
- base SED Opal keystore is now in SED block driver
- removed use of enum to indicate type
- refactored common code into common function that read and
  write use
- removed cast to void
- added use of SED Opal keystore functions to SED block driver

v3:
- No code changes, but per reviewer requests, adding additional
  mailing lists(keyring, EFI) for wider review.

v2:
- Include feedback from Gregory Joyce, Eric Richter and
  Murilo Opsfelder Araujo.
- Include suggestions from Michael Ellerman.
- Moved a dependency from generic SED code to this patchset.
  This patchset now builds of its own.

Greg Joyce (3):
  block: sed-opal: SED Opal keystore
  powerpc/pseries: PLPKS SED Opal keystore support
  block: sed-opal: keystore access for SED Opal keys

 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../powerpc/platforms/pseries/plpks_sed_ops.c | 124 ++
 block/Makefile|   2 +-
 block/sed-opal-key.c  |  23 
 block/sed-opal.c  |  17 ++-
 include/linux/sed-opal-key.h  |  15 +++
 6 files changed, 179 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_sed_ops.c
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

-- 
gjo...@linux.vnet.ibm.com



[PATCH v4 1/3] block: sed-opal: SED Opal keystore

2022-08-19 Thread gjoyce
From: Greg Joyce 

Add read and write functions that allow SED Opal keys to stored
in a permanent keystore.

Signed-off-by: Greg Joyce 
---
 block/Makefile   |  2 +-
 block/sed-opal-key.c | 23 +++
 include/linux/sed-opal-key.h | 15 +++
 3 files changed, 39 insertions(+), 1 deletion(-)
 create mode 100644 block/sed-opal-key.c
 create mode 100644 include/linux/sed-opal-key.h

diff --git a/block/Makefile b/block/Makefile
index 4e01bb71ad6e..464a9f209552 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -35,7 +35,7 @@ obj-$(CONFIG_BLK_DEV_ZONED)   += blk-zoned.o
 obj-$(CONFIG_BLK_WBT)  += blk-wbt.o
 obj-$(CONFIG_BLK_DEBUG_FS) += blk-mq-debugfs.o
 obj-$(CONFIG_BLK_DEBUG_FS_ZONED)+= blk-mq-debugfs-zoned.o
-obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o
+obj-$(CONFIG_BLK_SED_OPAL) += sed-opal.o sed-opal-key.o
 obj-$(CONFIG_BLK_PM)   += blk-pm.o
 obj-$(CONFIG_BLK_INLINE_ENCRYPTION)+= blk-crypto.o blk-crypto-profile.o \
   blk-crypto-sysfs.o
diff --git a/block/sed-opal-key.c b/block/sed-opal-key.c
new file mode 100644
index ..32ef988cd53b
--- /dev/null
+++ b/block/sed-opal-key.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+#include 
+
+int __weak sed_read_key(char *keyname, char *key, u_int *keylen)
+{
+   return -EOPNOTSUPP;
+}
+
+int __weak sed_write_key(char *keyname, char *key, u_int keylen)
+{
+   return -EOPNOTSUPP;
+}
diff --git a/include/linux/sed-opal-key.h b/include/linux/sed-opal-key.h
new file mode 100644
index ..c9b1447986d8
--- /dev/null
+++ b/include/linux/sed-opal-key.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SED key operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for SED Opal
+ * keys. Specific keystores can provide overrides.
+ *
+ */
+
+#include 
+
+int sed_read_key(char *keyname, char *key, u_int *keylen);
+int sed_write_key(char *keyname, char *key, u_int keylen);
-- 
gjo...@linux.vnet.ibm.com



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

2022-08-18 Thread gjoyce
From: Greg Joyce 

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 
---
 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 50b17e260fa2..f65169e9356b 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -182,6 +182,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 2916b9539b84..3bdb31cf3e7c 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -20,6 +20,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #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;
@@ -266,6 +271,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),
+ _type_user, key_name, true);
+
+   if (IS_ERR(kref))
+   ret = PTR_ERR(kref);
+
+   key = key_ref_to_ptr(kref);
+   down_read(>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(>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;
@@ -2204,6 +2304,9 @@ static int opal_secure_erase_locking_range(struct 
opal_dev *dev,
};
int ret;
 
+   ret = opal_get_key(dev, _session->opal_key);
+   if (ret)
+   return ret;
mutex_lock(>dev_lock);
setup_opal_dev(dev);
ret = execute_steps(dev, erase_steps, ARRAY_SIZE(erase_steps));
@@ -2237,6 +2340,9 @@ static int opal_revertlsp(struct opal_dev *dev, struct 
opal_revert_lsp *rev)
};
int ret;
 
+   ret = 

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

2022-08-18 Thread gjoyce
From: Greg Joyce 

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 
---
 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 9700197000f2..e4d8fbdc9dad 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -426,8 +426,12 @@ 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;
@@ -443,6 +447,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 */
 
@@ -517,13 +530,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, _step, 0);
@@ -2179,6 +2192,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_lock);
+   setup_opal_dev(dev);
+   ret = execute_step(dev, _step, 0);
+   mutex_unlock(>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)
 {
@@ -2685,6 +2714,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, 
void __user *arg)
case IOC_OPAL_GENERIC_TABLE_RW:
ret = opal_generic_read_write_table(dev, p);
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 1ac0d712a9c3..9197b7a628f2 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -43,6 +43,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
case IOC_OPAL_MBR_DONE:
case IOC_OPAL_WRITE_SHADOW_MBR:
case IOC_OPAL_GENERIC_TABLE_RW:
+   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 6f5af1a84213..89dd108b426f 100644
--- a/include/uapi/linux/sed-opal.h
+++ b/include/uapi/linux/sed-opal.h
@@ -132,6 +132,11 @@ struct opal_read_write_table {
__u64 priv;
 };
 
+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)
@@ -148,5 +153,6 @@ struct opal_read_write_table {
 #define IOC_OPAL_MBR_DONE   _IOW('p', 233, struct opal_mbr_done)
 #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_DISCOVERY  _IOW('p', 236, struct opal_discovery)
 
 #endif /* _UAPI_SED_OPAL_H */
-- 
2.27.0



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

2022-08-18 Thread gjoyce
From: Greg Joyce 

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 
---
 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 b486b3ec7dc4..6127c08267f8 100644
--- a/block/opal_proto.h
+++ b/block/opal_proto.h
@@ -210,6 +210,10 @@ enum opal_parameter {
OPAL_SUM_SET_LIST = 0x06,
 };
 
+enum opal_revertlsp {
+   OPAL_KEEP_GLOBAL_RANGE_KEY = 0x06,
+};
+
 /* 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 e4d8fbdc9dad..2916b9539b84 100644
--- a/block/sed-opal.c
+++ b/block/sed-opal.c
@@ -1593,6 +1593,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(, dev, OPAL_STARTNAME);
+   add_token_u64(, dev, OPAL_KEEP_GLOBAL_RANGE_KEY);
+   add_token_u8(, dev, (rev->options & OPAL_PRESERVE) ?
+   OPAL_TRUE : OPAL_FALSE);
+   add_token_u8(, 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;
@@ -2208,6 +2228,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, >key },
+   { revert_lsp, rev }
+   };
+   int ret;
+
+   mutex_lock(>dev_lock);
+   setup_opal_dev(dev);
+   ret = execute_steps(dev, steps, ARRAY_SIZE(steps));
+   mutex_unlock(>dev_lock);
+
+   return ret;
+}
+
 static int opal_erase_locking_range(struct opal_dev *dev,
struct opal_session_info *opal_session)
 {
@@ -2714,6 +2751,9 @@ int sed_ioctl(struct opal_dev *dev, unsigned int cmd, 
void __user *arg)
case IOC_OPAL_GENERIC_TABLE_RW:
ret = opal_generic_read_write_table(dev, p);
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 9197b7a628f2..3a6082ff97e7 100644
--- a/include/linux/sed-opal.h
+++ b/include/linux/sed-opal.h
@@ -43,6 +43,7 @@ static inline bool is_sed_ioctl(unsigned int cmd)
case IOC_OPAL_MBR_DONE:
case IOC_OPAL_WRITE_SHADOW_MBR:
case IOC_OPAL_GENERIC_TABLE_RW:
+   case IOC_OPAL_REVERT_LSP:
case IOC_OPAL_DISCOVERY:
return true;
}
diff --git a/include/uapi/linux/sed-opal.h b/include/uapi/linux/sed-opal.h
index 89dd108b426f..bc91987a6328 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;
@@ -137,6 +141,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)
@@ -154,5 +164,6 @@ struct opal_discovery {
 #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_DISCOVERY  _IOW('p', 236, struct opal_discovery)
+#define IOC_OPAL_REVERT_LSP _IOW('p', 237, struct opal_revert_lsp)
 
 #endif /* _UAPI_SED_OPAL_H */
-- 
2.27.0



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

2022-08-18 Thread gjoyce
From: Greg Joyce 

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:
- 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 Opal 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 
Reported-by: kernel test robot 
base-commit: ff6992735ade75aae3e35d16b17da1008d753d28
-- 
2.27.0



[PATCH v3a 1/2] lib: generic accessor functions for arch keystore

2022-08-08 Thread gjoyce
From: Greg Joyce 

Generic kernel subsystems may rely on platform specific persistent
KeyStore to store objects containing sensitive key material. In such case,
they need to access architecture specific functions to perform read/write
operations on these variables.

Define the generic variable read/write prototypes to be implemented by
architecture specific versions. The default(weak) implementations of
these prototypes return -EOPNOTSUPP unless overridden by architecture
versions.

Signed-off-by: Greg Joyce 
---
 include/linux/arch_vars.h | 23 +++
 lib/Makefile  |  2 +-
 lib/arch_vars.c   | 25 +
 3 files changed, 49 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/arch_vars.h
 create mode 100644 lib/arch_vars.c

diff --git a/include/linux/arch_vars.h b/include/linux/arch_vars.h
new file mode 100644
index ..9c280ff9432e
--- /dev/null
+++ b/include/linux/arch_vars.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Platform variable opearations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for architecture specific
+ * variables. Specific architectures can provide overrides.
+ *
+ */
+
+#include 
+
+enum arch_variable_type {
+   ARCH_VAR_OPAL_KEY  = 0, /* SED Opal Authentication Key */
+   ARCH_VAR_OTHER = 1, /* Other type of variable */
+   ARCH_VAR_MAX   = 1, /* Maximum type value */
+};
+
+int arch_read_variable(enum arch_variable_type type, char *varname,
+  void *varbuf, u_int *varlen);
+int arch_write_variable(enum arch_variable_type type, char *varname,
+   void *varbuf, u_int varlen);
diff --git a/lib/Makefile b/lib/Makefile
index f99bf61f8bbc..b90c4cb0dbbb 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -48,7 +48,7 @@ obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
 bsearch.o find_bit.o llist.o memweight.o kfifo.o \
 percpu-refcount.o rhashtable.o \
 once.o refcount.o usercopy.o errseq.o bucket_locks.o \
-generic-radix-tree.o
+generic-radix-tree.o arch_vars.o
 obj-$(CONFIG_STRING_SELFTEST) += test_string.o
 obj-y += string_helpers.o
 obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
diff --git a/lib/arch_vars.c b/lib/arch_vars.c
new file mode 100644
index ..e6f16d7d09c1
--- /dev/null
+++ b/lib/arch_vars.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Platform variable operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for architecture specific
+ * variables. Specific architectures can provide overrides.
+ *
+ */
+
+#include 
+#include 
+
+int __weak arch_read_variable(enum arch_variable_type type, char *varname,
+ void *varbuf, u_int *varlen)
+{
+   return -EOPNOTSUPP;
+}
+
+int __weak arch_write_variable(enum arch_variable_type type, char *varname,
+  void *varbuf, u_int varlen)
+{
+   return -EOPNOTSUPP;
+}
-- 
2.27.0



[PATCH v3a 2/2] powerpc/pseries: Override lib/arch_vars.c functions

2022-08-08 Thread gjoyce
From: Greg Joyce 

Self Encrypting Drives(SED) make use of POWER LPAR Platform KeyStore
for storing its variables. Thus the block subsystem needs to access
PowerPC specific functions to read/write objects in PLPKS.

Override the default implementations in lib/arch_vars.c file with
PowerPC specific versions.

Signed-off-by: Greg Joyce 
---
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../platforms/pseries/plpks_arch_ops.c| 167 ++
 2 files changed, 168 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_arch_ops.c

diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 14e143b946a3..3a545422eae5 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_SPLPAR)  += vphn.o
 obj-$(CONFIG_PPC_SVM)  += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
+obj-$(CONFIG_PSERIES_PLPKS) += plpks_arch_ops.o
 
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
diff --git a/arch/powerpc/platforms/pseries/plpks_arch_ops.c 
b/arch/powerpc/platforms/pseries/plpks_arch_ops.c
new file mode 100644
index ..fdea3322f696
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_arch_ops.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform arch specific code for SED
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for generic kernel subsystems to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * List of subsystems/usecase using PLPKS:
+ * - Self Encrypting Drives(SED)
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "plpks.h"
+
+/*
+ * variable structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+/*
+ * ext_type values
+ * 00no extension exists
+ * 01-1F common
+ * 20-3F AIX
+ * 40-5F Linux
+ * 60-7F IBMi
+ */
+
+/*
+ * This extension is optional for version 1 sed_object_data
+ */
+struct sed_object_extension {
+   u8 ext_type;
+   u8 rsvd[3];
+   u8 ext_data[64];
+};
+
+#define PKS_SED_OBJECT_DATA_V1  1
+#define PKS_SED_MANGLED_LABEL   "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+
+#define PLPKS_ARCHVAR_POLICYWORLDREADABLE
+#define PLPKS_ARCHVAR_OS_COMMON 4
+
+/*
+ * Read the variable data from PKS given the label
+ */
+int arch_read_variable(enum arch_variable_type type, char *varname,
+  void *varbuf, u_int *varlen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data *data;
+   u_int offset = 0;
+   char *buf = (char *)varbuf;
+   int ret;
+
+   var.name = varname;
+   var.namelen = strlen(varname);
+   var.policy = PLPKS_ARCHVAR_POLICY;
+   var.os = PLPKS_ARCHVAR_OS_COMMON;
+   var.data = NULL;
+   var.datalen = 0;
+
+   switch (type) {
+   case ARCH_VAR_OPAL_KEY:
+   var.component = PLPKS_SED_COMPONENT;
+#ifdef OPAL_AUTH_KEY
+   if (strcmp(OPAL_AUTH_KEY, varname) == 0) {
+   var.name = PKS_SED_MANGLED_LABEL;
+   var.namelen = strlen(varname);
+   }
+#endif
+   offset = offsetof(struct plpks_sed_object_data, key);
+   break;
+   case ARCH_VAR_OTHER:
+   var.component = "";
+   break;
+   }
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   if (offset > var.datalen)
+   offset = 0;
+
+   switch (type) {
+   case ARCH_VAR_OPAL_KEY:
+   data = (struct plpks_sed_object_data *)var.data;
+   *varlen = data->key_len;
+   break;
+   case ARCH_VAR_OTHER:
+   *varlen = var.datalen;
+   break;
+   }
+
+   if (var.data) {
+   memcpy(varbuf, var.data + offset, var.datalen - offset);
+   buf[*varlen] = '\0';
+   kfree(var.data);
+   }
+
+   return 0;
+}
+
+/*
+ * Write the variable data to PKS given the label
+ */
+int arch_write_variable(enum arch_variable_type type, char *varname,
+   void *varbuf, u_int varlen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   var.name = varname;
+   var.namelen = strlen(varname);
+   var.policy = PLPKS_ARCHVAR_POLICY;
+   var.os = PLPKS_ARCHVAR_OS_COMMON;
+   var.datalen = varlen;
+   var.data = varbuf;
+
+   switch (type) {
+   case ARCH_VAR_OPAL_KEY:
+   var.component = PLPKS_SED_COMPONENT;
+#ifdef 

[PATCH v3a 0/2] generic and PowerPC accessor functions for arch keystore

2022-08-08 Thread gjoyce
From: Greg Joyce 

Changelog v3a:
- No code changes, but per reviewer requests, adding additional
  mailing lists(keyring, EFI) for wider review.

Architectural neutral functions have been defined for accessing
architecture specific variable store. The neutral functions are
defined as weak so that they may be superseded by platform
specific versions. The functions have been desigined so that 
they can support a large range of platforms/architectures.

PowerPC/pseries versions of these functions provide read/write access
to the non-volatile PLPKS data store.

This functionality allows kernel code such as the block SED opal
driver to store authentication keys in a secure permanent store.

Greg Joyce (2):
  lib: define generic accessor functions for arch specific keystore
  powerpc/pseries: Override lib/arch_vars.c functions

 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../platforms/pseries/plpks_arch_ops.c| 167 ++
 include/linux/arch_vars.h |  23 +++
 lib/Makefile  |   2 +-
 lib/arch_vars.c   |  25 +++
 5 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_arch_ops.c
 create mode 100644 include/linux/arch_vars.h
 create mode 100644 lib/arch_vars.c


Signed-off-by: Greg Joyce 
base-commit: ff6992735ade75aae3e35d16b17da1008d753d28
-- 
2.27.0



[PATCH v3 2/2] powerpc/pseries: Override lib/arch_vars.c functions

2022-08-01 Thread gjoyce
From: Greg Joyce 

Self Encrypting Drives(SED) make use of POWER LPAR Platform KeyStore
for storing its variables. Thus the block subsystem needs to access
PowerPC specific functions to read/write objects in PLPKS.

Override the default implementations in lib/arch_vars.c file with
PowerPC specific versions.

Signed-off-by: Greg Joyce 
---
 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../platforms/pseries/plpks_arch_ops.c| 167 ++
 2 files changed, 168 insertions(+)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_arch_ops.c

diff --git a/arch/powerpc/platforms/pseries/Makefile 
b/arch/powerpc/platforms/pseries/Makefile
index 14e143b946a3..3a545422eae5 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PPC_SPLPAR)  += vphn.o
 obj-$(CONFIG_PPC_SVM)  += svm.o
 obj-$(CONFIG_FA_DUMP)  += rtas-fadump.o
 obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
+obj-$(CONFIG_PSERIES_PLPKS) += plpks_arch_ops.o
 
 obj-$(CONFIG_SUSPEND)  += suspend.o
 obj-$(CONFIG_PPC_VAS)  += vas.o vas-sysfs.o
diff --git a/arch/powerpc/platforms/pseries/plpks_arch_ops.c 
b/arch/powerpc/platforms/pseries/plpks_arch_ops.c
new file mode 100644
index ..fdea3322f696
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks_arch_ops.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * POWER Platform arch specific code for SED
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * Define operations for generic kernel subsystems to read/write keys
+ * from POWER LPAR Platform KeyStore(PLPKS).
+ *
+ * List of subsystems/usecase using PLPKS:
+ * - Self Encrypting Drives(SED)
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "plpks.h"
+
+/*
+ * variable structure that contains all SED data
+ */
+struct plpks_sed_object_data {
+   u_char version;
+   u_char pad1[7];
+   u_long authority;
+   u_long range;
+   u_int  key_len;
+   u_char key[32];
+};
+
+/*
+ * ext_type values
+ * 00no extension exists
+ * 01-1F common
+ * 20-3F AIX
+ * 40-5F Linux
+ * 60-7F IBMi
+ */
+
+/*
+ * This extension is optional for version 1 sed_object_data
+ */
+struct sed_object_extension {
+   u8 ext_type;
+   u8 rsvd[3];
+   u8 ext_data[64];
+};
+
+#define PKS_SED_OBJECT_DATA_V1  1
+#define PKS_SED_MANGLED_LABEL   "/default/pri"
+#define PLPKS_SED_COMPONENT "sed-opal"
+
+#define PLPKS_ARCHVAR_POLICYWORLDREADABLE
+#define PLPKS_ARCHVAR_OS_COMMON 4
+
+/*
+ * Read the variable data from PKS given the label
+ */
+int arch_read_variable(enum arch_variable_type type, char *varname,
+  void *varbuf, u_int *varlen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data *data;
+   u_int offset = 0;
+   char *buf = (char *)varbuf;
+   int ret;
+
+   var.name = varname;
+   var.namelen = strlen(varname);
+   var.policy = PLPKS_ARCHVAR_POLICY;
+   var.os = PLPKS_ARCHVAR_OS_COMMON;
+   var.data = NULL;
+   var.datalen = 0;
+
+   switch (type) {
+   case ARCH_VAR_OPAL_KEY:
+   var.component = PLPKS_SED_COMPONENT;
+#ifdef OPAL_AUTH_KEY
+   if (strcmp(OPAL_AUTH_KEY, varname) == 0) {
+   var.name = PKS_SED_MANGLED_LABEL;
+   var.namelen = strlen(varname);
+   }
+#endif
+   offset = offsetof(struct plpks_sed_object_data, key);
+   break;
+   case ARCH_VAR_OTHER:
+   var.component = "";
+   break;
+   }
+
+   ret = plpks_read_os_var();
+   if (ret != 0)
+   return ret;
+
+   if (offset > var.datalen)
+   offset = 0;
+
+   switch (type) {
+   case ARCH_VAR_OPAL_KEY:
+   data = (struct plpks_sed_object_data *)var.data;
+   *varlen = data->key_len;
+   break;
+   case ARCH_VAR_OTHER:
+   *varlen = var.datalen;
+   break;
+   }
+
+   if (var.data) {
+   memcpy(varbuf, var.data + offset, var.datalen - offset);
+   buf[*varlen] = '\0';
+   kfree(var.data);
+   }
+
+   return 0;
+}
+
+/*
+ * Write the variable data to PKS given the label
+ */
+int arch_write_variable(enum arch_variable_type type, char *varname,
+   void *varbuf, u_int varlen)
+{
+   struct plpks_var var;
+   struct plpks_sed_object_data data;
+   struct plpks_var_name vname;
+
+   var.name = varname;
+   var.namelen = strlen(varname);
+   var.policy = PLPKS_ARCHVAR_POLICY;
+   var.os = PLPKS_ARCHVAR_OS_COMMON;
+   var.datalen = varlen;
+   var.data = varbuf;
+
+   switch (type) {
+   case ARCH_VAR_OPAL_KEY:
+   var.component = PLPKS_SED_COMPONENT;
+#ifdef 

[PATCH v3 1/2] lib: generic accessor functions for arch keystore

2022-08-01 Thread gjoyce
From: Greg Joyce 

Generic kernel subsystems may rely on platform specific persistent
KeyStore to store objects containing sensitive key material. In such case,
they need to access architecture specific functions to perform read/write
operations on these variables.

Define the generic variable read/write prototypes to be implemented by
architecture specific versions. The default(weak) implementations of
these prototypes return -EOPNOTSUPP unless overridden by architecture
versions.

Signed-off-by: Greg Joyce 
---
 include/linux/arch_vars.h | 23 +++
 lib/Makefile  |  2 +-
 lib/arch_vars.c   | 25 +
 3 files changed, 49 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/arch_vars.h
 create mode 100644 lib/arch_vars.c

diff --git a/include/linux/arch_vars.h b/include/linux/arch_vars.h
new file mode 100644
index ..9c280ff9432e
--- /dev/null
+++ b/include/linux/arch_vars.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Platform variable opearations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for architecture specific
+ * variables. Specific architectures can provide overrides.
+ *
+ */
+
+#include 
+
+enum arch_variable_type {
+   ARCH_VAR_OPAL_KEY  = 0, /* SED Opal Authentication Key */
+   ARCH_VAR_OTHER = 1, /* Other type of variable */
+   ARCH_VAR_MAX   = 1, /* Maximum type value */
+};
+
+int arch_read_variable(enum arch_variable_type type, char *varname,
+  void *varbuf, u_int *varlen);
+int arch_write_variable(enum arch_variable_type type, char *varname,
+   void *varbuf, u_int varlen);
diff --git a/lib/Makefile b/lib/Makefile
index f99bf61f8bbc..b90c4cb0dbbb 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -48,7 +48,7 @@ obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
 bsearch.o find_bit.o llist.o memweight.o kfifo.o \
 percpu-refcount.o rhashtable.o \
 once.o refcount.o usercopy.o errseq.o bucket_locks.o \
-generic-radix-tree.o
+generic-radix-tree.o arch_vars.o
 obj-$(CONFIG_STRING_SELFTEST) += test_string.o
 obj-y += string_helpers.o
 obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
diff --git a/lib/arch_vars.c b/lib/arch_vars.c
new file mode 100644
index ..e6f16d7d09c1
--- /dev/null
+++ b/lib/arch_vars.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Platform variable operations.
+ *
+ * Copyright (C) 2022 IBM Corporation
+ *
+ * These are the accessor functions (read/write) for architecture specific
+ * variables. Specific architectures can provide overrides.
+ *
+ */
+
+#include 
+#include 
+
+int __weak arch_read_variable(enum arch_variable_type type, char *varname,
+ void *varbuf, u_int *varlen)
+{
+   return -EOPNOTSUPP;
+}
+
+int __weak arch_write_variable(enum arch_variable_type type, char *varname,
+  void *varbuf, u_int varlen)
+{
+   return -EOPNOTSUPP;
+}
-- 
2.27.0



[PATCH v3 0/2] generic and PowerPC accessor functions for arch keystore

2022-08-01 Thread gjoyce
From: Greg Joyce 

Architectural neutral functions have been defined for accessing
architecture specific variable store. The neutral functions are
defined as weak so that they may be superseded by platform
specific versions.

PowerPC/pseries versions of these functions provide read/write access
to the non-volatile PLPKS data store.

This functionality allows kernel code such as the block SED opal
driver to store authentication keys in a secure permanent store.

Greg Joyce (2):
  lib: define generic accessor functions for arch specific keystore
  powerpc/pseries: Override lib/arch_vars.c functions

 arch/powerpc/platforms/pseries/Makefile   |   1 +
 .../platforms/pseries/plpks_arch_ops.c| 167 ++
 include/linux/arch_vars.h |  23 +++
 lib/Makefile  |   2 +-
 lib/arch_vars.c   |  25 +++
 5 files changed, 217 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks_arch_ops.c
 create mode 100644 include/linux/arch_vars.h
 create mode 100644 lib/arch_vars.c


Signed-off-by: Greg Joyce 
base-commit: ff6992735ade75aae3e35d16b17da1008d753d28
-- 
2.27.0