Extend PKWM to support user-created wrapping keys
Subsystems (8)
Srish Srinivasan
maintainerv6 cover Extend PKWM to support user-created wrapping keys
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 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 six preparatory fixes. These correct double conversion of PLPKS write, remove, and wrapping key flush errors; align wrapping length types with the underlying HCALL interfaces; preserve the original error returned when default wrapping key generation fails; initialize PKWM output buffer pointers before cleanup; and clear sensitive PKWM seal and unseal buffers before freeing them.
Changelog:
v5 -> v6:
- Hardened wrapping key lifecycle HCALL helpers
- Default wrapping key check
- Component prefix and wrapping key handling
- Label length validation
- -ENXIO when revoke/unrevoke are unsupported
- Rejected non-ASCII characters in wrapping key labels
- Added stable prerequisite to the wrapping key flush error fix
- Re-ordered the stable fixes
v4 -> v5:
- Addressed issues reported by Sashiko
- Added HCALL-defined length validation for wrapping operations
- Cleared stale PLPKS sysfs kobject pointers on initialization failure
- Documented "default-wrapping-key" as a reserved label without assuming it exists
- Dropped Tested-by tags from modified patches
v3 -> v4:
- Addressed issues reported by Sashiko
- Fixed double conversion of PLPKS object flush errors
- Initialized PKWM output buffer pointers before cleanup
- Corrected the documented H_PKS_GET_OBJECTLABELS output field order
- Prevented stale policy use and caller data modification during revocation checks
- Fixed wrapping key sysfs kobject cleanup
- Restricted wrapping key sysfs initialization to pseries
- Dropped Tested-by tags from modified patches
v2 -> v3:
- Moved most of the refactoring and hardening patches into a separate series:
https://lore.kernel.org/all/[email protected]/
- Added a fix to clear sensitive PKWM seal and unseal buffers before freeing them
- Added 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 [email protected] where applicable
Srish Srinivasan (9):
keys/trusted_keys: propagate wrapping key generation errors keys/trusted_keys: fix PKWM output buffer cleanup keys/trusted_keys: clear sensitive PKWM buffers pseries/plpks: fix double conversion of write and remove flush errors pseries/plpks: fix double conversion of wrapping key flush errors pseries/plpks: fix length types for wrapping operations 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 | 113 ++++ 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 | 14 + .../platforms/pseries/plpks-wrapkey-sysfs.c | 408 +++++++++++++ arch/powerpc/platforms/pseries/plpks.c | 576 ++++++++++++++++-- include/keys/trusted_pkwm.h | 3 + security/keys/trusted-keys/trusted_pkwm.c | 52 +- 12 files changed, 1203 insertions(+), 61 deletions(-) create mode 100644 arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c
Signature · 1 line
2.52.0
Srish Srinivasan
maintainerPATCH v6 1/9 keys/trusted_keys: propagate wrapping key generation errors
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.
--- security/keys/trusted-keys/trusted_pkwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/keys/trusted-keys/trusted_pkwm.c +1 -1
@@ -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);
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH v6 1/9] keys/trusted_keys: propagate wrapping key generation errors
Sashiko has reviewed this patch and found no issues.
Quoted 9 lines
plpks_gen_wrapping_key()returns a negative errno when default wrapping key generation fails. However,trusted_pkwm_init()returns-EINVALfor 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 [email protected] # 7.0Signed-off-by Srish Srinivasan <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Re: [PATCH v6 1/9] keys/trusted_keys: propagate wrapping key generation errors
In reply to Srish SrinivasanQuoted 10 lines · Srish Srinivasan
plpks_gen_wrapping_key()returns a negative errno when default wrapping key generation fails. However,trusted_pkwm_init()returns-EINVALfor 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 [email protected] # 7.0Signed-off-by Srish Srinivasan <[email protected]>Tested-by R Nageswara Sastry <[email protected]>
Nit: I'd put the SOB as last.
Quoted 20 lines
--- security/keys/trusted-keys/trusted_pkwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)security/keys/trusted-keys/trusted_pkwm.c +1
-1@@ -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);Signature · 1 line
2.52.0
Br, Jarkko
Srish Srinivasan
maintainerRe: [PATCH v6 1/9] keys/trusted_keys: propagate wrapping key generation errors
Hi Jarkko,
Thanks for taking a look.
Quoted 5 lines · Jarkko Sakkinen
Quoted 4 lines · Srish Srinivasan
plpks_gen_wrapping_key()returns a negative errno when default wrapping key generation fails. However,trusted_pkwm_init()returns-EINVALfor all such failures, discarding the original error.
Quoted 7 lines
Quoted 6 lines
Propagate the error returned by
plpks_gen_wrapping_key()unchanged.Fixes c99fcb0d735b ("keys/trusted_keys: establish PKWM as a trusted source")Cc [email protected] # 7.0Signed-off-by Srish Srinivasan <[email protected]>Tested-by R Nageswara Sastry <[email protected]>Nit: I'd put the SOB as last.
Sure, I will make this change.
Quoted 17 lines
Quoted 17 lines
--- security/keys/trusted-keys/trusted_pkwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)security/keys/trusted-keys/trusted_pkwm.c +1
-1@@ -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; }
Quoted 5 lines
Quoted 4 lines
security/keys/trusted-keys/trusted_pkwm.c +0
-0return register_key_type (&key_type_trusted);Signature · 1 line
2.52.0Reviewed-by Jarkko Sakkinen <[email protected]>
Thank you for the Rb.
Quoted 2 lines
Br, Jarkko
Thanks,
Srish.
Srish Srinivasan
maintainerPATCH v6 2/9 keys/trusted_keys: fix PKWM output buffer cleanup
In reply to Srish SrinivasanThe PKWM seal and unseal paths unconditionally free their output buffers, but the PLPKS helpers can return without initializing those pointers.
Initialize the output buffer pointers to NULL to make cleanup safe on early failure paths.
--- security/keys/trusted-keys/trusted_pkwm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
security/keys/trusted-keys/trusted_pkwm.c +2 -2
@@ -82,7 +82,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; +u8 *input_buf, *output_buf =NULL ;u32 output_len, input_len;int rc;
@@ -129,7 +129,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; +u8 *input_buf, *output_buf =NULL ;u32 input_len, output_len;int rc;
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH v6 2/9] keys/trusted_keys: fix PKWM output buffer cleanup
Sashiko has reviewed this patch and found no issues.
Quoted 9 lines
The PKWM seal and unseal paths unconditionally free their output buffers, but the PLPKS helpers can return without initializing those pointers.
Initialize the output buffer pointers to NULL to make cleanup safe on early failure paths.
Fixes c99fcb0d735b ("keys/trusted_keys: establish PKWM as a trusted source")Cc [email protected] # 7.0Signed-off-by Srish Srinivasan <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [PATCH v6 2/9] keys/trusted_keys: fix PKWM output buffer cleanup
In reply to Srish SrinivasanQuoted 38 lines · Srish Srinivasan
The PKWM seal and unseal paths unconditionally free their output buffers, but the PLPKS helpers can return without initializing those pointers.
Initialize the output buffer pointers to NULL to make cleanup safe on early failure paths.
Fixes c99fcb0d735b ("keys/trusted_keys: establish PKWM as a trusted source")Cc [email protected] # 7.0Signed-off-by Srish Srinivasan <[email protected]>--- security/keys/trusted-keys/trusted_pkwm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)security/keys/trusted-keys/trusted_pkwm.c +2
-2@@ -82,7 +82,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; +u8 *input_buf, *output_buf =NULL ;u32 output_len, input_len;int rc;@@ -129,7 +129,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; +u8 *input_buf, *output_buf =NULL ;u32 input_len, output_len;int rc;Signature · 1 line
2.52.0
Br, Jarkko
Srish Srinivasan
maintainerRe: [PATCH v6 2/9] keys/trusted_keys: fix PKWM output buffer cleanup
Quoted 36 lines · Jarkko Sakkinen
Quoted 35 lines · Srish Srinivasan
The PKWM seal and unseal paths unconditionally free their output buffers, but the PLPKS helpers can return without initializing those pointers.
Initialize the output buffer pointers to NULL to make cleanup safe on early failure paths.
Fixes c99fcb0d735b ("keys/trusted_keys: establish PKWM as a trusted source")Cc [email protected] # 7.0Signed-off-by Srish Srinivasan <[email protected]>--- security/keys/trusted-keys/trusted_pkwm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)security/keys/trusted-keys/trusted_pkwm.c +2
-2@@ -82,7 +82,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; +u8 *input_buf, *output_buf =NULL ;u32 output_len, input_len;int rc;@@ -129,7 +129,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; +u8 *input_buf, *output_buf =NULL ;u32 input_len, output_len;int rc;
Quoted 4 lines
Quoted 3 lines
Signature · 1 line
2.52.0Reviewed-by Jarkko Sakkinen <[email protected]>
Thank you for the Rb, Jarkko.
Quoted 2 lines
Br, Jarkko
Thanks,
Srish.
Srish Srinivasan
maintainerPATCH v6 3/9 keys/trusted_keys: clear sensitive PKWM buffers
In reply to Srish SrinivasanThe 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.
--- security/keys/trusted-keys/trusted_pkwm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
security/keys/trusted-keys/trusted_pkwm.c +2 -2
@@ -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; }
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH v6 3/9] keys/trusted_keys: clear sensitive PKWM buffers
Sashiko has reviewed this patch and found no issues.
Quoted 11 lines
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 [email protected] # 7.0Signed-off-by Srish Srinivasan <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Srish Srinivasan
maintainerPATCH v6 4/9 pseries/plpks: fix double conversion of write and remove flush errors
In reply to Srish Srinivasanplpks_confirm_object_flushed() returns zero or a negative Linux errno. However, plpks_write_var() and plpks_remove_var() pass this return value through pseries_status_to_err(), which treats it as a raw hypervisor status and converts it again.
Convert only errors returned by the write and remove HCALLs, and propagate errors from plpks_confirm_object_flushed() unchanged.
--- arch/powerpc/platforms/pseries/plpks.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
arch/powerpc/platforms/pseries/plpks.c +6 -2
@@ -714,6 +714,7 @@ int plpks_signed_update_var(struct plpks_var *var, u64 flags)* -ENOMEM if unable to store the requested object in the space available * -EBUSY if unable to handle the request * -EEXIST if the object label already exists +* -ETIMEDOUT if the object was not flushed to storage in time * * Returns: On success 0 is returned, a negative errno if not. */
@@ -750,8 +751,9 @@ int plpks_write_var(struct plpks_var var)if (!rc) rc =plpks_confirm_object_flushed (label, auth); +else + rc =pseries_status_to_err (rc); - rc =pseries_status_to_err (rc);kfree (label); out:kfree_sensitive (auth);
@@ -780,6 +782,7 @@ int plpks_write_var(struct plpks_var var)* -EPERM if access is denied * -ENOENT if the requested object was not found * -EBUSY if unable to handle the request +* -ETIMEDOUT if the object was not flushed to storage in time * * Returns: On success 0 is returned, a negative errno if not. */
@@ -808,8 +811,9 @@ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname)if (!rc) rc =plpks_confirm_object_flushed (label, auth); +else + rc =pseries_status_to_err (rc); - rc =pseries_status_to_err (rc);kfree (label); out:kfree_sensitive (auth);
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH v6 4/9] pseries/plpks: fix double conversion of write and remove flush errors
Sashiko has reviewed this patch and found no issues.
Quoted 11 lines
plpks_confirm_object_flushed()returns zero or a negative Linux errno. However,plpks_write_var()andplpks_remove_var()pass this return value throughpseries_status_to_err(), which treats it as a raw hypervisor status and converts it again.Convert only errors returned by the write and remove HCALLs, and propagate errors from
plpks_confirm_object_flushed()unchanged.Fixes 2454a7af0f2a ("powerpc/pseries: define driver for Platform KeyStore")Cc [email protected] # 6.0Signed-off-by Srish Srinivasan <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Srish Srinivasan
maintainerPATCH v6 5/9 pseries/plpks: fix double conversion of wrapping key flush errors
In reply to Srish Srinivasanplpks_confirm_object_flushed() returns zero or a negative Linux errno. However, plpks_gen_wrapping_key() passes this return value through pseries_status_to_err(), which treats it as a raw hypervisor status and converts it again.
Convert only errors returned by H_PKS_GEN_KEY, and propagate errors from plpks_confirm_object_flushed() unchanged.
--- arch/powerpc/platforms/pseries/plpks.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
arch/powerpc/platforms/pseries/plpks.c +11 -10
@@ -932,6 +932,7 @@ EXPORT_SYMBOL_GPL(plpks_wrapping_is_supported);* -ENOMEM if there is inadequate memory to perform this operation * -EBUSY if unable to handle the request * -EEXIST if the object label already exists +* -ETIMEDOUT if the object was not flushed to storage in time * * Returns: On success 0 is returned, a negative errno if not. */
@@ -940,7 +941,7 @@ int plpks_gen_wrapping_key(void)unsigned long retbuf[PLPAR_HCALL_BUFSIZE ] = {0 };struct plpks_auth *auth;struct label *label; -int rc =0 , pseries_status =0 ; +int rc, pseries_status;struct plpks_var var = { .name =PLPKS_DEFAULT_WRAPKEY_LABEL , .namelen =sizeof (PLPKS_DEFAULT_WRAPKEY_LABEL ) -1 ,
@@ -964,17 +965,17 @@ int plpks_gen_wrapping_key(void) label->size, var.policy, NULL, PLPKS_WRAPPING_KEY_LENGTH); -if (!rc) +if (!rc) { rc =plpks_confirm_object_flushed (label, auth); - - 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" , - pseries_status, rc); }else { - rc =0 ; + pseries_status = rc; + rc =pseries_status_to_err (rc); + +if (rc != -EEXIST ) +pr_err ("H_PKS_GEN_KEY failed. pseries_status=%d, rc=%d" , + pseries_status, rc); +else + rc =0 ; }kfree (label);
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH v6 5/9] pseries/plpks: fix double conversion of wrapping key flush errors
Sashiko has reviewed this patch and found no issues.
Quoted 5 lines
plpks_confirm_object_flushed()returns zero or a negative Linux errno. However,plpks_gen_wrapping_key()passes this return value throughpseries_status_to_err(), which treats it as a raw hypervisor status and converts it again.
Quoted 7 lines
Convert only errors returned by
H_PKS_GEN_KEY, and propagate errors fromplpks_confirm_object_flushed()unchanged.Fixes 133aa79e211d ("pseries/plpks: add HCALLs for PowerVM Key Wrapping Module")Cc [email protected] # 7.0: a2df535d9dd9: pseries/plpks: rename the default wrapping key macroCc [email protected] # 7.0Signed-off-by Srish Srinivasan <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
Srish Srinivasan
maintainerPATCH v6 6/9 pseries/plpks: fix length types for wrapping operations
In reply to Srish SrinivasanThe 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.
Use u64 for the length parameters to match the underlying HCALL interfaces, and update the PKWM consumer accordingly. Validate input lengths against the HCALL-defined limits before calculating output buffer sizes.
--- arch/powerpc/include/asm/plpks.h | 8 ++++---- arch/powerpc/platforms/pseries/plpks.c | 23 +++++++++++++++++------ security/keys/trusted-keys/trusted_pkwm.c | 4 ++-- 3 files changed, 23 insertions(+), 12 deletions(-)
arch/powerpc/include/asm/plpks.h +4 -4
@@ -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 (); }
arch/powerpc/platforms/pseries/plpks.c +17 -6
@@ -22,6 +22,9 @@* than the input buffer's length during the WRAP H_CALL */ #define PLPKS_WRAPPING_BUF_DIFF 1024 +#define PLPKS_MAX_WRAPPING_INPUT_SIZE (32 * 1024) +#define PLPKS_MAX_WRAPPED_OBJECT_SIZE \ + (PLPKS_MAX_WRAPPING_INPUT_SIZE + PLPKS_WRAPPING_BUF_DIFF)#define PLPKS_WRAP_INTERFACE_BIT 3#define PLPKS_WRAPPING_KEY_LENGTH 32
@@ -989,7 +992,7 @@ EXPORT_SYMBOL_GPL(plpks_gen_wrapping_key);* plpks_wrap_object() - Wrap an object using the default wrapping key stored in * the PLPKS. * @input_buf: buffer containing the data to be wrapped -* @input_len: length of the input buffer +* @input_len: length of the input buffer (non-zero, at most 32KB) * @wrap_flags: object wrapping flags * @output_buf: buffer to store the wrapped data * @output_len: length of the output buffer
@@ -1026,8 +1029,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;
@@ -1044,6 +1047,9 @@ int plpks_wrap_object(u8 **input_buf, u32 input_len, u16 wrap_flags, .component = PLPKS_WRAPKEY_COMPONENT }; +if (!input_len || input_len >PLPKS_MAX_WRAPPING_INPUT_SIZE ) +return -EINVAL ; + auth =construct_auth (PLPKS_OS_OWNER );if (IS_ERR (auth))return PTR_ERR (auth);
@@ -1114,7 +1120,7 @@ EXPORT_SYMBOL_GPL(plpks_wrap_object);* plpks_unwrap_object() - Unwrap an object using the default wrapping key * stored in the PLPKS. * @input_buf: buffer containing the data to be unwrapped -* @input_len: length of the input buffer +* @input_len: length of the input buffer (more than 1KB, at most 33KB) * @output_buf: buffer to store the unwrapped data * @output_len: length of the output buffer *
@@ -1145,8 +1151,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;
@@ -1154,6 +1160,11 @@ int plpks_unwrap_object(u8 **input_buf, u32 input_len, u8 **output_buf,u64 objwrapflags =0 ;int rc =0 , pseries_status =0 ; +/* outlen = inlen - 1KB must be non-zero */ +if (input_len <=PLPKS_WRAPPING_BUF_DIFF || + input_len >PLPKS_MAX_WRAPPED_OBJECT_SIZE ) +return -EINVAL ; + auth =construct_auth (PLPKS_OS_OWNER );if (IS_ERR (auth))return PTR_ERR (auth);
security/keys/trusted-keys/trusted_pkwm.c +2 -2
@@ -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 =NULL ; -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 =NULL ; -u32 input_len, output_len; +u64 input_len, output_len;int rc; input_len = p->blob_len;
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH v6 6/9] pseries/plpks: fix length types for wrapping operations
Sashiko has reviewed this patch and found no issues.
Quoted 4 lines
The object wrapping and unwrapping HCALLs use 64-bit length values, but
plpks_wrap_object()andplpks_unwrap_object()currently use u32 for the input and output length parameters.
Quoted 8 lines
Use u64 for the length parameters to match the underlying HCALL interfaces, and update the PKWM consumer accordingly. Validate input lengths against the HCALL-defined limits before calculating output buffer sizes.
Fixes 133aa79e211d ("pseries/plpks: add HCALLs for PowerVM Key Wrapping Module")Fixes c99fcb0d735b ("keys/trusted_keys: establish PKWM as a trusted source")Cc [email protected] # 7.0Signed-off-by Srish Srinivasan <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
Srish Srinivasan
maintainerPATCH v6 7/9 pseries/plpks: add HCALLs for PKWM wrapping key life cycle management
In reply to Srish SrinivasanThe 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.
--- 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 | 489 ++++++++++++++++++++- 4 files changed, 538 insertions(+), 4 deletions(-)
Documentation/arch/powerpc/papr_hcalls.rst +33 -0
@@ -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: *number of object labels in the returned list, continue-token, 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"
arch/powerpc/include/asm/hvcall.h +4 -1
@@ -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)
arch/powerpc/include/asm/plpks.h +15 -0
@@ -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 (const 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 (); }
arch/powerpc/platforms/pseries/plpks.c +486 -3
539 lines not on this page · raw message
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH v6 7/9] pseries/plpks: add HCALLs for PKWM wrapping key life cycle management
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] pseries/plpks: output_buf leak and -EAGAIN return in plpks_get_object_labels() --
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] pseries/plpks: output_buf leak and -EAGAIN return in plpks_get_object_labels() --
commit 41ef08b282e00765eba284dad461f1985057d371
Author: Srish Srinivasan <[email protected]>
pseries/plpks: add HCALLs for PKWM wrapping key life cycle management
This commit adds support for the H_PKS_REVOKE_OBJECT, H_PKS_UNREVOKE_OBJECT, and H_PKS_GET_OBJECTLABELS hypercalls to manage the life cycle of PKWM wrapping keys and retrieve wrapping key labels in the Platform Keystore.
Quoted 4 lines
arch/powerpc/platforms/pseries/plpks.c +0
-0
[ ... ]
Quoted 1 line
arch/powerpc/platforms/pseries/plpks.c +0
-0@@ -1205,6 +1237,457 @@ int plpks_unwrap_object(u8 **input_buf, u64 input_len, u8 **output_buf,
[ ... ]
Quoted 133 lines
arch/powerpc/platforms/pseries/plpks.c +133
-0+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 ; +u8 prefix[PLPKS_OBJLABEL_PREFIX_LEN ]; +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; + +if (!output_buf || !output_len || !comp_prefix) +return -EINVAL ; + + *output_buf =NULL ; + *output_len =0 ; + +memset (prefix,0 ,sizeof (prefix)); +memcpy (prefix, comp_prefix,strnlen (comp_prefix,sizeof (prefix))); + + auth =construct_auth (PLPKS_OS_OWNER ); +if (IS_ERR (auth)) +return PTR_ERR (auth); + +do { + labels_buf = +kzalloc (PLPKS_OBJLABEL_BUF_SIZE ,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), +PLPKS_OBJLABEL_BUF_SIZE ); + + 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 +=PLPKS_OBJLABEL_BUF_SIZE ; + + 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) { +if (labels_buf_offset + +PLPKS_OBJLABEL_LEN_FIELD_SIZE > +PLPKS_OBJLABEL_BUF_SIZE ) { + rc = -EIO ; + goto out_free_labels_buf; + } + + label_len = +get_unaligned_be16 (labels_buf + + labels_buf_offset); + + obj_label_entry_size = +PLPKS_OBJLABEL_LEN_FIELD_SIZE + + label_len; + +if (label_len <sizeof (struct label_attr ) || + labels_buf_offset + obj_label_entry_size > +PLPKS_OBJLABEL_BUF_SIZE ) { + rc = -EIO ; + goto out_free_labels_buf; + } + + metadata = + (struct label_attr *)(labels_buf + + labels_buf_offset + +PLPKS_OBJLABEL_LEN_FIELD_SIZE ); + +if (!memcmp (metadata->prefix, 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:
arch/powerpc/platforms/pseries/plpks.c int plpks_unwrap_object(u8 **input_buf, u64 input_len, u8 **output_buf, · line 1688
Quoted 10 lines
arch/powerpc/platforms/pseries/plpks.c +10
-0+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; +}
[Severity: Medium]
Can plpks_get_object_labels() leak *output_buf or return -EAGAIN to the caller?
First, inside the do-while loop, when labels_count > 0, *output_buf is allocated or grown via krealloc() before checking whether any of the returned labels match comp_prefix. If PLPKS contains objects for other components so labels_count > 0, but none of those labels match comp_prefix, the loop completes with rc == 0 and *output_len == 0 and jumps to out without freeing *output_buf. Unlike the case where PLPKS has 0 total objects on the first call (which returns 0 with *output_len == 0 and *output_buf == NULL), this returns 0 with *output_len == 0 while *output_buf points to an allocated buffer of uninitialized heap memory. Callers checking *output_len == 0 will leak *output_buf, while callers checking *output_buf != NULL will read uninitialized memory.
Second, if !labels_count (retbuf[0] == 0) is encountered when H_PKS_GET_OBJECTLABELS returns H_CONTINUE (converted by pseries_status_to_err() to rc = -EAGAIN) or on a subsequent continuation iteration after *output_buf was already allocated, jumping directly to out bypasses the loop condition and out_free_output_buf. Could that return the internal continuation code -EAGAIN to the caller and leak any *output_buf allocated in prior iterations?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
Srish Srinivasan
maintainerRe: [PATCH v6 7/9] pseries/plpks: add HCALLs for PKWM wrapping key life cycle management
Hi
Quoted 3 lines · On 11/5/26 8:26 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] pseries/plpks:output_bufleak and-EAGAINreturn inplpks_get_object_labels()--
Yes, these are valid findings and I will fix these in my next version.
Thanks,
Srish.
Quoted 184 lines
commit
41ef08b282e00765eba284dad461f1985057d371
Author: Srish Srinivasan <[email protected]>pseries/plpks: add HCALLs for PKWM wrapping key life cycle management
This commit adds support for the
H_PKS_REVOKE_OBJECT,H_PKS_UNREVOKE_OBJECT, andH_PKS_GET_OBJECTLABELShypercalls to manage the life cycle of PKWM wrapping keys and retrieve wrapping key labels in the Platform Keystore.Quoted 4 lines
arch/powerpc/platforms/pseries/plpks.c +0
-0[ ... ]
Quoted 1 line
arch/powerpc/platforms/pseries/plpks.c +0
-0@@ -1205,6 +1237,457 @@ int plpks_unwrap_object(u8 **input_buf, u64 input_len, u8 **output_buf,[ ... ]
Quoted 133 lines
arch/powerpc/platforms/pseries/plpks.c +133
-0+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 ; +u8 prefix[PLPKS_OBJLABEL_PREFIX_LEN ]; +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; + +if (!output_buf || !output_len || !comp_prefix) +return -EINVAL ; + + *output_buf =NULL ; + *output_len =0 ; + +memset (prefix,0 ,sizeof (prefix)); +memcpy (prefix, comp_prefix,strnlen (comp_prefix,sizeof (prefix))); + + auth =construct_auth (PLPKS_OS_OWNER ); +if (IS_ERR (auth)) +return PTR_ERR (auth); + +do { + labels_buf = +kzalloc (PLPKS_OBJLABEL_BUF_SIZE ,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), +PLPKS_OBJLABEL_BUF_SIZE ); + + 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 +=PLPKS_OBJLABEL_BUF_SIZE ; + + 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) { +if (labels_buf_offset + +PLPKS_OBJLABEL_LEN_FIELD_SIZE > +PLPKS_OBJLABEL_BUF_SIZE ) { + rc = -EIO ; + goto out_free_labels_buf; + } + + label_len = +get_unaligned_be16 (labels_buf + + labels_buf_offset); + + obj_label_entry_size = +PLPKS_OBJLABEL_LEN_FIELD_SIZE + + label_len; + +if (label_len <sizeof (struct label_attr ) || + labels_buf_offset + obj_label_entry_size > +PLPKS_OBJLABEL_BUF_SIZE ) { + rc = -EIO ; + goto out_free_labels_buf; + } + + metadata = + (struct label_attr *)(labels_buf + + labels_buf_offset + +PLPKS_OBJLABEL_LEN_FIELD_SIZE ); + +if (!memcmp (metadata->prefix, 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:arch/powerpc/platforms/pseries/plpks.c int plpks_unwrap_object(u8 **input_buf, u64 input_len, u8 **output_buf, · line 1688
Quoted 10 lines
arch/powerpc/platforms/pseries/plpks.c +10
-0+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; +}[Severity: Medium]
Canplpks_get_object_labels()leak*output_bufor return-EAGAINto the caller?First, inside the do-while loop, when
labels_count> 0,*output_bufis allocated or grown viakrealloc()before checking whether any of the returned labels matchcomp_prefix. If PLPKS contains objects for other components solabels_count> 0, but none of those labels matchcomp_prefix, the loop completes with rc == 0 and*output_len== 0 and jumps to out without freeing*output_buf. Unlike the case where PLPKS has 0 total objects on the first call (which returns 0 with*output_len== 0 and*output_buf== NULL), this returns 0 with*output_len== 0 while*output_bufpoints to an allocated buffer of uninitialized heap memory. Callers checking*output_len== 0 will leak*output_buf, while callers checking*output_buf!= NULL will read uninitialized memory.Second, if !labels_count (retbuf[0] == 0) is encountered when
H_PKS_GET_OBJECTLABELSreturnsH_CONTINUE(converted bypseries_status_to_err()to rc =-EAGAIN) or on a subsequent continuation iteration after*output_bufwas already allocated, jumping directly to out bypasses the loop condition andout_free_output_buf. Could that return the internal continuation code-EAGAINto the caller and leak any*output_bufallocated in prior iterations?
Srish Srinivasan
maintainerPATCH v6 8/9 keys/trusted_keys: enable PKWM wrapping key selection by label
In reply to Srish SrinivasanThe 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.
--- .../security/keys/trusted-encrypted.rst | 4 +- arch/powerpc/include/asm/plpks.h | 10 ++++- arch/powerpc/platforms/pseries/plpks.c | 42 ++++++++----------- include/keys/trusted_pkwm.h | 3 ++ security/keys/trusted-keys/trusted_pkwm.c | 38 +++++++++++++++-- 5 files changed, 65 insertions(+), 32 deletions(-)
Documentation/security/keys/trusted-encrypted.rst +3 -1
@@ -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
arch/powerpc/include/asm/plpks.h +8 -2
@@ -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);
arch/powerpc/platforms/pseries/plpks.c +17 -25
118 lines not on this page · raw message
include/keys/trusted_pkwm.h +3 -0
@@ -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)
security/keys/trusted-keys/trusted_pkwm.c +34 -4
@@ -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 ; }
@@ -83,6 +91,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 =NULL ; +struct plpks_var var = {0 };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; }
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH v6 8/9] keys/trusted_keys: enable PKWM wrapping key selection by label
Sashiko has reviewed this patch and found no issues.
Quoted 10 lines
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 <[email protected]>
Sashiko has reviewed this patch and found no issues.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
Srish Srinivasan
maintainerPATCH v6 9/9 pseries/plpks/wrapkey: expose PKWM wrapping key management to userspace via sysfs
In reply to Srish SrinivasanThe 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 label "default-wrapping-key" is reserved for the default wrapping key and cannot be managed through this interface
The wrapping keys themselves are confidential objects stored in PLPKS. Only their labels are exposed to userspace for identification and management purposes.
These user-created wrapping keys can be used in seal operations via the wrapping_key=<label> option.
--- .../ABI/testing/sysfs-firmware-plpks | 113 +++++ 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 | 14 + .../platforms/pseries/plpks-wrapkey-sysfs.c | 408 ++++++++++++++++++ arch/powerpc/platforms/pseries/plpks.c | 1 - 7 files changed, 560 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c
Documentation/ABI/testing/sysfs-firmware-plpks +113 -0
@@ -56,3 +56,116 @@ 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 <[email protected]> +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 label "default-wrapping-key" is reserved for the default + wrapping key and cannot be managed through this interface. + +What: /sys/firmware/plpks/wrapkey/create +Date: August 2026 +Contact: Srish Srinivasan <[email protected]> +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 <[email protected]> +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 <[email protected]> +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 <[email protected]> +Description: (WO) Unrevoke a revoked wrapping key identified by the specified + label. The default wrapping key, named "default-wrapping-key", + is not subject to revocation and therefore cannot be unrevoked + through this interface. + + 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 <[email protected]> +Description: (RO) List the labels of active, non-revoked wrapping keys. + + For example: + + cat /sys/firmware/plpks/wrapkey/list_active + +What: /sys/firmware/plpks/wrapkey/list_revoked +Date: August 2026 +Contact: Srish Srinivasan <[email protected]> +Description: (RO) List the labels of revoked wrapping keys. + + For example: + + cat /sys/firmware/plpks/wrapkey/list_revoked
arch/powerpc/include/asm/plpks.h +9 -0
@@ -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
arch/powerpc/platforms/pseries/Kconfig +15 -0
@@ -215,3 +215,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.
arch/powerpc/platforms/pseries/Makefile +1 -0
@@ -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
arch/powerpc/platforms/pseries/plpks-sysfs.c +14 -0
@@ -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)
@@ -89,6 +100,7 @@ static __init int plpks_sysfs_init(void)if (!plpks_config_kobj) {pr_err ("Failed to create plpks config kobj\n" );kobject_put (plpks_kobj); + plpks_kobj =NULL ;return -ENOMEM ; }
@@ -96,7 +108,9 @@ static __init int plpks_sysfs_init(void)if (rc) {pr_err ("Failed to create attribute group for plpks config\n" );kobject_put (plpks_config_kobj); + plpks_config_kobj =NULL ;kobject_put (plpks_kobj); + plpks_kobj =NULL ;return rc; }
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +408 -0
408 lines not on this page · raw message
arch/powerpc/platforms/pseries/plpks.c +0 -1
@@ -31,7 +31,6 @@#define PLPKS_OBJLABEL_BUF_SIZE \ roundup_pow_of_two(PLPKS_OBJLABEL_BUF_BASE_SIZE) -#define PLPKS_OBJLABEL_LEN_FIELD_SIZE 2#define PLPKS_OBJLABEL_PREFIX_LEN 8#define PLPKS_WRAP_INTERFACE_BIT 3
Signature · 1 line
2.52.0
[email protected]
AI reviewRe: [PATCH v6 9/9] pseries/plpks/wrapkey: expose PKWM wrapping key management to userspace via sysfs
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [Medium] pseries/plpks: label truncation and undocumented format in list_key_labels() - [Medium]…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] pseries/plpks: label truncation and undocumented format in list_key_labels()
- [Medium] pseries/plpks: TOCTOU race between delete_store() and unrevoke_store()
- [Low] pseries/plpks: duplicated sysfs store/show logic in plpks-wrapkey-sysfs.c --
commit 58203a02dbc210e21378df2545831a7ea49bbca4
Author: Srish Srinivasan <[email protected]>
pseries/plpks/wrapkey: expose PKWM wrapping key management to userspace via sysfs
This commit adds a sysfs interface under /sys/firmware/plpks/wrapkey to allow userspace to create, revoke, unrevoke, delete, and list PKWM wrapping keys.
Quoted 5 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +0
-0
[ ... ]
Quoted 23 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +23
-0+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 ); +
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c line 71
Quoted 10 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +10
-0+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);
[Severity: Medium]
Can list_key_labels() silently truncate wrapping key labels when reading /sys/firmware/plpks/wrapkey/list_active or list_revoked?
plpks_get_object_labels() can retrieve labels across multiple 4KB buffers via H_CONTINUE, and each label can be up to PLPKS_MAX_NAME_SIZE (239) bytes. However, a standard kobj_attribute show buffer is limited to PAGE_SIZE - 1 bytes. Once len reaches PAGE_SIZE - 1, sysfs_emit_at() returns 0 and any remaining wrapping key labels are silently omitted without any error or indication to userspace.
Also, list_key_labels() formats each label wrapped in angle brackets ("<%s>\n"), whereas Documentation/ABI/testing/sysfs-firmware-plpks does not mention the angle-bracket format for list_active and list_revoked. Should the output format and buffer limit be addressed or documented?
Quoted 58 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +58
-0+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 =NULL ; +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 =NULL ; +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) +{
[ ... ]
Quoted 44 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +44
-0+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) {
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c line 290
Quoted 10 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +10
-0+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; +}
[Severity: Low]
This isn't a bug, but create_store(), revoke_store(), unrevoke_store(), and delete_store() all duplicate the same CAP_SYS_ADMIN check, count validation, PLPKS_DEFAULT_WRAPKEY_LABEL check, is_wrapkey_label_alnum() validation, kstrndup() allocation, and struct plpks_var initialization (with unrevoke_store() returning -EINVAL instead of -EPERM for PLPKS_DEFAULT_WRAPKEY_LABEL).
Similarly, list_active_show() and list_revoked_show() duplicate the plpks_get_object_labels() call and cleanup, differing only in passing PLPKS_WRAPKEY_UNREVOKED vs PLPKS_WRAPKEY_REVOKED to list_key_labels().
Could the shared store validation/setup and show label retrieval logic be factored into common helpers?
Quoted 4 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +4
-0+ +static ssize_t delete_store (struct kobject *kobj,struct kobj_attribute *attr, +const char *buf,size_t count) +{
[ ... ]
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c line 333
Quoted 1 line
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +1
-0+ rc =plpks_del_wrapping_key (&var);
[Severity: Medium]
What prevents a TOCTOU race if delete_store() and unrevoke_store() are called concurrently on the same revoked wrapping key?
In arch/powerpc/platforms/pseries/plpks.c, plpks_del_wrapping_key() enforces that a key is revoked before deletion across two separate hypercalls without any lock:
plpks_del_wrapping_key()
rc = plpks_is_wrapping_key_revoked(var);
if (rc == 1) {
...
rc = plpks_remove_var(PLPKS_WRAPKEY_COMPONENT, var->os, vname);Because delete and unrevoke are separate sysfs attributes, kernfs only holds its per-open-file mutex separately for each attribute. If CPU 0 enters delete_store() -> plpks_del_wrapping_key() and sees plpks_is_wrapping_key_revoked() == 1, and CPU 1 concurrently runs unrevoke_store() -> plpks_unrevoke_wrapping_key() (H_PKS_UNREVOKE_OBJECT) before CPU 0 calls plpks_remove_var() (H_PKS_REMOVE_OBJECT), won't CPU 0 delete the now-active wrapping key?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
Srish Srinivasan
maintainerRe: [PATCH v6 9/9] pseries/plpks/wrapkey: expose PKWM wrapping key management to userspace via sysfs
Hi
Quoted 5 lines · On 11/5/26 8:32 PM, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] pseries/plpks: label truncation and undocumented format inlist_key_labels()
- [Medium] pseries/plpks: TOCTOU race betweendelete_store()andunrevoke_store()
- [Low] pseries/plpks: duplicated sysfs store/show logic inplpks-wrapkey-sysfs.c--
Yes, these are valid findings and I will fix these in my next version.
Thanks,
Srish
Quoted 220 lines
commit
58203a02dbc210e21378df2545831a7ea49bbca4
Author: Srish Srinivasan <[email protected]>pseries/plpks/wrapkey: expose PKWM wrapping key management to userspace via sysfs
This commit adds a sysfs interface under
/sys/firmware/plpks/wrapkeyto allow userspace to create, revoke, unrevoke, delete, and list PKWM wrapping keys.Quoted 5 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +0
-0[ ... ]
Quoted 23 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +23
-0+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 ); +arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c line 71
Quoted 10 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +10
-0+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);[Severity: Medium]
Canlist_key_labels()silently truncate wrapping key labels when reading/sys/firmware/plpks/wrapkey/list_activeorlist_revoked?
plpks_get_object_labels()can retrieve labels across multiple 4KB buffers viaH_CONTINUE, and each label can be up toPLPKS_MAX_NAME_SIZE(239) bytes. However, a standardkobj_attributeshow buffer is limited toPAGE_SIZE- 1 bytes. Once len reachesPAGE_SIZE- 1,sysfs_emit_at()returns 0 and any remaining wrapping key labels are silently omitted without any error or indication to userspace.Also,
list_key_labels()formats each label wrapped in angle brackets ("<%s>\n"), whereasDocumentation/ABI/testing/sysfs-firmware-plpksdoes not mention the angle-bracket format forlist_activeandlist_revoked. Should the output format and buffer limit be addressed or documented?Quoted 58 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +58
-0+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 =NULL ; +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 =NULL ; +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) +{[ ... ]
Quoted 44 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +44
-0+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) {arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c line 290
Quoted 10 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +10
-0+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; +}[Severity: Low]
This isn't a bug, butcreate_store(),revoke_store(),unrevoke_store(), anddelete_store()all duplicate the sameCAP_SYS_ADMINcheck, count validation,PLPKS_DEFAULT_WRAPKEY_LABELcheck,is_wrapkey_label_alnum()validation,kstrndup()allocation, and structplpks_varinitialization (withunrevoke_store()returning-EINVALinstead of-EPERMforPLPKS_DEFAULT_WRAPKEY_LABEL).Similarly,
list_active_show()andlist_revoked_show()duplicate theplpks_get_object_labels()call and cleanup, differing only in passingPLPKS_WRAPKEY_UNREVOKEDvsPLPKS_WRAPKEY_REVOKEDtolist_key_labels().Could the shared store validation/setup and show label retrieval logic be factored into common helpers?
Quoted 4 lines
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +4
-0+ +static ssize_t delete_store (struct kobject *kobj,struct kobj_attribute *attr, +const char *buf,size_t count) +{[ ... ]
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c line 333
Quoted 1 line
arch/powerpc/platforms/pseries/plpks-wrapkey-sysfs.c new file +1
-0+ rc =plpks_del_wrapping_key (&var);[Severity: Medium]
What prevents a TOCTOU race ifdelete_store()andunrevoke_store()are called concurrently on the same revoked wrapping key?In
arch/powerpc/platforms/pseries/plpks.c,plpks_del_wrapping_key()enforces that a key is revoked before deletion across two separate hypercalls without any lock:
plpks_del_wrapping_key()rc = plpks_is_wrapping_key_revoked(var); if (rc == 1) { ... rc = plpks_remove_var(PLPKS_WRAPKEY_COMPONENT, var->os, vname);Because delete and unrevoke are separate sysfs attributes, kernfs only holds its per-open-file mutex separately for each attribute. If CPU 0 enters
delete_store()->plpks_del_wrapping_key()and seesplpks_is_wrapping_key_revoked()== 1, and CPU 1 concurrently runsunrevoke_store()->plpks_unrevoke_wrapping_key()(H_PKS_UNREVOKE_OBJECT) before CPU 0 callsplpks_remove_var()(H_PKS_REMOVE_OBJECT), won't CPU 0 delete the now-active wrapping key?