* [PATCH v3 0/6] Extend PKWM to support user-created wrapping keys
@ 2026-10-17 7:48 Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 1/6] pseries/plpks: fix length types for wrapping operations Srish Srinivasan
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Srish Srinivasan @ 2026-10-17 7:48 UTC (permalink / raw)
To: linux-integrity, keyrings, linuxppc-dev
Cc: maddy, ritesh.list, sshegde, mpe, npiggin, christophe.leroy,
James.Bottomley, jarkko, zohar, linux-kernel,
linux-security-module, nayna, rnsastry, ssrish
The PKWM trusted source currently uses a single default wrapping key per
LPAR. This key is created during trusted source initialization, and all
trusted keys backed by PKWM are sealed and unsealed using it.
Recent versions of PKWM allow users to create and manage their own wrapping
keys through a set of lifecycle operations. This patch series brings these
PKWM capabilities into the kernel, allowing users to create, manage, and
select wrapping keys for sealing and unsealing their trusted keys, rather
than requiring all trusted keys to use the default wrapping key.
This series extends PKWM to support user-created wrapping keys. It adds
the required hcalls, allows users to select a wrapping key by label when
creating PKWM-backed trusted keys, and introduces a sysfs interface for
managing wrapping keys from userspace.
This patchset also includes three fixes: one aligning the PLPKS wrapping
length types with the underlying hcall interfaces, another preserving the
original error returned when default wrapping key generation fails, and a
third clearing sensitive PKWM seal and unseal buffers before freeing them.
This series depends on the following PLPKS refactoring and hardening series
and must be applied on top of it:
https://lore.kernel.org/all/20260923182816.151451-1-ssrish@linux.ibm.com/
Changelog:
v2 -> v3:
- Moved most of the refactoring and hardening patches into a separate
series:
https://lore.kernel.org/all/20260923182816.151451-1-ssrish@linux.ibm.com/
- Added a fix to clear sensitive PKWM seal and unseal buffers before
freeing them
- Retained Nageswara's Tested-by tag
- Refined error handling and documented default wrapping key restrictions
v1 -> v2:
- Addressed parameter validation issues reported by Nageswara
- Tweaked PLPKS_WRAPKEY_SYSFS Kconfig help text
- Added two preparatory bug-fix patches
- Cc'd stable@vger.kernel.org where applicable
Srish Srinivasan (6):
pseries/plpks: fix length types for wrapping operations
keys/trusted_keys: propagate wrapping key generation errors
keys/trusted_keys: clear sensitive PKWM buffers
pseries/plpks: add HCALLs for PKWM wrapping key life cycle management
keys/trusted_keys: enable PKWM wrapping key selection by label
pseries/plpks/wrapkey: expose PKWM wrapping key management to
userspace via sysfs
.../ABI/testing/sysfs-firmware-plpks | 116 ++++
Documentation/arch/powerpc/papr_hcalls.rst | 33 ++
.../security/keys/trusted-encrypted.rst | 4 +-
arch/powerpc/include/asm/hvcall.h | 5 +-
arch/powerpc/include/asm/plpks.h | 40 +-
arch/powerpc/platforms/pseries/Kconfig | 15 +
arch/powerpc/platforms/pseries/Makefile | 1 +
arch/powerpc/platforms/pseries/plpks-sysfs.c | 11 +
.../platforms/pseries/plpks-wrapkey-sysfs.c | 399 ++++++++++++++
arch/powerpc/platforms/pseries/plpks.c | 502 ++++++++++++++++--
include/keys/trusted_pkwm.h | 3 +
security/keys/trusted-keys/trusted_pkwm.c | 48 +-
12 files changed, 1126 insertions(+), 51 deletions(-)
create mode 100644 arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c
--
2.52.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 1/6] pseries/plpks: fix length types for wrapping operations
2026-10-17 7:48 [PATCH v3 0/6] Extend PKWM to support user-created wrapping keys Srish Srinivasan
@ 2026-10-17 7:48 ` Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 2/6] keys/trusted_keys: propagate wrapping key generation errors Srish Srinivasan
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Srish Srinivasan @ 2026-10-17 7:48 UTC (permalink / raw)
To: linux-integrity, keyrings, linuxppc-dev
Cc: maddy, ritesh.list, sshegde, mpe, npiggin, christophe.leroy,
James.Bottomley, jarkko, zohar, linux-kernel,
linux-security-module, nayna, rnsastry, ssrish, stable
The object wrapping and unwrapping hcalls use 64-bit length values, but
plpks_wrap_object() and plpks_unwrap_object() currently use u32 for the
input and output length parameters. As a result, the interfaces cannot
represent the full range of values supported by the hcalls.
Use u64 for the length parameters to align them with the underlying hcall
interfaces. Update the PKWM consumer accordingly.
Fixes: 133aa79e211d ("pseries/plpks: add HCALLs for PowerVM Key Wrapping Module")
Fixes: c99fcb0d735b ("keys/trusted_keys: establish PKWM as a trusted source")
Cc: stable@vger.kernel.org # 7.0
Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Tested-by: R Nageswara Sastry <rnsastry@linux.ibm.com>
---
arch/powerpc/include/asm/plpks.h | 8 ++++----
arch/powerpc/platforms/pseries/plpks.c | 8 ++++----
security/keys/trusted-keys/trusted_pkwm.c | 4 ++--
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index e87f90e40d4e..8b2ffb27db5a 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -118,11 +118,11 @@ bool plpks_wrapping_is_supported(void);
int plpks_gen_wrapping_key(void);
-int plpks_wrap_object(u8 **input_buf, u32 input_len, u16 wrap_flags,
- u8 **output_buf, u32 *output_len);
+int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
+ u8 **output_buf, u64 *output_len);
-int plpks_unwrap_object(u8 **input_buf, u32 input_len,
- u8 **output_buf, u32 *output_len);
+int plpks_unwrap_object(u8 **input_buf, u64 input_len,
+ u8 **output_buf, u64 *output_len);
#else // CONFIG_PSERIES_PLPKS
static inline bool plpks_is_available(void) { return false; }
static inline u16 plpks_get_passwordlen(void) { BUILD_BUG(); }
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 240cd5632446..a7953db3f23a 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -1021,8 +1021,8 @@ EXPORT_SYMBOL_GPL(plpks_gen_wrapping_key);
*
* Returns: On success 0 is returned, a negative errno if not.
*/
-int plpks_wrap_object(u8 **input_buf, u32 input_len, u16 wrap_flags,
- u8 **output_buf, u32 *output_len)
+int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
+ u8 **output_buf, u64 *output_len)
{
unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = { 0 };
struct plpks_auth *auth;
@@ -1140,8 +1140,8 @@ EXPORT_SYMBOL_GPL(plpks_wrap_object);
*
* Returns: On success 0 is returned, a negative errno if not.
*/
-int plpks_unwrap_object(u8 **input_buf, u32 input_len, u8 **output_buf,
- u32 *output_len)
+int plpks_unwrap_object(u8 **input_buf, u64 input_len, u8 **output_buf,
+ u64 *output_len)
{
unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = { 0 };
struct plpks_auth *auth;
diff --git a/security/keys/trusted-keys/trusted_pkwm.c b/security/keys/trusted-keys/trusted_pkwm.c
index bf42c6679245..b6b5697426a8 100644
--- a/security/keys/trusted-keys/trusted_pkwm.c
+++ b/security/keys/trusted-keys/trusted_pkwm.c
@@ -83,7 +83,7 @@ static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
struct trusted_key_options *options = NULL;
struct trusted_pkwm_options *pkwm = NULL;
u8 *input_buf, *output_buf;
- u32 output_len, input_len;
+ u64 output_len, input_len;
int rc;
options = trusted_options_alloc();
@@ -130,7 +130,7 @@ static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *datablob)
{
u8 *input_buf, *output_buf;
- u32 input_len, output_len;
+ u64 input_len, output_len;
int rc;
input_len = p->blob_len;
--
2.52.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 2/6] keys/trusted_keys: propagate wrapping key generation errors
2026-10-17 7:48 [PATCH v3 0/6] Extend PKWM to support user-created wrapping keys Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 1/6] pseries/plpks: fix length types for wrapping operations Srish Srinivasan
@ 2026-10-17 7:48 ` Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 3/6] keys/trusted_keys: clear sensitive PKWM buffers Srish Srinivasan
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Srish Srinivasan @ 2026-10-17 7:48 UTC (permalink / raw)
To: linux-integrity, keyrings, linuxppc-dev
Cc: maddy, ritesh.list, sshegde, mpe, npiggin, christophe.leroy,
James.Bottomley, jarkko, zohar, linux-kernel,
linux-security-module, nayna, rnsastry, ssrish, stable
plpks_gen_wrapping_key() returns a negative errno when default wrapping key
generation fails. However, trusted_pkwm_init() returns -EINVAL for all such
failures, discarding the original error.
Propagate the error returned by plpks_gen_wrapping_key() unchanged.
Fixes: c99fcb0d735b ("keys/trusted_keys: establish PKWM as a trusted source")
Cc: stable@vger.kernel.org # 7.0
Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Tested-by: R Nageswara Sastry <rnsastry@linux.ibm.com>
---
security/keys/trusted-keys/trusted_pkwm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/keys/trusted-keys/trusted_pkwm.c b/security/keys/trusted-keys/trusted_pkwm.c
index b6b5697426a8..633a7674d065 100644
--- a/security/keys/trusted-keys/trusted_pkwm.c
+++ b/security/keys/trusted-keys/trusted_pkwm.c
@@ -170,7 +170,7 @@ static int trusted_pkwm_init(void)
ret = plpks_gen_wrapping_key();
if (ret) {
pr_err("Failed to generate default wrapping key\n");
- return -EINVAL;
+ return ret;
}
return register_key_type(&key_type_trusted);
--
2.52.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 3/6] keys/trusted_keys: clear sensitive PKWM buffers
2026-10-17 7:48 [PATCH v3 0/6] Extend PKWM to support user-created wrapping keys Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 1/6] pseries/plpks: fix length types for wrapping operations Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 2/6] keys/trusted_keys: propagate wrapping key generation errors Srish Srinivasan
@ 2026-10-17 7:48 ` Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 4/6] pseries/plpks: add HCALLs for PKWM wrapping key life cycle management Srish Srinivasan
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Srish Srinivasan @ 2026-10-17 7:48 UTC (permalink / raw)
To: linux-integrity, keyrings, linuxppc-dev
Cc: maddy, ritesh.list, sshegde, mpe, npiggin, christophe.leroy,
James.Bottomley, jarkko, zohar, linux-kernel,
linux-security-module, nayna, rnsastry, ssrish, stable
The input buffer to PKWM seal and the output buffer from PKWM unseal
contain plaintext trusted-key payload data. Freeing these buffers with
kfree(), without wiping the contents, can leave sensitive key material
in memory.
Use kfree_sensitive() to wipe the sensitive key material when freeing
these buffers.
Fixes: c99fcb0d735b ("keys/trusted_keys: establish PKWM as a trusted source")
Cc: stable@vger.kernel.org # 7.0
Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Reviewed-by: Nayna Jain <nayna@linux.ibm.com>
Tested-by: R Nageswara Sastry <rnsastry@linux.ibm.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
---
security/keys/trusted-keys/trusted_pkwm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/security/keys/trusted-keys/trusted_pkwm.c b/security/keys/trusted-keys/trusted_pkwm.c
index 633a7674d065..6774557f818a 100644
--- a/security/keys/trusted-keys/trusted_pkwm.c
+++ b/security/keys/trusted-keys/trusted_pkwm.c
@@ -118,7 +118,7 @@ static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
pr_err("Wrapping of payload key failed: %d\n", rc);
}
- kfree(input_buf);
+ kfree_sensitive(input_buf);
kfree(output_buf);
out:
@@ -153,7 +153,7 @@ static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *datablob)
}
kfree(input_buf);
- kfree(output_buf);
+ kfree_sensitive(output_buf);
return rc;
}
--
2.52.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 4/6] pseries/plpks: add HCALLs for PKWM wrapping key life cycle management
2026-10-17 7:48 [PATCH v3 0/6] Extend PKWM to support user-created wrapping keys Srish Srinivasan
` (2 preceding siblings ...)
2026-10-17 7:48 ` [PATCH v3 3/6] keys/trusted_keys: clear sensitive PKWM buffers Srish Srinivasan
@ 2026-10-17 7:48 ` Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 5/6] keys/trusted_keys: enable PKWM wrapping key selection by label Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 6/6] pseries/plpks/wrapkey: expose PKWM wrapping key management to userspace via sysfs Srish Srinivasan
5 siblings, 0 replies; 7+ messages in thread
From: Srish Srinivasan @ 2026-10-17 7:48 UTC (permalink / raw)
To: linux-integrity, keyrings, linuxppc-dev
Cc: maddy, ritesh.list, sshegde, mpe, npiggin, christophe.leroy,
James.Bottomley, jarkko, zohar, linux-kernel,
linux-security-module, nayna, rnsastry, ssrish
The PKWM trusted source uses a single wrapping key per LPAR, created only
once during trust source initialization. All the wrap and unwrap requests
are bound to this default wrapping key.
Implement H_PKS_REVOKE_OBJECT, H_PKS_UNREVOKE_OBJECT, and
H_PKS_GET_OBJECTLABELS HCALLs to enable support for revoking and unrevoking
PKWM wrapping keys, and for retrieving wrapping key labels. The label
retrieval operation (H_PKS_GET_OBJECTLABELS) applies to all wrapping keys
including the default one, while the life cycle operations
(H_PKS_REVOKE_OBJECT/H_PKS_UNREVOKE_OBJECT) apply only to user-created
wrapping keys.
Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Tested-by: R Nageswara Sastry <rnsastry@linux.ibm.com>
---
Documentation/arch/powerpc/papr_hcalls.rst | 33 ++
arch/powerpc/include/asm/hvcall.h | 5 +-
arch/powerpc/include/asm/plpks.h | 15 +
arch/powerpc/platforms/pseries/plpks.c | 448 ++++++++++++++++++++-
4 files changed, 497 insertions(+), 4 deletions(-)
diff --git a/Documentation/arch/powerpc/papr_hcalls.rst b/Documentation/arch/powerpc/papr_hcalls.rst
index 44c9c8b32ae3..3455b403a048 100644
--- a/Documentation/arch/powerpc/papr_hcalls.rst
+++ b/Documentation/arch/powerpc/papr_hcalls.rst
@@ -343,6 +343,39 @@ is returned to the caller.
H_PKS_UNWRAP_OBJECT is used to unwrap an object that was previously wrapped with
H_PKS_WRAP_OBJECT.
+**H_PKS_REVOKE_OBJECT**
+
+| Input: authorization, objectlabel, objectlabellen, flags
+| Out: *object policy*
+| Return Value: *H_Success, H_Function, H_State, H_Parameter, H_P2, H_P3, H_P4,
+ H_Authority, H_Not_Found, H_Busy, H_Aborted*
+
+H_PKS_REVOKE_OBJECT is used to revoke an object in Platform Keystore.
+
+
+**H_PKS_UNREVOKE_OBJECT**
+
+| Input: authorization, objectlabel, objectlabellen, flags
+| Out: *object policy*
+| Return Value: *H_Success, H_Function, H_State, H_Parameter, H_P2, H_P3, H_P4,
+ H_Authority, H_Not_Found, H_Busy, H_Aborted*
+
+H_PKS_UNREVOKE_OBJECT is used to unrevoke an object that was previously revoked
+with H_PKS_REVOKE_OBJECT in Platform Keystore.
+
+
+**H_PKS_GET_OBJECTLABELS**
+
+| Input: authorization, continueToken, out, outlen
+| Out: *continue-token, number of object labels in the returned list, object
+ label list*
+| Return Value: *H_Success, H_Function, H_State, H_Parameter, H_P2, H_P3, H_P4,
+ H_Authority, H_Busy, H_Aborted, H_Continue*
+
+H_PKS_GET_OBJECTLABELS is used to retrieve a list of object labels owned by the
+specified consumer.
+
+
References
==========
.. [1] "Power Architecture Platform Reference"
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index dff90a7d7f70..4d4c2ce1dd87 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -340,6 +340,7 @@
#define H_PKS_GET_CONFIG 0x41C
#define H_PKS_SET_PASSWORD 0x420
#define H_PKS_GEN_PASSWORD 0x424
+#define H_PKS_GET_OBJECTLABELS 0x428
#define H_PKS_WRITE_OBJECT 0x42C
#define H_PKS_GEN_KEY 0x430
#define H_PKS_READ_OBJECT 0x434
@@ -362,7 +363,9 @@
#define H_GUEST_DELETE 0x488
#define H_PKS_WRAP_OBJECT 0x490
#define H_PKS_UNWRAP_OBJECT 0x494
-#define MAX_HCALL_OPCODE H_PKS_UNWRAP_OBJECT
+#define H_PKS_REVOKE_OBJECT 0x4AC
+#define H_PKS_UNREVOKE_OBJECT 0x4B0
+#define MAX_HCALL_OPCODE H_PKS_UNREVOKE_OBJECT
/* Scope args for H_SCM_UNBIND_ALL */
#define H_UNBIND_SCOPE_ALL (0x1)
diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index 8b2ffb27db5a..c39d1f07017e 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -25,6 +25,7 @@
#define PLPKS_SIGNEDUPDATE PPC_BIT32(7) // Object can only be modified by signed updates
#define PLPKS_WRAPPINGKEY PPC_BIT32(8) // Object contains a wrapping key
#define PLPKS_HVPROVISIONED PPC_BIT32(28) // Hypervisor has provisioned this object
+#define PLPKS_REVOKED PPC_BIT32(30) // Object is revoked
// Signature algorithm flags from signed_update_algorithms
#define PLPKS_ALG_RSA2048 PPC_BIT(0)
@@ -123,6 +124,20 @@ int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
int plpks_unwrap_object(u8 **input_buf, u64 input_len,
u8 **output_buf, u64 *output_len);
+
+int plpks_revoke_wrapping_key(struct plpks_var *var);
+
+int plpks_unrevoke_wrapping_key(struct plpks_var *var);
+
+int plpks_del_wrapping_key(struct plpks_var *var);
+
+int plpks_is_wrapping_key_revoked(struct plpks_var *var);
+
+int plpks_get_object_labels(u8 **output_buf, u64 *output_len,
+ char *comp_prefix);
+
+bool plpks_revoke_is_supported(void);
+
#else // CONFIG_PSERIES_PLPKS
static inline bool plpks_is_available(void) { return false; }
static inline u16 plpks_get_passwordlen(void) { BUILD_BUG(); }
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index a7953db3f23a..edd189cfcc85 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -23,8 +23,17 @@
*/
#define PLPKS_WRAPPING_BUF_DIFF 1024
+/*
+ * Maximum length for the buffer to store the retrieved object labels
+ */
+#define PLPKS_OBJLABEL_BUF_MAX 2550
+
+#define PLPKS_OBJLABEL_LEN_FIELD_SIZE 2
+#define PLPKS_OBJLABEL_PREFIX_LEN 8
+
#define PLPKS_WRAP_INTERFACE_BIT 3
#define PLPKS_WRAPPING_KEY_LENGTH 32
+#define PLPKS_REVOKE_INTERFACE_BIT 4
#define WRAPFLAG_BE_BIT_SET(be_bit) \
BIT_ULL(63 - (be_bit))
@@ -46,6 +55,7 @@
#include <linux/libfdt.h>
#include <linux/memblock.h>
#include <linux/bitfield.h>
+#include <linux/unaligned.h>
#include <asm/hvcall.h>
#include <asm/machdep.h>
#include <asm/plpks.h>
@@ -67,6 +77,7 @@ static u32 maxlargeobjectsize;
static u64 signedupdatealgorithms;
static u64 wrappingfeatures;
static bool wrapsupport;
+static bool revokesupport;
struct plpks_auth {
u8 version;
@@ -146,6 +157,9 @@ static int pseries_status_to_err(int rc)
case H_ABORTED:
err = -EIO;
break;
+ case H_CONTINUE:
+ err = -EAGAIN;
+ break;
default:
err = -EINVAL;
}
@@ -312,6 +326,7 @@ static int _plpks_get_config(void)
signedupdatealgorithms = be64_to_cpu(config->signedupdatealgorithms);
wrappingfeatures = be64_to_cpu(config->wrappingfeatures);
wrapsupport = config->flags & PPC_BIT8(PLPKS_WRAP_INTERFACE_BIT);
+ revokesupport = config->flags & PPC_BIT8(PLPKS_REVOKE_INTERFACE_BIT);
// Validate that the numbers we get back match the requirements of the spec
if (maxpwsize < 32) {
@@ -831,9 +846,6 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
if (var->namelen > PLPKS_MAX_NAME_SIZE)
return -EINVAL;
- if (var->policy & PLPKS_WRAPPINGKEY)
- return -EPERM;
-
auth = construct_auth(consumer);
if (IS_ERR(auth))
return PTR_ERR(auth);
@@ -903,6 +915,23 @@ bool plpks_wrapping_is_supported(void)
}
EXPORT_SYMBOL_GPL(plpks_wrapping_is_supported);
+/**
+ * plpks_revoke_is_supported() - Get the H_PKS_REVOKE_OBJECT and
+ * H_PKS_UNREVOKE_OBJECT interfaces availability status for the LPAR.
+ *
+ * Successful execution of the H_PKS_GET_CONFIG HCALL during initialization
+ * sets bit 4 of the flags variable in the PLPKS config structure if the
+ * H_PKS_REVOKE_OBJECT and H_PKS_UNREVOKE_OBJECT interfaces are supported.
+ *
+ * Returns: true if the H_PKS_REVOKE_OBJECT and H_PKS_UNREVOKE_OBJECT interfaces
+ * are supported, false if not.
+ */
+bool plpks_revoke_is_supported(void)
+{
+ return revokesupport;
+}
+EXPORT_SYMBOL_GPL(plpks_revoke_is_supported);
+
/**
* plpks_gen_wrapping_key() - Generate a new random key with the 'wrapping key'
* policy set.
@@ -1189,6 +1218,419 @@ int plpks_unwrap_object(u8 **input_buf, u64 input_len, u8 **output_buf,
}
EXPORT_SYMBOL_GPL(plpks_unwrap_object);
+/**
+ * plpks_revoke_wrapping_key() - Revoke a wrapping key stored in the PLPKS.
+ * @var: variable representing the wrapping key to be revoked
+ *
+ * The H_PKS_REVOKE_OBJECT HCALL revokes an object stored in the PLPKS.
+ *
+ * Possible reasons for the returned errno values:
+ *
+ * -ENXIO if PLPKS is not supported
+ * -EIO if PLPKS access is blocked due to the LPAR's state
+ * if PLPKS modification is blocked due to the LPAR's state
+ * if an error occurred while processing the request
+ * -EINVAL if invalid authorization parameter
+ * if invalid wrapping key label parameter
+ * if invalid wrapping key label length parameter
+ * if invalid or unsupported wrapping key revoking flags
+ * -EPERM if access is denied
+ * if the specified wrapping key is the default wrapping key
+ * -ENOENT if the requested wrapping key was not found
+ * -EBUSY if unable to handle the request or long running operation
+ * initiated, retry later.
+ *
+ * Returns: On success 0 is returned, a negative errno if not.
+ */
+int plpks_revoke_wrapping_key(struct plpks_var *var)
+{
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
+ struct plpks_auth *auth;
+ struct label *label;
+ u64 objrevokeflags = 0;
+ int rc, pseries_status;
+
+ if (!var || !var->name || !*var->name)
+ return -EINVAL;
+
+ if (!strcmp((char *)var->name, PLPKS_DEFAULT_WRAPKEY_LABEL))
+ return -EPERM;
+
+ auth = construct_auth(PLPKS_OS_OWNER);
+ if (IS_ERR(auth))
+ return PTR_ERR(auth);
+
+ label = construct_label(var->component, var->os, var->name,
+ var->namelen);
+ if (IS_ERR(label)) {
+ rc = PTR_ERR(label);
+ goto out;
+ }
+
+ rc = plpar_hcall(H_PKS_REVOKE_OBJECT, retbuf, virt_to_phys(auth),
+ virt_to_phys(label), label->size, objrevokeflags);
+
+ pseries_status = rc;
+ rc = pseries_status_to_err(rc);
+
+ if (rc) {
+ pr_err("H_PKS_REVOKE_OBJECT failed. pseries_status=%d, rc=%d\n",
+ pseries_status, rc);
+ }
+
+ if (!rc || (rc == -EPERM && retbuf[0]))
+ var->policy = (u32)retbuf[0];
+
+ kfree(label);
+out:
+ kfree_sensitive(auth);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(plpks_revoke_wrapping_key);
+
+/**
+ * plpks_unrevoke_wrapping_key() - Unrevoke a revoked wrapping key in the PLPKS.
+ * @var: variable representing the revoked wrapping key to be unrevoked
+ *
+ * The H_PKS_UNREVOKE_OBJECT HCALL unrevokes a revoked object stored in the
+ * PLPKS.
+ *
+ * Possible reasons for the returned errno values:
+ *
+ * -ENXIO if PLPKS is not supported
+ * -EIO if PLPKS access is blocked due to the LPAR's state
+ * if PLPKS modification is blocked due to the LPAR's state
+ * if an error occurred while processing the request
+ * -EINVAL if invalid authorization parameter
+ * if invalid object label parameter
+ * if invalid object label length parameter
+ * if invalid or unsupported object revoking flags
+ * if the specified wrapping key is the default wrapping key
+ * -EPERM if access is denied
+ * -ENOENT if the requested object was not found
+ * -EBUSY if unable to handle the request or long running operation
+ * initiated, retry later.
+ *
+ * Returns: On success 0 is returned, a negative errno if not.
+ */
+int plpks_unrevoke_wrapping_key(struct plpks_var *var)
+{
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
+ struct plpks_auth *auth;
+ struct label *label;
+ u64 objrevokeflags = 0;
+ int rc, pseries_status;
+
+ if (!var || !var->name || !*var->name)
+ return -EINVAL;
+
+ if (!strcmp((char *)var->name, PLPKS_DEFAULT_WRAPKEY_LABEL))
+ return -EINVAL;
+
+ auth = construct_auth(PLPKS_OS_OWNER);
+ if (IS_ERR(auth))
+ return PTR_ERR(auth);
+
+ label = construct_label(var->component, var->os, var->name,
+ var->namelen);
+ if (IS_ERR(label)) {
+ rc = PTR_ERR(label);
+ goto out;
+ }
+
+ rc = plpar_hcall(H_PKS_UNREVOKE_OBJECT, retbuf,
+ virt_to_phys(auth), virt_to_phys(label),
+ label->size, objrevokeflags);
+
+ pseries_status = rc;
+ rc = pseries_status_to_err(rc);
+
+ if (rc)
+ pr_err("H_PKS_UNREVOKE_OBJECT failed. pseries_status=%d, rc=%d\n",
+ pseries_status, rc);
+
+ if (!rc || (rc == -EPERM && retbuf[0]))
+ var->policy = (u32)retbuf[0];
+
+ kfree(label);
+out:
+ kfree_sensitive(auth);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(plpks_unrevoke_wrapping_key);
+
+/**
+ * plpks_is_wrapping_key_revoked() - Check if a given wrapping key has been
+ * revoked.
+ * @var: variable representing the wrapping key to be checked
+ *
+ * When the H_PKS_READ_OBJECT HCALL tries reads an object that exists but when
+ * the policy is not met, it returns H_AUTHORITY along with the 4-byte object
+ * policy. This policy is inspected to determine if the object has been revoked.
+ *
+ * Possible reasons for the returned errno values:
+ *
+ * -ENXIO if PLPKS is not supported
+ * -EIO if PLPKS access is blocked due to the LPAR's state
+ * if reading a wrapping key unexpectedly succeeds
+ * if an error occurred while processing the request
+ * -EINVAL if invalid authorization parameter
+ * if invalid object label parameter
+ * if invalid object label len parameter
+ * if invalid output data parameter
+ * if invalid output data len parameter
+ * -EPERM if access is denied
+ * -ENOENT if the requested object was not found
+ * -EFBIG if the requested object couldn't be
+ * stored in the buffer provided
+ * -EBUSY if unable to handle the request
+ *
+ * Returns: 1 is returned if the wrapping key has been revoked. 0 is returned if
+ * the wrapping key has not been revoked. Otherwise, a negative errno
+ * is returned.
+ */
+int plpks_is_wrapping_key_revoked(struct plpks_var *var)
+{
+ int rc;
+
+ if (!var || !var->name || !*var->name)
+ return -EINVAL;
+
+ rc = plpks_read_var(PLPKS_OS_OWNER, var);
+ if (!rc) {
+ /*
+ * Reading a wrapping key is expected to fail with
+ * -EPERM and return its policy.
+ */
+ rc = -EIO;
+ } else if (rc == -EPERM) {
+ if (var->policy & PLPKS_WRAPPINGKEY) {
+ if (var->policy & PLPKS_REVOKED)
+ rc = 1;
+ else
+ rc = 0;
+ }
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(plpks_is_wrapping_key_revoked);
+
+/**
+ * plpks_del_wrapping_key() - Delete a wrapping key from the PLPKS.
+ * @var: variable representing the revoked wrapping key to be deleted
+ *
+ * The plpks_remove_var function removes the specified variable and its data
+ * from the PLPKS by invoking the H_PKS_REMOVE_OBJECT HCALL.
+ *
+ * Possible reasons for the returned errno values:
+ *
+ * -ENXIO if PLPKS is not supported
+ * -EIO if PLPKS access is blocked due to the LPAR's state
+ * if PLPKS modification is blocked due to the LPAR's state
+ * if an error occurred while processing the request
+ * -EINVAL if invalid authorization parameter
+ * if invalid object label parameter
+ * if invalid object label len parameter
+ * -EPERM if access is denied
+ * if the specified wrapping key is the default wrapping key
+ * if the specified wrapping key has not been revoked
+ * -ENOENT if the requested object was not found
+ * -EBUSY if unable to handle the request
+ *
+ * Returns: On success 0 is returned, a negative errno if not.
+ */
+int plpks_del_wrapping_key(struct plpks_var *var)
+{
+ int rc;
+ struct plpks_var_name vname;
+
+ if (!var || !var->name || !*var->name)
+ return -EINVAL;
+
+ if (!strcmp((char *)var->name, PLPKS_DEFAULT_WRAPKEY_LABEL))
+ return -EPERM;
+
+ rc = plpks_is_wrapping_key_revoked(var);
+ if (rc == 1) {
+ vname = (struct plpks_var_name) {
+ .name = var->name,
+ .namelen = var->namelen
+ };
+
+ rc = plpks_remove_var(PLPKS_WRAPKEY_COMPONENT, var->os,
+ vname);
+ if (rc)
+ pr_err("deletion of <%s> failed. rc=%d\n",
+ (char *)var->name, rc);
+ } else if (!rc) {
+ pr_err("revoke <%s> before deletion\n", (char *)var->name);
+ rc = -EPERM;
+ } else {
+ pr_err("revocation status check failed for <%s>. rc = %d\n",
+ (char *)var->name, rc);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(plpks_del_wrapping_key);
+
+/**
+ * plpks_get_object_labels() - retrieve a list of object labels for the objects
+ * stored in the PLPKS
+ * @output_buf: buffer to store the retrieved object labels
+ * @output_len: number of object labels retrieved
+ * @comp_prefix: component prefix string
+ *
+ * The H_PKS_GET_OBJECTLABELS HCALL retrieves a list of object labels for the
+ * objects with the given component prefix stored in the PLPKS.
+ *
+ * Possible reasons for the returned errno values:
+ *
+ * -ENXIO if PLPKS is not supported
+ * -EIO if PLPKS access is blocked due to the LPAR's state
+ * if PLPKS modification is blocked due to the LPAR's state
+ * if an error occurred while processing the request
+ * -EINVAL if invalid authorization parameter
+ * if invalid output buffer parameter
+ * if invalid output buffer length parameter
+ * if invalid continue token parameter
+ * if the provided component prefix is NULL
+ * -EPERM if access is denied
+ * -EBUSY if unable to handle the request or long running operation
+ * initiated, retry later.
+ *
+ * Returns: On success 0 is returned, a negative errno if not.
+ */
+int plpks_get_object_labels(u8 **output_buf, u64 *output_len,
+ char *comp_prefix)
+{
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
+ u8 *labels_buf = NULL;
+ u8 *tmp_buf = NULL;
+ struct plpks_auth *auth;
+ struct label_attr *metadata = NULL;
+ u16 label_len;
+ u64 labels_count;
+ u64 continuetoken = 0, output_buf_len = 0;
+ int rc, pseries_status;
+ size_t labels_buf_offset = 0, output_buf_offset = 0;
+ size_t obj_label_entry_size, i;
+
+ *output_buf = NULL;
+ *output_len = 0;
+
+ if (!comp_prefix)
+ return -EINVAL;
+
+ auth = construct_auth(PLPKS_OS_OWNER);
+ if (IS_ERR(auth))
+ return PTR_ERR(auth);
+
+ do {
+ labels_buf =
+ kzalloc(roundup_pow_of_two(PLPKS_OBJLABEL_BUF_MAX),
+ GFP_KERNEL);
+
+ if (!labels_buf) {
+ rc = -ENOMEM;
+ goto out_free_output_buf;
+ }
+
+ rc = plpar_hcall(H_PKS_GET_OBJECTLABELS, retbuf,
+ virt_to_phys(auth), continuetoken,
+ virt_to_phys(labels_buf),
+ roundup_pow_of_two(PLPKS_OBJLABEL_BUF_MAX));
+
+ pseries_status = rc;
+ rc = pseries_status_to_err(rc);
+
+ if (rc && rc != -EAGAIN) {
+ pr_err("H_PKS_GET_OBJECTLABELS failed. pseries_status=%d rc=%d\n",
+ pseries_status, rc);
+ goto out_free_labels_buf;
+ } else {
+ /*
+ * Setting an incorrect countinuetoken upon
+ * receiving H_CONTINUE would result in H_P2. Since
+ * the continuetoken is being set to the expected
+ * value from the previous call, H_P2 must not be
+ * returned.
+ */
+ continuetoken = retbuf[1];
+
+ labels_count = retbuf[0];
+ if (!labels_count) {
+ kfree(labels_buf);
+ labels_buf = NULL;
+ goto out;
+ }
+
+ /*
+ * Filter out object labels that don't have the provided
+ * component prefix.
+ */
+
+ output_buf_len +=
+ roundup_pow_of_two(PLPKS_OBJLABEL_BUF_MAX);
+
+ tmp_buf = krealloc(*output_buf, output_buf_len,
+ GFP_KERNEL);
+
+ if (!tmp_buf) {
+ rc = -ENOMEM;
+ goto out_free_labels_buf;
+ }
+
+ *output_buf = tmp_buf;
+
+ for (i = 0; i < labels_count; ++i) {
+ label_len =
+ get_unaligned_be16(labels_buf +
+ labels_buf_offset);
+
+ obj_label_entry_size =
+ PLPKS_OBJLABEL_LEN_FIELD_SIZE +
+ label_len;
+
+ metadata =
+ (struct label_attr *)(labels_buf +
+ labels_buf_offset +
+ PLPKS_OBJLABEL_LEN_FIELD_SIZE);
+
+ if (!memcmp(metadata->prefix, comp_prefix,
+ PLPKS_OBJLABEL_PREFIX_LEN)) {
+ memcpy(*output_buf + output_buf_offset,
+ labels_buf + labels_buf_offset,
+ obj_label_entry_size);
+
+ output_buf_offset +=
+ obj_label_entry_size;
+ (*output_len) += 1;
+ }
+ labels_buf_offset += obj_label_entry_size;
+ }
+ kfree(labels_buf);
+ labels_buf = NULL;
+ labels_buf_offset = 0;
+ }
+ } while (rc == -EAGAIN);
+
+ goto out;
+
+out_free_labels_buf:
+ kfree(labels_buf);
+ labels_buf = NULL;
+out_free_output_buf:
+ kfree(*output_buf);
+ *output_buf = NULL;
+ *output_len = 0;
+out:
+ kfree_sensitive(auth);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(plpks_get_object_labels);
+
/**
* plpks_read_os_var() - Fetch the data for the specified variable that is owned
* by the OS consumer.
--
2.52.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 5/6] keys/trusted_keys: enable PKWM wrapping key selection by label
2026-10-17 7:48 [PATCH v3 0/6] Extend PKWM to support user-created wrapping keys Srish Srinivasan
` (3 preceding siblings ...)
2026-10-17 7:48 ` [PATCH v3 4/6] pseries/plpks: add HCALLs for PKWM wrapping key life cycle management Srish Srinivasan
@ 2026-10-17 7:48 ` Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 6/6] pseries/plpks/wrapkey: expose PKWM wrapping key management to userspace via sysfs Srish Srinivasan
5 siblings, 0 replies; 7+ messages in thread
From: Srish Srinivasan @ 2026-10-17 7:48 UTC (permalink / raw)
To: linux-integrity, keyrings, linuxppc-dev
Cc: maddy, ritesh.list, sshegde, mpe, npiggin, christophe.leroy,
James.Bottomley, jarkko, zohar, linux-kernel,
linux-security-module, nayna, rnsastry, ssrish
The PKWM trusted source currently uses the default wrapping key for all
seal and unseal operations. However, PKWM supports multiple wrapping keys,
enabling better isolation between trusted keys.
Allow users to provide an active wrapping key of their choice created
through sysfs when sealing trusted keys through a new wrapping_key=<label>
option. If no label is specified, the default wrapping key is used for
sealing.
Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Tested-by: R Nageswara Sastry <rnsastry@linux.ibm.com>
---
.../security/keys/trusted-encrypted.rst | 4 +-
arch/powerpc/include/asm/plpks.h | 10 +++-
arch/powerpc/platforms/pseries/plpks.c | 49 ++++++++-----------
include/keys/trusted_pkwm.h | 3 ++
security/keys/trusted-keys/trusted_pkwm.c | 38 ++++++++++++--
5 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst
index ddff7c7c2582..76fda28fddb1 100644
--- a/Documentation/security/keys/trusted-encrypted.rst
+++ b/Documentation/security/keys/trusted-encrypted.rst
@@ -83,7 +83,7 @@ safe.
(5) PKWM (PowerVM Key Wrapping Module: IBM PowerVM + Platform KeyStore)
- Rooted to a unique, per-LPAR key, which is derived from a system-wide,
+ Rooted to unique, per-LPAR keys, which are derived from a system-wide,
randomly generated LPAR root key. Both the per-LPAR keys and the LPAR
root key are stored in hypervisor-owned secure memory at runtime,
and the LPAR root key is additionally persisted in secure locations
@@ -366,6 +366,8 @@ Usage::
0x01: require secure boot to be in either audit or
enforced mode
0x02: require secure boot to be in enforced mode
+ wrapping_key= optional wrapping key label as a string. The default
+ wrapping key is used when no label is provided.
"keyctl print" returns an ASCII hex copy of the sealed key, which is in format
specific to PKWM key-blob implementation. The key length for new keys is
diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index c39d1f07017e..badb07afe749 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -50,6 +50,12 @@
#define PLPKS_MAX_TIMEOUT (5 * USEC_PER_SEC)
#define PLPKS_FLUSH_SLEEP 10000 // usec
+// Label for the PKWM default wrapping key
+#define PLPKS_DEFAULT_WRAPKEY_LABEL "default-wrapping-key"
+
+// Component for a PKWM wrapping key
+#define PLPKS_WRAPKEY_COMPONENT "PLPKSWR"
+
struct plpks_var {
char *component;
u8 *name;
@@ -117,10 +123,10 @@ int plpks_config_create_softlink(struct kobject *from);
bool plpks_wrapping_is_supported(void);
-int plpks_gen_wrapping_key(void);
+int plpks_gen_wrapping_key(struct plpks_var *var);
int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
- u8 **output_buf, u64 *output_len);
+ u8 **output_buf, u64 *output_len, struct plpks_var *var);
int plpks_unwrap_object(u8 **input_buf, u64 input_len,
u8 **output_buf, u64 *output_len);
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index edd189cfcc85..a4fb5dbac406 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -9,9 +9,6 @@
#define pr_fmt(fmt) "plpks: " fmt
-#define PLPKS_WRAPKEY_COMPONENT "PLPKSWR"
-#define PLPKS_DEFAULT_WRAPKEY_LABEL "default-wrapping-key"
-
/*
* To 4K align the {input, output} buffers to the {UN}WRAP H_CALLs
*/
@@ -935,6 +932,7 @@ EXPORT_SYMBOL_GPL(plpks_revoke_is_supported);
/**
* plpks_gen_wrapping_key() - Generate a new random key with the 'wrapping key'
* policy set.
+ * @var: variable representing the wrapping key to be created
*
* The H_PKS_GEN_KEY HCALL makes the hypervisor generate a new random key and
* store the key in a PLPKS object with the provided object label. With the
@@ -960,25 +958,22 @@ EXPORT_SYMBOL_GPL(plpks_revoke_is_supported);
*
* Returns: On success 0 is returned, a negative errno if not.
*/
-int plpks_gen_wrapping_key(void)
+int plpks_gen_wrapping_key(struct plpks_var *var)
{
unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
struct plpks_auth *auth;
struct label *label;
int rc = 0, pseries_status = 0;
- struct plpks_var var = {
- .name = PLPKS_DEFAULT_WRAPKEY_LABEL,
- .namelen = sizeof(PLPKS_DEFAULT_WRAPKEY_LABEL) - 1,
- .policy = PLPKS_WRAPPINGKEY,
- .os = PLPKS_VAR_LINUX,
- .component = PLPKS_WRAPKEY_COMPONENT
- };
+
+ if (!var || !var->name || !*var->name)
+ return -EINVAL;
auth = construct_auth(PLPKS_OS_OWNER);
if (IS_ERR(auth))
return PTR_ERR(auth);
- label = construct_label(var.component, var.os, var.name, var.namelen);
+ label = construct_label(var->component, var->os, var->name,
+ var->namelen);
if (IS_ERR(label)) {
rc = PTR_ERR(label);
goto out;
@@ -986,7 +981,7 @@ int plpks_gen_wrapping_key(void)
rc = plpar_hcall(H_PKS_GEN_KEY, retbuf,
virt_to_phys(auth), virt_to_phys(label),
- label->size, var.policy,
+ label->size, var->policy,
NULL, PLPKS_WRAPPING_KEY_LENGTH);
if (!rc)
@@ -995,12 +990,9 @@ int plpks_gen_wrapping_key(void)
pseries_status = rc;
rc = pseries_status_to_err(rc);
- if (rc && rc != -EEXIST) {
- pr_err("H_PKS_GEN_KEY failed. pseries_status=%d, rc=%d",
+ if (rc && rc != -EEXIST)
+ pr_err("H_PKS_GEN_KEY failed. pseries_status=%d, rc=%d\n",
pseries_status, rc);
- } else {
- rc = 0;
- }
kfree(label);
out:
@@ -1010,13 +1002,14 @@ int plpks_gen_wrapping_key(void)
EXPORT_SYMBOL_GPL(plpks_gen_wrapping_key);
/**
- * plpks_wrap_object() - Wrap an object using the default wrapping key stored in
- * the PLPKS.
+ * plpks_wrap_object() - Wrap an object using the specified wrapping key stored
+ * in the PLPKS.
* @input_buf: buffer containing the data to be wrapped
* @input_len: length of the input buffer
* @wrap_flags: object wrapping flags
* @output_buf: buffer to store the wrapped data
* @output_len: length of the output buffer
+ * @var: variable representing the wrapping key to be used
*
* The H_PKS_WRAP_OBJECT HCALL wraps an object using a wrapping key stored in
* the PLPKS and returns the wrapped object to the caller. The caller provides a
@@ -1051,7 +1044,7 @@ EXPORT_SYMBOL_GPL(plpks_gen_wrapping_key);
* Returns: On success 0 is returned, a negative errno if not.
*/
int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
- u8 **output_buf, u64 *output_len)
+ u8 **output_buf, u64 *output_len, struct plpks_var *var)
{
unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = { 0 };
struct plpks_auth *auth;
@@ -1061,18 +1054,16 @@ int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
int rc = 0, pseries_status = 0;
bool sb_audit_or_enforce_bit = wrap_flags & BIT(0);
bool sb_enforce_bit = wrap_flags & BIT(1);
- struct plpks_var var = {
- .name = PLPKS_DEFAULT_WRAPKEY_LABEL,
- .namelen = sizeof(PLPKS_DEFAULT_WRAPKEY_LABEL) - 1,
- .os = PLPKS_VAR_LINUX,
- .component = PLPKS_WRAPKEY_COMPONENT
- };
+
+ if (!var || !var->name || !*var->name)
+ return -EINVAL;
auth = construct_auth(PLPKS_OS_OWNER);
if (IS_ERR(auth))
return PTR_ERR(auth);
- label = construct_label(var.component, var.os, var.name, var.namelen);
+ label = construct_label(var->component, var->os, var->name,
+ var->namelen);
if (IS_ERR(label)) {
rc = PTR_ERR(label);
goto out;
@@ -1135,7 +1126,7 @@ int plpks_wrap_object(u8 **input_buf, u64 input_len, u16 wrap_flags,
EXPORT_SYMBOL_GPL(plpks_wrap_object);
/**
- * plpks_unwrap_object() - Unwrap an object using the default wrapping key
+ * plpks_unwrap_object() - Unwrap an object using its associated wrapping key
* stored in the PLPKS.
* @input_buf: buffer containing the data to be unwrapped
* @input_len: length of the input buffer
diff --git a/include/keys/trusted_pkwm.h b/include/keys/trusted_pkwm.h
index 4035b9776394..53a5f780edd2 100644
--- a/include/keys/trusted_pkwm.h
+++ b/include/keys/trusted_pkwm.h
@@ -6,10 +6,13 @@
#include <linux/bitops.h>
#include <linux/printk.h>
+#define WRAPPING_KEY_LABEL_LEN_MAX 239
+
extern struct trusted_key_ops pkwm_trusted_key_ops;
struct trusted_pkwm_options {
u16 wrap_flags;
+ unsigned char wrapping_key_label[WRAPPING_KEY_LABEL_LEN_MAX + 1];
};
static inline void dump_options(struct trusted_key_options *o)
diff --git a/security/keys/trusted-keys/trusted_pkwm.c b/security/keys/trusted-keys/trusted_pkwm.c
index 6774557f818a..ba7717b474b2 100644
--- a/security/keys/trusted-keys/trusted_pkwm.c
+++ b/security/keys/trusted-keys/trusted_pkwm.c
@@ -13,10 +13,12 @@
enum {
Opt_err,
Opt_wrap_flags,
+ Opt_wrapping_key_label,
};
static const match_table_t key_tokens = {
{Opt_wrap_flags, "wrap_flags=%s"},
+ {Opt_wrapping_key_label, "wrapping_key=%s"},
{Opt_err, NULL}
};
@@ -50,6 +52,12 @@ static int getoptions(char *datablob, struct trusted_key_options *opt)
return -EINVAL;
pkwm->wrap_flags = wrap_flags;
break;
+ case Opt_wrapping_key_label:
+ if (strlen(args[0].from) > WRAPPING_KEY_LABEL_LEN_MAX)
+ return -EINVAL;
+ strscpy(pkwm->wrapping_key_label, args[0].from,
+ sizeof(pkwm->wrapping_key_label));
+ break;
default:
return -EINVAL;
}
@@ -82,6 +90,7 @@ static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
{
struct trusted_key_options *options = NULL;
struct trusted_pkwm_options *pkwm = NULL;
+ struct plpks_var var = {0};
u8 *input_buf, *output_buf;
u64 output_len, input_len;
int rc;
@@ -108,8 +117,18 @@ static int trusted_pkwm_seal(struct trusted_key_payload *p, char *datablob)
pkwm = options->private;
+ if (pkwm->wrapping_key_label[0]) {
+ var.name = (u8 *)pkwm->wrapping_key_label;
+ var.namelen = strlen(pkwm->wrapping_key_label);
+ } else {
+ var.name = (u8 *)PLPKS_DEFAULT_WRAPKEY_LABEL;
+ var.namelen = strlen(PLPKS_DEFAULT_WRAPKEY_LABEL);
+ }
+ var.os = PLPKS_VAR_LINUX;
+ var.component = PLPKS_WRAPKEY_COMPONENT;
+
rc = plpks_wrap_object(&input_buf, input_len, pkwm->wrap_flags,
- &output_buf, &output_len);
+ &output_buf, &output_len, &var);
if (!rc) {
memcpy(p->blob, output_buf, output_len);
p->blob_len = output_len;
@@ -161,15 +180,26 @@ static int trusted_pkwm_unseal(struct trusted_key_payload *p, char *datablob)
static int trusted_pkwm_init(void)
{
int ret;
+ struct plpks_var var;
if (!plpks_wrapping_is_supported()) {
pr_err("H_PKS_WRAP_OBJECT interface not supported\n");
return -ENODEV;
}
- ret = plpks_gen_wrapping_key();
- if (ret) {
- pr_err("Failed to generate default wrapping key\n");
+ var = (struct plpks_var) {
+ .name = (u8 *)PLPKS_DEFAULT_WRAPKEY_LABEL,
+ .namelen = sizeof(PLPKS_DEFAULT_WRAPKEY_LABEL) - 1,
+ .policy = PLPKS_WRAPPINGKEY,
+ .os = PLPKS_VAR_LINUX,
+ .component = PLPKS_WRAPKEY_COMPONENT
+ };
+
+ ret = plpks_gen_wrapping_key(&var);
+
+ /* An existing default wrapping key is considered success. */
+ if (ret && ret != -EEXIST) {
+ pr_err("Failed to generate default wrapping key: %d\n", ret);
return ret;
}
--
2.52.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 6/6] pseries/plpks/wrapkey: expose PKWM wrapping key management to userspace via sysfs
2026-10-17 7:48 [PATCH v3 0/6] Extend PKWM to support user-created wrapping keys Srish Srinivasan
` (4 preceding siblings ...)
2026-10-17 7:48 ` [PATCH v3 5/6] keys/trusted_keys: enable PKWM wrapping key selection by label Srish Srinivasan
@ 2026-10-17 7:48 ` Srish Srinivasan
5 siblings, 0 replies; 7+ messages in thread
From: Srish Srinivasan @ 2026-10-17 7:48 UTC (permalink / raw)
To: linux-integrity, keyrings, linuxppc-dev
Cc: maddy, ritesh.list, sshegde, mpe, npiggin, christophe.leroy,
James.Bottomley, jarkko, zohar, linux-kernel,
linux-security-module, nayna, rnsastry, ssrish
The PKWM trusted source currently uses a single default wrapping key
created during initialization. However, PKWM also supports user-created
wrapping keys for better isolation between trusted keys.
Expose wrapping key lifecycle operations through sysfs to allow users to
create and manage their own wrapping keys.
Create a sysfs interface at /sys/firmware/plpks/wrapkey with the following
attributes:
create - Create a new wrapping key with a user-provided label
delete - Delete a revoked wrapping key by label
revoke - Revoke a wrapping key by label
unrevoke - Unrevoke a previously revoked wrapping key by label
list_active - List labels of all active (non-revoked) wrapping keys
list_revoked - List labels of all revoked wrapping keys
User-provided labels are validated to contain only alphanumeric characters.
Wrapping key lifecycle constraints:
- A wrapping key must be revoked before it can be deleted
- Revoked wrapping keys cannot be used for wrap operations until unrevoked
- The default wrapping key cannot be revoked or deleted; it always appears
in list_active
The wrapping keys themselves are confidential objects stored in PLPKS. Only
the user-provided labels are exposed to userspace for identification and
management purposes.
These user-created wrapping keys can be used in seal/unseal operations via
the wrapping_key=<label> option.
Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Tested-by: R Nageswara Sastry <rnsastry@linux.ibm.com>
---
.../ABI/testing/sysfs-firmware-plpks | 116 +++++
arch/powerpc/include/asm/plpks.h | 9 +
arch/powerpc/platforms/pseries/Kconfig | 15 +
arch/powerpc/platforms/pseries/Makefile | 1 +
arch/powerpc/platforms/pseries/plpks-sysfs.c | 11 +
.../platforms/pseries/plpks-wrapkey-sysfs.c | 399 ++++++++++++++++++
arch/powerpc/platforms/pseries/plpks.c | 1 -
7 files changed, 551 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c
diff --git a/Documentation/ABI/testing/sysfs-firmware-plpks b/Documentation/ABI/testing/sysfs-firmware-plpks
index cba061e4eee2..4144e868da1b 100644
--- a/Documentation/ABI/testing/sysfs-firmware-plpks
+++ b/Documentation/ABI/testing/sysfs-firmware-plpks
@@ -56,3 +56,119 @@ Description: Bitmask of the wrapping features indicating the wrapping
algorithms that are supported for the H_PKS_WRAP_OBJECT requests
, represented as a 8 byte hexadecimal ASCII string. Consult the
hypervisor documentation for what these flags mean.
+
+What: /sys/firmware/plpks/wrapkey
+Date: August 2026
+Contact: Srish Srinivasan <ssrish@linux.ibm.com>
+Description: This directory provides the interface for creating and managing
+ user-created PKWM wrapping keys.
+
+ The directory is present only when CONFIG_PLPKS_WRAPKEY_SYSFS is
+ enabled and the system supports the H_PKS_{UN}REVOKE_OBJECT
+ interfaces.
+
+ Only alphanumeric characters are accepted in wrapping key
+ labels. The wrapping keys themselves are confidential PLPKS
+ objects and are not exposed to userspace. Only their labels are
+ exposed for identification and management.
+
+ Each write is processed as an independent operation and accepts
+ exactly one wrapping key label. The resulting state can be
+ verified through list_active or list_revoked, as appropriate.
+
+ The default wrapping key, named "default-wrapping-key", cannot
+ be created, revoked, unrevoked, or deleted through this
+ interface.
+
+What: /sys/firmware/plpks/wrapkey/create
+Date: August 2026
+Contact: Srish Srinivasan <ssrish@linux.ibm.com>
+Description: (WO) Create a wrapping key with the specified label, except
+ "default-wrapping-key", which is reserved for the default
+ wrapping key.
+
+ On success, the label appears in list_active.
+
+ For example, to create a wrapping key labelled "wk1":
+
+ echo -n wk1 > /sys/firmware/plpks/wrapkey/create
+
+ or:
+
+ printf '%s' 'wk1' > /sys/firmware/plpks/wrapkey/create
+
+What: /sys/firmware/plpks/wrapkey/delete
+Date: August 2026
+Contact: Srish Srinivasan <ssrish@linux.ibm.com>
+Description: (WO) Delete a revoked wrapping key identified by the specified
+ label. A wrapping key must be revoked before it can be deleted.
+ The default wrapping key, named "default-wrapping-key", cannot
+ be deleted.
+
+ On success, the label no longer appears in list_revoked.
+
+ For example, to delete a revoked wrapping key labelled "wk1":
+
+ echo -n wk1 > /sys/firmware/plpks/wrapkey/delete
+
+ or:
+
+ printf '%s' 'wk1' > /sys/firmware/plpks/wrapkey/delete
+
+What: /sys/firmware/plpks/wrapkey/revoke
+Date: August 2026
+Contact: Srish Srinivasan <ssrish@linux.ibm.com>
+Description: (WO) Revoke a wrapping key identified by the specified label. A
+ revoked wrapping key cannot be used for seal or unseal
+ operations until it is unrevoked. The default wrapping key,
+ named "default-wrapping-key", cannot be revoked.
+
+ On success, the label appears in list_revoked and no longer
+ appears in list_active.
+
+ For example, to revoke a wrapping key labelled "wk1":
+
+ echo -n wk1 > /sys/firmware/plpks/wrapkey/revoke
+
+ or:
+
+ printf '%s' 'wk1' > /sys/firmware/plpks/wrapkey/revoke
+
+What: /sys/firmware/plpks/wrapkey/unrevoke
+Date: August 2026
+Contact: Srish Srinivasan <ssrish@linux.ibm.com>
+Description: (WO) Unrevoke a revoked wrapping key identified by the specified
+ label. The default wrapping key, named "default-wrapping-key",
+ cannot be unrevoked through this interface because it cannot be
+ revoked.
+
+ On success, the label appears in list_active and no longer
+ appears in list_revoked.
+
+ For example, to unrevoke a revoked wrapping key labelled "wk1":
+
+ echo -n wk1 > /sys/firmware/plpks/wrapkey/unrevoke
+
+ or:
+
+ printf '%s' 'wk1' > /sys/firmware/plpks/wrapkey/unrevoke
+
+What: /sys/firmware/plpks/wrapkey/list_active
+Date: August 2026
+Contact: Srish Srinivasan <ssrish@linux.ibm.com>
+Description: (RO) List the labels of active, non-revoked wrapping keys. The
+ default wrapping key, named "default-wrapping-key", is always
+ included in this list.
+
+ For example:
+
+ cat /sys/firmware/plpks/wrapkey/list_active
+
+What: /sys/firmware/plpks/wrapkey/list_revoked
+Date: August 2026
+Contact: Srish Srinivasan <ssrish@linux.ibm.com>
+Description: (RO) List the labels of revoked wrapping keys.
+
+ For example:
+
+ cat /sys/firmware/plpks/wrapkey/list_revoked
diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index badb07afe749..420945aeeb0e 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -56,6 +56,8 @@
// Component for a PKWM wrapping key
#define PLPKS_WRAPKEY_COMPONENT "PLPKSWR"
+#define PLPKS_OBJLABEL_LEN_FIELD_SIZE 2
+
struct plpks_var {
char *component;
u8 *name;
@@ -144,6 +146,9 @@ int plpks_get_object_labels(u8 **output_buf, u64 *output_len,
bool plpks_revoke_is_supported(void);
+int plpks_init_child_kobj(struct kobject *kobj, const struct kobj_type *ktype,
+ const char *name);
+
#else // CONFIG_PSERIES_PLPKS
static inline bool plpks_is_available(void) { return false; }
static inline u16 plpks_get_passwordlen(void) { BUILD_BUG(); }
@@ -151,6 +156,10 @@ static inline void plpks_early_init_devtree(void) { }
static inline int plpks_populate_fdt(void *fdt) { BUILD_BUG(); }
static inline int plpks_config_create_softlink(struct kobject *from)
{ return 0; }
+static inline int plpks_init_child_kobj(struct kobject *kobj,
+ const struct kobj_type *ktype,
+ const char *name)
+ { return 0; }
#endif // CONFIG_PSERIES_PLPKS
#endif // _ASM_POWERPC_PLPKS_H
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 74910ce3a541..d0dcfbae6fc9 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -216,3 +216,18 @@ config PPC_SVM
those guests.
If unsure, say "N".
+
+config PLPKS_WRAPKEY_SYSFS
+ bool "Enable sysfs interface for managing PKWM wrapping keys"
+ default n
+ depends on PSERIES_PLPKS
+ depends on SYSFS
+ depends on TRUSTED_KEYS_PKWM
+ help
+ The PKWM trusted source supports user-created wrapping keys that are
+ managed by the OS. These wrapping keys can be created, revoked,
+ unrevoked, and deleted through sysfs. Their labels can also be viewed
+ through sysfs.
+
+ Say Y if PLPKS and PKWM are enabled and you want to isolate trusted
+ keys using user-created wrapping keys.
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 3ced289a675b..c604be40f546 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_FA_DUMP) += rtas-fadump.o
obj-$(CONFIG_PSERIES_PLPKS) += plpks.o plpks-sysfs.o
obj-$(CONFIG_PPC_SECURE_BOOT) += plpks-secvar.o
obj-$(CONFIG_PSERIES_PLPKS_SED) += plpks_sed_ops.o
+obj-$(CONFIG_PLPKS_WRAPKEY_SYSFS) += plpks-wrapkey-sysfs.o
obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PPC_VAS) += vas.o vas-sysfs.o
diff --git a/arch/powerpc/platforms/pseries/plpks-sysfs.c b/arch/powerpc/platforms/pseries/plpks-sysfs.c
index f2436229f323..0ca13bb6405f 100644
--- a/arch/powerpc/platforms/pseries/plpks-sysfs.c
+++ b/arch/powerpc/platforms/pseries/plpks-sysfs.c
@@ -55,6 +55,17 @@ static umode_t plpks_config_attr_is_visible(struct kobject *kobj,
return attr->mode;
}
+int plpks_init_child_kobj(struct kobject *kobj, const struct kobj_type *ktype,
+ const char *name)
+{
+ kobject_init(kobj, ktype);
+
+ if (!plpks_kobj)
+ return -ENODEV;
+
+ return kobject_add(kobj, plpks_kobj, "%s", name);
+}
+
int plpks_config_create_softlink(struct kobject *from)
{
if (!plpks_config_kobj)
diff --git a/arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c b/arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c
new file mode 100644
index 000000000000..efae08e899b6
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c
@@ -0,0 +1,399 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 IBM Corporation <ssrish@linux.ibm.com>
+ *
+ * This code exposes wrapping key management options to the user via the
+ * sysfs
+ */
+
+#define pr_fmt(fmt) "wrapkey-sysfs: " fmt
+#define PLPKS_WRAPKEY_REVOKED 1
+#define PLPKS_WRAPKEY_UNREVOKED 0
+
+#include <linux/slab.h>
+#include <linux/compat.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <linux/ctype.h>
+#include <linux/unaligned.h>
+#include <asm/plpks.h>
+
+static struct kobject *wrapkey_kobj;
+
+static bool is_wrapkey_label_alnum(const char *key_label, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (!isalnum((unsigned char)key_label[i])) {
+ pr_err("key label <%*pE> is not alphanumeric\n",
+ (int)len, key_label);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static ssize_t list_key_labels(char *buf, u8 *obj_labels_buf,
+ u64 obj_labels_count, int revoked)
+{
+ struct plpks_var var = {0};
+ u8 *obj_labels_buf_ptr, *comp_prefix;
+ u8 *key_label_ptr;
+ u16 obj_label_len;
+ int len = 0;
+ int is_revoked;
+ u64 i;
+
+ var.os = PLPKS_VAR_LINUX;
+ var.component = PLPKS_WRAPKEY_COMPONENT;
+ obj_labels_buf_ptr = obj_labels_buf;
+
+ for (i = 0; i < obj_labels_count; ++i) {
+ obj_label_len = get_unaligned_be16(obj_labels_buf_ptr);
+ comp_prefix = obj_labels_buf_ptr +
+ PLPKS_OBJLABEL_LEN_FIELD_SIZE;
+
+ var.namelen = obj_label_len - PLPKS_MAX_LABEL_ATTR_SIZE;
+ var.name = kzalloc(var.namelen + 1, GFP_KERNEL);
+
+ if (!var.name)
+ return -ENOMEM;
+
+ key_label_ptr = comp_prefix + PLPKS_MAX_LABEL_ATTR_SIZE;
+ memcpy(var.name, key_label_ptr, var.namelen);
+
+ is_revoked = plpks_is_wrapping_key_revoked(&var);
+ if (is_revoked == revoked)
+ len += sysfs_emit_at(buf, len, "<%s>\n",
+ (char *)var.name);
+ else if (is_revoked < 0)
+ pr_warn("Failed to get revocation status for <%s>\n",
+ (char *)var.name);
+
+ kfree(var.name);
+ obj_labels_buf_ptr = key_label_ptr + var.namelen;
+ }
+
+ return len;
+}
+
+static ssize_t list_active_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ u8 *obj_labels_buf;
+ u64 obj_labels_count = 0;
+ int rc;
+
+ rc = plpks_get_object_labels(&obj_labels_buf, &obj_labels_count,
+ PLPKS_WRAPKEY_COMPONENT);
+ if (rc) {
+ pr_err("Retrieving object labels failed. rc=%d\n", rc);
+ goto out;
+ }
+
+ rc = list_key_labels(buf, obj_labels_buf, obj_labels_count,
+ PLPKS_WRAPKEY_UNREVOKED);
+
+out:
+ kfree(obj_labels_buf);
+ return rc;
+}
+
+static ssize_t list_revoked_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ u8 *obj_labels_buf;
+ u64 obj_labels_count = 0;
+ int rc;
+
+ rc = plpks_get_object_labels(&obj_labels_buf, &obj_labels_count,
+ PLPKS_WRAPKEY_COMPONENT);
+ if (rc) {
+ pr_err("Retrieving object labels failed. rc=%d\n", rc);
+ goto out;
+ }
+
+ rc = list_key_labels(buf, obj_labels_buf, obj_labels_count,
+ PLPKS_WRAPKEY_REVOKED);
+
+out:
+ kfree(obj_labels_buf);
+ return rc;
+}
+
+static ssize_t create_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct plpks_var var = {0};
+ int rc;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ rc = -EPERM;
+ goto out;
+ }
+
+ if (!count) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (count > PLPKS_MAX_NAME_SIZE) {
+ rc = -ENAMETOOLONG;
+ goto out;
+ }
+
+ if (!strcmp(buf, PLPKS_DEFAULT_WRAPKEY_LABEL)) {
+ rc = -EEXIST;
+ goto out;
+ }
+
+ if (!is_wrapkey_label_alnum(buf, count)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ var.name = kstrndup(buf, count, GFP_KERNEL);
+ if (!var.name) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ var.namelen = count;
+ var.policy = PLPKS_WRAPPINGKEY;
+ var.os = PLPKS_VAR_LINUX;
+ var.component = PLPKS_WRAPKEY_COMPONENT;
+
+ rc = plpks_gen_wrapping_key(&var);
+ if (rc) {
+ pr_err("creation of wrapping key <%s> failed. rc = %d\n",
+ (char *)var.name, rc);
+ goto out;
+ }
+
+ rc = count;
+out:
+ kfree(var.name);
+ return rc;
+}
+
+static ssize_t revoke_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct plpks_var var = {0};
+ int rc;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ rc = -EPERM;
+ goto out;
+ }
+
+ if (!count) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (count > PLPKS_MAX_NAME_SIZE) {
+ rc = -ENAMETOOLONG;
+ goto out;
+ }
+
+ if (!strcmp(buf, PLPKS_DEFAULT_WRAPKEY_LABEL)) {
+ rc = -EPERM;
+ goto out;
+ }
+
+ if (!is_wrapkey_label_alnum(buf, count)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ var.name = kstrndup(buf, count, GFP_KERNEL);
+ if (!var.name) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ var.namelen = count;
+ var.os = PLPKS_VAR_LINUX;
+ var.component = PLPKS_WRAPKEY_COMPONENT;
+
+ rc = plpks_revoke_wrapping_key(&var);
+
+ if (rc) {
+ pr_err("revocation of wrapping key <%s> failed. rc = %d\n",
+ (char *)var.name, rc);
+ goto out;
+ }
+
+ rc = count;
+out:
+ kfree(var.name);
+ return rc;
+}
+
+static ssize_t unrevoke_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct plpks_var var = {0};
+ int rc;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ rc = -EPERM;
+ goto out;
+ }
+
+ if (!count) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (count > PLPKS_MAX_NAME_SIZE) {
+ rc = -ENAMETOOLONG;
+ goto out;
+ }
+
+ if (!strcmp(buf, PLPKS_DEFAULT_WRAPKEY_LABEL)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (!is_wrapkey_label_alnum(buf, count)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ var.name = kstrndup(buf, count, GFP_KERNEL);
+ if (!var.name) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ var.namelen = count;
+ var.os = PLPKS_VAR_LINUX;
+ var.component = PLPKS_WRAPKEY_COMPONENT;
+
+ rc = plpks_unrevoke_wrapping_key(&var);
+
+ if (rc) {
+ pr_err("un-revocation of wrapping key <%s> failed. rc = %d\n",
+ (char *)var.name, rc);
+ goto out;
+ }
+
+ rc = count;
+out:
+ kfree(var.name);
+ return rc;
+}
+
+static ssize_t delete_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct plpks_var var = {0};
+ int rc;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ rc = -EPERM;
+ goto out;
+ }
+
+ if (!count) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (count > PLPKS_MAX_NAME_SIZE) {
+ rc = -ENAMETOOLONG;
+ goto out;
+ }
+
+ if (!strcmp(buf, PLPKS_DEFAULT_WRAPKEY_LABEL)) {
+ rc = -EPERM;
+ goto out;
+ }
+
+ if (!is_wrapkey_label_alnum(buf, count)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ var.name = kstrndup(buf, count, GFP_KERNEL);
+ if (!var.name) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ var.namelen = count;
+ var.os = PLPKS_VAR_LINUX;
+ var.component = PLPKS_WRAPKEY_COMPONENT;
+
+ rc = plpks_del_wrapping_key(&var);
+
+ if (rc) {
+ pr_err("deletion of wrapping key <%s> failed. rc = %d\n",
+ (char *)var.name, rc);
+ goto out;
+ }
+
+ rc = count;
+out:
+ kfree(var.name);
+ return rc;
+}
+
+static struct kobj_attribute view_active_attr = __ATTR_RO(list_active);
+
+static struct kobj_attribute view_revoked_attr = __ATTR_RO(list_revoked);
+
+static struct kobj_attribute create_attr = __ATTR_WO(create);
+
+static struct kobj_attribute revoke_attr = __ATTR_WO(revoke);
+
+static struct kobj_attribute unrevoke_attr = __ATTR_WO(unrevoke);
+
+static struct kobj_attribute delete_attr = __ATTR_WO(delete);
+
+static struct attribute *wrapkey_attrs[] = {
+ &view_active_attr.attr,
+ &view_revoked_attr.attr,
+ &create_attr.attr,
+ &revoke_attr.attr,
+ &unrevoke_attr.attr,
+ &delete_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group wrapkey_attr_group = {
+ .attrs = wrapkey_attrs,
+};
+__ATTRIBUTE_GROUPS(wrapkey_attr);
+
+static const struct kobj_type wrapkey_ktype = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = wrapkey_attr_groups,
+};
+
+static __init int wrapkey_sysfs_init(void)
+{
+ int rc;
+
+ if (!plpks_revoke_is_supported()) {
+ pr_err("H_PKS_{UN}REVOKE_OBJECT interface not supported\n");
+ return -ENODEV;
+ }
+
+ wrapkey_kobj = kzalloc_obj(*wrapkey_kobj);
+ if (!wrapkey_kobj)
+ return -ENOMEM;
+
+ rc = plpks_init_child_kobj(wrapkey_kobj, &wrapkey_ktype, "wrapkey");
+
+ if (rc)
+ kobject_put(wrapkey_kobj);
+
+ return rc;
+}
+
+late_initcall(wrapkey_sysfs_init);
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index a4fb5dbac406..dd916af71c11 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -25,7 +25,6 @@
*/
#define PLPKS_OBJLABEL_BUF_MAX 2550
-#define PLPKS_OBJLABEL_LEN_FIELD_SIZE 2
#define PLPKS_OBJLABEL_PREFIX_LEN 8
#define PLPKS_WRAP_INTERFACE_BIT 3
--
2.52.0
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-17 7:50 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-17 7:48 [PATCH v3 0/6] Extend PKWM to support user-created wrapping keys Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 1/6] pseries/plpks: fix length types for wrapping operations Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 2/6] keys/trusted_keys: propagate wrapping key generation errors Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 3/6] keys/trusted_keys: clear sensitive PKWM buffers Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 4/6] pseries/plpks: add HCALLs for PKWM wrapping key life cycle management Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 5/6] keys/trusted_keys: enable PKWM wrapping key selection by label Srish Srinivasan
2026-10-17 7:48 ` [PATCH v3 6/6] pseries/plpks/wrapkey: expose PKWM wrapping key management to userspace via sysfs Srish Srinivasan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®