All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/24] pSeries dynamic secure boot secvar interface + platform keyring loading
@ 2023-01-20  7:42 ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

This series exposes an interface to userspace for reading and writing
secure variables contained within the PowerVM LPAR Platform KeyStore
(PLPKS) for the purpose of configuring dynamic secure boot, and adds
the glue required to load keys from the PLPKS into the platform keyring.

This series builds on past work by Nayna Jain[0] in exposing PLPKS
variables to userspace.  Rather than being a generic interface for
interacting with the keystore, however, we use the existing powerpc
secvar infrastructure to only expose objects in the keystore used
for dynamic secure boot.  This has the benefit of leveraging an
existing interface and making the implementation relatively minimal.

This series integrates a previous series to fix some bugs in PLPKS
and implement support for signed updates[1], and a cleanup patch from
Michael Ellerman[2].

There are a few relevant details to note about the implementation:

 * New additions to the secvar API: format(), max_size(), config_attrs,
   var_names

 * New optional sysfs directory "config/" for arbitrary ASCII variables

 * Some OPAL-specific code has been relocated from secvar-sysfs.c to
   powernv platform code.  Would appreciate any powernv testing!

 * Variable names are fixed and only those used for secure boot are
   exposed.  This is not a generic PLPKS interface, but also doesn't
   preclude one being added in future.

With this series, both powernv and pseries platforms support dynamic
secure boot through the same interface.

[0]: https://lore.kernel.org/linuxppc-dev/20221106210744.603240-1-nayna@linux.ibm.com/
[1]: https://lore.kernel.org/linuxppc-dev/20221220071626.1426786-1-ajd@linux.ibm.com/
[2]: https://lore.kernel.org/linuxppc-dev/20230112023819.1692452-1-mpe@ellerman.id.au/

v1: https://lore.kernel.org/linuxppc-dev/20221228072943.429266-1-ruscur@russell.cc/
v2: https://lore.kernel.org/linuxppc-dev/20221230042014.154483-1-ruscur@russell.cc/
v3: https://lore.kernel.org/linuxppc-dev/20230118061049.1006141-1-ajd@linux.ibm.com/

=================

Changes in v4:

    Fix the build when CONFIG_PSERIES_PLPKS=n (snowpatch)

    Shuffled fixes to the front the series (npiggin)

    Pass buffer size in secvar_operations->format() (stefanb, npiggin)

    Return an error when set_secvar_ops() fails (npiggin)

    Add some extra null checks (stefanb, gjoyce)

    Add commit message comment elaborating on PAGE_SIZE issues (joel)

    Fix error handling in the kexec code (ruscur)

    Fix hvcall.h MAX_HCALL_OPCODE rebasing issue (npiggin)

Changes in v3:

    Integrate Andrew's PLPKS bugfixes and enhancements series and Michael
    Ellerman's u64 cleanup patch into this series (and update the other
    patches to use u64)

    New patches to load keys from the PLPKS into the kernel's platform
    keyring (ruscur)

    New patches to pass PLPKS password to new kernels when kexecing
    (ruscur)

    Improve handling of format strings (ruscur)

    Clean up secvar error messages (ajd)

    Merge config attributes into secvar_operations (mpe)

    Add a new static variable names API rather than (ab)using get_next()
    (ajd/mpe)

    Warning message when PAGE_SIZE is smaller than the max object size
    (ajd)

    Move plpks.h to the include directory, and move a bunch of constants
    in there with a consistent naming scheme

    Refresh PLPKS config values whenever plpks_get_usedspace() is called
    (ajd)

    Extra validation on PLPKS config values (ruscur)

    Return maxobjlabelsize to userspace as is without subtracting overhead (ruscur)

    Fix error code handling in plpks_confirm_object_flushed() (ruscur)

    Pass plpks_var struct to plpks_signed_update_var() by reference (mpe)

    Make the data buffer in plpks_read_var() caller-allocated to reduce
    number of allocations/copies (mpe)

    Rework the Kconfig options so that PSERIES_PLPKS is a hidden option,
    turned on by enabling PPC_SECURE_BOOT, and the PLPKS secvar code is
    activated by PPC_SECVAR_SYSFS to match powernv (ajd)

    Use machine_arch_initcall() rather than device_initcall() so we don't
    break powernv (mpe)

    Improve ABI documentation (mpe)

    Return -EIO on most read errors (mpe)

    Add "grubdbx" variable (Sudhakar)

    Use utf8s_to_utf16s() rather than our own "UCS-2" conversion code (mpe)

    Fix SB_VERSION data length (ruscur)

    Stop prepending policy data on read (ruscur)

    Don't print errors to the kernel log when reading non-existent
    variables (Sudhakar)

    Miscellaneous code style, checkpatch cleanups

Changes in v2:

    Remove unnecessary config vars from sysfs and document the others,
    thanks to review from Greg.  If we end up needing to expose more, we
    can add them later and update the docs.

    Use sysfs_emit() instead of sprintf() for all sysfs strings

    Change the size of the sysfs binary attributes to include the 8-byte
    flags header, preventing truncation of large writes.

Andrew Donnellan (8):
  powerpc/pseries: Fix handling of PLPKS object flushing timeout
  powerpc/pseries: Fix alignment of PLPKS structures and buffers
  powerpc/secvar: Clean up init error messages
  powerpc/secvar: Allow backend to populate static list of variable
    names
  powerpc/secvar: Warn when PAGE_SIZE is smaller than max object size
  powerpc/secvar: Don't print error on ENOENT when reading variables
  powerpc/pseries: Make caller pass buffer to plpks_read_var()
  powerpc/pseries: Turn PSERIES_PLPKS into a hidden option

Michael Ellerman (1):
  powerpc/secvar: Use u64 in secvar_operations

Nayna Jain (2):
  powerpc/pseries: Expose PLPKS config values, support additional fields
  powerpc/pseries: Implement signed update for PLPKS objects

Russell Currey (13):
  powerpc/secvar: Warn and error if multiple secvar ops are set
  powerpc/secvar: Use sysfs_emit() instead of sprintf()
  powerpc/secvar: Handle format string in the consumer
  powerpc/secvar: Handle max object size in the consumer
  powerpc/secvar: Extend sysfs to include config vars
  powerpc/pseries: Move plpks.h to include directory
  powerpc/pseries: Move PLPKS constants to header file
  powerpc/pseries: Log hcall return codes for PLPKS debug
  powerpc/pseries: Add helpers to get PLPKS password
  powerpc/pseries: Pass PLPKS password on kexec
  powerpc/pseries: Implement secvars for dynamic secure boot
  integrity/powerpc: Improve error handling & reporting when loading
    certs
  integrity/powerpc: Support loading keys from pseries secvar

 Documentation/ABI/testing/sysfs-secvar        |  75 +++-
 arch/powerpc/Kconfig                          |   1 +
 arch/powerpc/include/asm/hvcall.h             |   1 +
 arch/powerpc/include/asm/plpks.h              | 187 ++++++++++
 arch/powerpc/include/asm/secvar.h             |  21 +-
 arch/powerpc/kernel/secvar-ops.c              |   8 +-
 arch/powerpc/kernel/secvar-sysfs.c            | 172 +++++----
 arch/powerpc/kexec/file_load_64.c             |  18 +
 arch/powerpc/platforms/powernv/opal-secvar.c  |  60 +++-
 arch/powerpc/platforms/pseries/Kconfig        |  11 +-
 arch/powerpc/platforms/pseries/Makefile       |   4 +-
 arch/powerpc/platforms/pseries/plpks-secvar.c | 215 +++++++++++
 arch/powerpc/platforms/pseries/plpks.c        | 338 ++++++++++++++----
 arch/powerpc/platforms/pseries/plpks.h        |  71 ----
 .../integrity/platform_certs/load_powerpc.c   |  47 ++-
 15 files changed, 978 insertions(+), 251 deletions(-)
 create mode 100644 arch/powerpc/include/asm/plpks.h
 create mode 100644 arch/powerpc/platforms/pseries/plpks-secvar.c
 delete mode 100644 arch/powerpc/platforms/pseries/plpks.h

-- 
2.39.0

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH v4 00/24] pSeries dynamic secure boot secvar interface + platform keyring loading
@ 2023-01-20  7:42 ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

This series exposes an interface to userspace for reading and writing
secure variables contained within the PowerVM LPAR Platform KeyStore
(PLPKS) for the purpose of configuring dynamic secure boot, and adds
the glue required to load keys from the PLPKS into the platform keyring.

This series builds on past work by Nayna Jain[0] in exposing PLPKS
variables to userspace.  Rather than being a generic interface for
interacting with the keystore, however, we use the existing powerpc
secvar infrastructure to only expose objects in the keystore used
for dynamic secure boot.  This has the benefit of leveraging an
existing interface and making the implementation relatively minimal.

This series integrates a previous series to fix some bugs in PLPKS
and implement support for signed updates[1], and a cleanup patch from
Michael Ellerman[2].

There are a few relevant details to note about the implementation:

 * New additions to the secvar API: format(), max_size(), config_attrs,
   var_names

 * New optional sysfs directory "config/" for arbitrary ASCII variables

 * Some OPAL-specific code has been relocated from secvar-sysfs.c to
   powernv platform code.  Would appreciate any powernv testing!

 * Variable names are fixed and only those used for secure boot are
   exposed.  This is not a generic PLPKS interface, but also doesn't
   preclude one being added in future.

With this series, both powernv and pseries platforms support dynamic
secure boot through the same interface.

[0]: https://lore.kernel.org/linuxppc-dev/20221106210744.603240-1-nayna@linux.ibm.com/
[1]: https://lore.kernel.org/linuxppc-dev/20221220071626.1426786-1-ajd@linux.ibm.com/
[2]: https://lore.kernel.org/linuxppc-dev/20230112023819.1692452-1-mpe@ellerman.id.au/

v1: https://lore.kernel.org/linuxppc-dev/20221228072943.429266-1-ruscur@russell.cc/
v2: https://lore.kernel.org/linuxppc-dev/20221230042014.154483-1-ruscur@russell.cc/
v3: https://lore.kernel.org/linuxppc-dev/20230118061049.1006141-1-ajd@linux.ibm.com/

=================

Changes in v4:

    Fix the build when CONFIG_PSERIES_PLPKS=n (snowpatch)

    Shuffled fixes to the front the series (npiggin)

    Pass buffer size in secvar_operations->format() (stefanb, npiggin)

    Return an error when set_secvar_ops() fails (npiggin)

    Add some extra null checks (stefanb, gjoyce)

    Add commit message comment elaborating on PAGE_SIZE issues (joel)

    Fix error handling in the kexec code (ruscur)

    Fix hvcall.h MAX_HCALL_OPCODE rebasing issue (npiggin)

Changes in v3:

    Integrate Andrew's PLPKS bugfixes and enhancements series and Michael
    Ellerman's u64 cleanup patch into this series (and update the other
    patches to use u64)

    New patches to load keys from the PLPKS into the kernel's platform
    keyring (ruscur)

    New patches to pass PLPKS password to new kernels when kexecing
    (ruscur)

    Improve handling of format strings (ruscur)

    Clean up secvar error messages (ajd)

    Merge config attributes into secvar_operations (mpe)

    Add a new static variable names API rather than (ab)using get_next()
    (ajd/mpe)

    Warning message when PAGE_SIZE is smaller than the max object size
    (ajd)

    Move plpks.h to the include directory, and move a bunch of constants
    in there with a consistent naming scheme

    Refresh PLPKS config values whenever plpks_get_usedspace() is called
    (ajd)

    Extra validation on PLPKS config values (ruscur)

    Return maxobjlabelsize to userspace as is without subtracting overhead (ruscur)

    Fix error code handling in plpks_confirm_object_flushed() (ruscur)

    Pass plpks_var struct to plpks_signed_update_var() by reference (mpe)

    Make the data buffer in plpks_read_var() caller-allocated to reduce
    number of allocations/copies (mpe)

    Rework the Kconfig options so that PSERIES_PLPKS is a hidden option,
    turned on by enabling PPC_SECURE_BOOT, and the PLPKS secvar code is
    activated by PPC_SECVAR_SYSFS to match powernv (ajd)

    Use machine_arch_initcall() rather than device_initcall() so we don't
    break powernv (mpe)

    Improve ABI documentation (mpe)

    Return -EIO on most read errors (mpe)

    Add "grubdbx" variable (Sudhakar)

    Use utf8s_to_utf16s() rather than our own "UCS-2" conversion code (mpe)

    Fix SB_VERSION data length (ruscur)

    Stop prepending policy data on read (ruscur)

    Don't print errors to the kernel log when reading non-existent
    variables (Sudhakar)

    Miscellaneous code style, checkpatch cleanups

Changes in v2:

    Remove unnecessary config vars from sysfs and document the others,
    thanks to review from Greg.  If we end up needing to expose more, we
    can add them later and update the docs.

    Use sysfs_emit() instead of sprintf() for all sysfs strings

    Change the size of the sysfs binary attributes to include the 8-byte
    flags header, preventing truncation of large writes.

Andrew Donnellan (8):
  powerpc/pseries: Fix handling of PLPKS object flushing timeout
  powerpc/pseries: Fix alignment of PLPKS structures and buffers
  powerpc/secvar: Clean up init error messages
  powerpc/secvar: Allow backend to populate static list of variable
    names
  powerpc/secvar: Warn when PAGE_SIZE is smaller than max object size
  powerpc/secvar: Don't print error on ENOENT when reading variables
  powerpc/pseries: Make caller pass buffer to plpks_read_var()
  powerpc/pseries: Turn PSERIES_PLPKS into a hidden option

Michael Ellerman (1):
  powerpc/secvar: Use u64 in secvar_operations

Nayna Jain (2):
  powerpc/pseries: Expose PLPKS config values, support additional fields
  powerpc/pseries: Implement signed update for PLPKS objects

Russell Currey (13):
  powerpc/secvar: Warn and error if multiple secvar ops are set
  powerpc/secvar: Use sysfs_emit() instead of sprintf()
  powerpc/secvar: Handle format string in the consumer
  powerpc/secvar: Handle max object size in the consumer
  powerpc/secvar: Extend sysfs to include config vars
  powerpc/pseries: Move plpks.h to include directory
  powerpc/pseries: Move PLPKS constants to header file
  powerpc/pseries: Log hcall return codes for PLPKS debug
  powerpc/pseries: Add helpers to get PLPKS password
  powerpc/pseries: Pass PLPKS password on kexec
  powerpc/pseries: Implement secvars for dynamic secure boot
  integrity/powerpc: Improve error handling & reporting when loading
    certs
  integrity/powerpc: Support loading keys from pseries secvar

 Documentation/ABI/testing/sysfs-secvar        |  75 +++-
 arch/powerpc/Kconfig                          |   1 +
 arch/powerpc/include/asm/hvcall.h             |   1 +
 arch/powerpc/include/asm/plpks.h              | 187 ++++++++++
 arch/powerpc/include/asm/secvar.h             |  21 +-
 arch/powerpc/kernel/secvar-ops.c              |   8 +-
 arch/powerpc/kernel/secvar-sysfs.c            | 172 +++++----
 arch/powerpc/kexec/file_load_64.c             |  18 +
 arch/powerpc/platforms/powernv/opal-secvar.c  |  60 +++-
 arch/powerpc/platforms/pseries/Kconfig        |  11 +-
 arch/powerpc/platforms/pseries/Makefile       |   4 +-
 arch/powerpc/platforms/pseries/plpks-secvar.c | 215 +++++++++++
 arch/powerpc/platforms/pseries/plpks.c        | 338 ++++++++++++++----
 arch/powerpc/platforms/pseries/plpks.h        |  71 ----
 .../integrity/platform_certs/load_powerpc.c   |  47 ++-
 15 files changed, 978 insertions(+), 251 deletions(-)
 create mode 100644 arch/powerpc/include/asm/plpks.h
 create mode 100644 arch/powerpc/platforms/pseries/plpks-secvar.c
 delete mode 100644 arch/powerpc/platforms/pseries/plpks.h

-- 
2.39.0

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH v4 01/24] powerpc/pseries: Fix handling of PLPKS object flushing timeout
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

plpks_confirm_object_flushed() uses the H_PKS_CONFIRM_OBJECT_FLUSHED hcall
to check whether changes to an object in the Platform KeyStore have been
flushed to non-volatile storage.

The hcall returns two output values, the return code and the flush status.
plpks_confirm_object_flushed() polls the hcall until either the flush
status has updated, the return code is an error, or a timeout has been
exceeded.

While we're still polling, the hcall is returning H_SUCCESS (0) as the
return code. In the timeout case, this means that upon exiting the polling
loop, rc is 0, and therefore 0 is returned to the user.

Handle the timeout case separately and return ETIMEDOUT if triggered.

Fixes: 2454a7af0f2a ("powerpc/pseries: define driver for Platform KeyStore")
Reported-by: Benjamin Gray <bgray@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Tested-by: Russell Currey <ruscur@russell.cc>
Reviewed-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: Merge plpks fixes and signed update series with secvar series

    Neaten how we return at the end of the function (ruscur)

v4: Move up in series (npiggin)
---
 arch/powerpc/platforms/pseries/plpks.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 4edd1585e245..9e85b6d85b0b 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -248,6 +248,7 @@ static int plpks_confirm_object_flushed(struct label *label,
 					struct plpks_auth *auth)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
+	bool timed_out = true;
 	u64 timeout = 0;
 	u8 status;
 	int rc;
@@ -259,22 +260,26 @@ static int plpks_confirm_object_flushed(struct label *label,
 
 		status = retbuf[0];
 		if (rc) {
+			timed_out = false;
 			if (rc == H_NOT_FOUND && status == 1)
 				rc = 0;
 			break;
 		}
 
-		if (!rc && status == 1)
+		if (!rc && status == 1) {
+			timed_out = false;
 			break;
+		}
 
 		usleep_range(PKS_FLUSH_SLEEP,
 			     PKS_FLUSH_SLEEP + PKS_FLUSH_SLEEP_RANGE);
 		timeout = timeout + PKS_FLUSH_SLEEP;
 	} while (timeout < PKS_FLUSH_MAX_TIMEOUT);
 
-	rc = pseries_status_to_err(rc);
+	if (timed_out)
+		return -ETIMEDOUT;
 
-	return rc;
+	return pseries_status_to_err(rc);
 }
 
 int plpks_write_var(struct plpks_var var)
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 01/24] powerpc/pseries: Fix handling of PLPKS object flushing timeout
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

plpks_confirm_object_flushed() uses the H_PKS_CONFIRM_OBJECT_FLUSHED hcall
to check whether changes to an object in the Platform KeyStore have been
flushed to non-volatile storage.

The hcall returns two output values, the return code and the flush status.
plpks_confirm_object_flushed() polls the hcall until either the flush
status has updated, the return code is an error, or a timeout has been
exceeded.

While we're still polling, the hcall is returning H_SUCCESS (0) as the
return code. In the timeout case, this means that upon exiting the polling
loop, rc is 0, and therefore 0 is returned to the user.

Handle the timeout case separately and return ETIMEDOUT if triggered.

Fixes: 2454a7af0f2a ("powerpc/pseries: define driver for Platform KeyStore")
Reported-by: Benjamin Gray <bgray@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Tested-by: Russell Currey <ruscur@russell.cc>
Reviewed-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: Merge plpks fixes and signed update series with secvar series

    Neaten how we return at the end of the function (ruscur)

v4: Move up in series (npiggin)
---
 arch/powerpc/platforms/pseries/plpks.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 4edd1585e245..9e85b6d85b0b 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -248,6 +248,7 @@ static int plpks_confirm_object_flushed(struct label *label,
 					struct plpks_auth *auth)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
+	bool timed_out = true;
 	u64 timeout = 0;
 	u8 status;
 	int rc;
@@ -259,22 +260,26 @@ static int plpks_confirm_object_flushed(struct label *label,
 
 		status = retbuf[0];
 		if (rc) {
+			timed_out = false;
 			if (rc == H_NOT_FOUND && status == 1)
 				rc = 0;
 			break;
 		}
 
-		if (!rc && status == 1)
+		if (!rc && status == 1) {
+			timed_out = false;
 			break;
+		}
 
 		usleep_range(PKS_FLUSH_SLEEP,
 			     PKS_FLUSH_SLEEP + PKS_FLUSH_SLEEP_RANGE);
 		timeout = timeout + PKS_FLUSH_SLEEP;
 	} while (timeout < PKS_FLUSH_MAX_TIMEOUT);
 
-	rc = pseries_status_to_err(rc);
+	if (timed_out)
+		return -ETIMEDOUT;
 
-	return rc;
+	return pseries_status_to_err(rc);
 }
 
 int plpks_write_var(struct plpks_var var)
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

A number of structures and buffers passed to PKS hcalls have alignment
requirements, which could on occasion cause problems:

- Authorisation structures must be 16-byte aligned and must not cross a
  page boundary

- Label structures must not cross page boundaries

- Password output buffers must not cross page boundaries

Round up the allocations of these structures/buffers to the next power of
2 to make sure this happens.

Reported-by: Benjamin Gray <bgray@linux.ibm.com>
Fixes: 2454a7af0f2a ("powerpc/pseries: define driver for Platform KeyStore")
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Reviewed-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: Merge plpks fixes and signed update series with secvar series

v4: Fix typo in commit message

    Move up in series (npiggin)
---
 arch/powerpc/platforms/pseries/plpks.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 9e85b6d85b0b..a01cf2ff140a 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -126,7 +126,8 @@ static int plpks_gen_password(void)
 	u8 *password, consumer = PKS_OS_OWNER;
 	int rc;
 
-	password = kzalloc(maxpwsize, GFP_KERNEL);
+	// The password must not cross a page boundary, so we align to the next power of 2
+	password = kzalloc(roundup_pow_of_two(maxpwsize), GFP_KERNEL);
 	if (!password)
 		return -ENOMEM;
 
@@ -162,7 +163,9 @@ static struct plpks_auth *construct_auth(u8 consumer)
 	if (consumer > PKS_OS_OWNER)
 		return ERR_PTR(-EINVAL);
 
-	auth = kzalloc(struct_size(auth, password, maxpwsize), GFP_KERNEL);
+	// The auth structure must not cross a page boundary and must be
+	// 16 byte aligned. We align to the next largest power of 2
+	auth = kzalloc(roundup_pow_of_two(struct_size(auth, password, maxpwsize)), GFP_KERNEL);
 	if (!auth)
 		return ERR_PTR(-ENOMEM);
 
@@ -196,7 +199,8 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 	if (component && slen > sizeof(label->attr.prefix))
 		return ERR_PTR(-EINVAL);
 
-	label = kzalloc(sizeof(*label), GFP_KERNEL);
+	// The label structure must not cross a page boundary, so we align to the next power of 2
+	label = kzalloc(roundup_pow_of_two(sizeof(*label)), GFP_KERNEL);
 	if (!label)
 		return ERR_PTR(-ENOMEM);
 
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

A number of structures and buffers passed to PKS hcalls have alignment
requirements, which could on occasion cause problems:

- Authorisation structures must be 16-byte aligned and must not cross a
  page boundary

- Label structures must not cross page boundaries

- Password output buffers must not cross page boundaries

Round up the allocations of these structures/buffers to the next power of
2 to make sure this happens.

Reported-by: Benjamin Gray <bgray@linux.ibm.com>
Fixes: 2454a7af0f2a ("powerpc/pseries: define driver for Platform KeyStore")
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Reviewed-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: Merge plpks fixes and signed update series with secvar series

v4: Fix typo in commit message

    Move up in series (npiggin)
---
 arch/powerpc/platforms/pseries/plpks.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 9e85b6d85b0b..a01cf2ff140a 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -126,7 +126,8 @@ static int plpks_gen_password(void)
 	u8 *password, consumer = PKS_OS_OWNER;
 	int rc;
 
-	password = kzalloc(maxpwsize, GFP_KERNEL);
+	// The password must not cross a page boundary, so we align to the next power of 2
+	password = kzalloc(roundup_pow_of_two(maxpwsize), GFP_KERNEL);
 	if (!password)
 		return -ENOMEM;
 
@@ -162,7 +163,9 @@ static struct plpks_auth *construct_auth(u8 consumer)
 	if (consumer > PKS_OS_OWNER)
 		return ERR_PTR(-EINVAL);
 
-	auth = kzalloc(struct_size(auth, password, maxpwsize), GFP_KERNEL);
+	// The auth structure must not cross a page boundary and must be
+	// 16 byte aligned. We align to the next largest power of 2
+	auth = kzalloc(roundup_pow_of_two(struct_size(auth, password, maxpwsize)), GFP_KERNEL);
 	if (!auth)
 		return ERR_PTR(-ENOMEM);
 
@@ -196,7 +199,8 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 	if (component && slen > sizeof(label->attr.prefix))
 		return ERR_PTR(-EINVAL);
 
-	label = kzalloc(sizeof(*label), GFP_KERNEL);
+	// The label structure must not cross a page boundary, so we align to the next power of 2
+	label = kzalloc(roundup_pow_of_two(sizeof(*label)), GFP_KERNEL);
 	if (!label)
 		return ERR_PTR(-ENOMEM);
 
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 03/24] powerpc/secvar: Use u64 in secvar_operations
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Michael Ellerman <mpe@ellerman.id.au>

There's no reason for secvar_operations to use uint64_t vs the more
common kernel type u64.

The types are compatible, but they require different printk format
strings which can lead to confusion.

Change all the secvar related routines to use u64.

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Reviewed-by: Russell Currey <ruscur@russell.cc>
Reviewed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: Include new patch
---
 arch/powerpc/include/asm/secvar.h                | 9 +++------
 arch/powerpc/kernel/secvar-sysfs.c               | 8 ++++----
 arch/powerpc/platforms/powernv/opal-secvar.c     | 9 +++------
 security/integrity/platform_certs/load_powerpc.c | 4 ++--
 4 files changed, 12 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 4cc35b58b986..07ba36f868a7 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -14,12 +14,9 @@
 extern const struct secvar_operations *secvar_ops;
 
 struct secvar_operations {
-	int (*get)(const char *key, uint64_t key_len, u8 *data,
-		   uint64_t *data_size);
-	int (*get_next)(const char *key, uint64_t *key_len,
-			uint64_t keybufsize);
-	int (*set)(const char *key, uint64_t key_len, u8 *data,
-		   uint64_t data_size);
+	int (*get)(const char *key, u64 key_len, u8 *data, u64 *data_size);
+	int (*get_next)(const char *key, u64 *key_len, u64 keybufsize);
+	int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 1ee4640a2641..001cdbcdb9d2 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -47,7 +47,7 @@ static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
 static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
 			 char *buf)
 {
-	uint64_t dsize;
+	u64 dsize;
 	int rc;
 
 	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
@@ -64,8 +64,8 @@ static ssize_t data_read(struct file *filep, struct kobject *kobj,
 			 struct bin_attribute *attr, char *buf, loff_t off,
 			 size_t count)
 {
-	uint64_t dsize;
 	char *data;
+	u64 dsize;
 	int rc;
 
 	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
@@ -166,9 +166,9 @@ static int update_kobj_size(void)
 
 static int secvar_sysfs_load(void)
 {
-	char *name;
-	uint64_t namesize = 0;
 	struct kobject *kobj;
+	u64 namesize = 0;
+	char *name;
 	int rc;
 
 	name = kzalloc(NAME_MAX_SIZE, GFP_KERNEL);
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
index 14133e120bdd..ef89861569e0 100644
--- a/arch/powerpc/platforms/powernv/opal-secvar.c
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -54,8 +54,7 @@ static int opal_status_to_err(int rc)
 	return err;
 }
 
-static int opal_get_variable(const char *key, uint64_t ksize,
-			     u8 *data, uint64_t *dsize)
+static int opal_get_variable(const char *key, u64 ksize, u8 *data, u64 *dsize)
 {
 	int rc;
 
@@ -71,8 +70,7 @@ static int opal_get_variable(const char *key, uint64_t ksize,
 	return opal_status_to_err(rc);
 }
 
-static int opal_get_next_variable(const char *key, uint64_t *keylen,
-				  uint64_t keybufsize)
+static int opal_get_next_variable(const char *key, u64 *keylen, u64 keybufsize)
 {
 	int rc;
 
@@ -88,8 +86,7 @@ static int opal_get_next_variable(const char *key, uint64_t *keylen,
 	return opal_status_to_err(rc);
 }
 
-static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
-			     uint64_t dsize)
+static int opal_set_variable(const char *key, u64 ksize, u8 *data, u64 dsize)
 {
 	int rc;
 
diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
index a2900cb85357..1e4f80a4e71c 100644
--- a/security/integrity/platform_certs/load_powerpc.c
+++ b/security/integrity/platform_certs/load_powerpc.c
@@ -18,7 +18,7 @@
 /*
  * Get a certificate list blob from the named secure variable.
  */
-static __init void *get_cert_list(u8 *key, unsigned long keylen, uint64_t *size)
+static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
 {
 	int rc;
 	void *db;
@@ -51,7 +51,7 @@ static __init void *get_cert_list(u8 *key, unsigned long keylen, uint64_t *size)
 static int __init load_powerpc_certs(void)
 {
 	void *db = NULL, *dbx = NULL;
-	uint64_t dbsize = 0, dbxsize = 0;
+	u64 dbsize = 0, dbxsize = 0;
 	int rc = 0;
 	struct device_node *node;
 
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 03/24] powerpc/secvar: Use u64 in secvar_operations
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Michael Ellerman <mpe@ellerman.id.au>

There's no reason for secvar_operations to use uint64_t vs the more
common kernel type u64.

The types are compatible, but they require different printk format
strings which can lead to confusion.

Change all the secvar related routines to use u64.

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Reviewed-by: Russell Currey <ruscur@russell.cc>
Reviewed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: Include new patch
---
 arch/powerpc/include/asm/secvar.h                | 9 +++------
 arch/powerpc/kernel/secvar-sysfs.c               | 8 ++++----
 arch/powerpc/platforms/powernv/opal-secvar.c     | 9 +++------
 security/integrity/platform_certs/load_powerpc.c | 4 ++--
 4 files changed, 12 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 4cc35b58b986..07ba36f868a7 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -14,12 +14,9 @@
 extern const struct secvar_operations *secvar_ops;
 
 struct secvar_operations {
-	int (*get)(const char *key, uint64_t key_len, u8 *data,
-		   uint64_t *data_size);
-	int (*get_next)(const char *key, uint64_t *key_len,
-			uint64_t keybufsize);
-	int (*set)(const char *key, uint64_t key_len, u8 *data,
-		   uint64_t data_size);
+	int (*get)(const char *key, u64 key_len, u8 *data, u64 *data_size);
+	int (*get_next)(const char *key, u64 *key_len, u64 keybufsize);
+	int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 1ee4640a2641..001cdbcdb9d2 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -47,7 +47,7 @@ static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
 static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
 			 char *buf)
 {
-	uint64_t dsize;
+	u64 dsize;
 	int rc;
 
 	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
@@ -64,8 +64,8 @@ static ssize_t data_read(struct file *filep, struct kobject *kobj,
 			 struct bin_attribute *attr, char *buf, loff_t off,
 			 size_t count)
 {
-	uint64_t dsize;
 	char *data;
+	u64 dsize;
 	int rc;
 
 	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
@@ -166,9 +166,9 @@ static int update_kobj_size(void)
 
 static int secvar_sysfs_load(void)
 {
-	char *name;
-	uint64_t namesize = 0;
 	struct kobject *kobj;
+	u64 namesize = 0;
+	char *name;
 	int rc;
 
 	name = kzalloc(NAME_MAX_SIZE, GFP_KERNEL);
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
index 14133e120bdd..ef89861569e0 100644
--- a/arch/powerpc/platforms/powernv/opal-secvar.c
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -54,8 +54,7 @@ static int opal_status_to_err(int rc)
 	return err;
 }
 
-static int opal_get_variable(const char *key, uint64_t ksize,
-			     u8 *data, uint64_t *dsize)
+static int opal_get_variable(const char *key, u64 ksize, u8 *data, u64 *dsize)
 {
 	int rc;
 
@@ -71,8 +70,7 @@ static int opal_get_variable(const char *key, uint64_t ksize,
 	return opal_status_to_err(rc);
 }
 
-static int opal_get_next_variable(const char *key, uint64_t *keylen,
-				  uint64_t keybufsize)
+static int opal_get_next_variable(const char *key, u64 *keylen, u64 keybufsize)
 {
 	int rc;
 
@@ -88,8 +86,7 @@ static int opal_get_next_variable(const char *key, uint64_t *keylen,
 	return opal_status_to_err(rc);
 }
 
-static int opal_set_variable(const char *key, uint64_t ksize, u8 *data,
-			     uint64_t dsize)
+static int opal_set_variable(const char *key, u64 ksize, u8 *data, u64 dsize)
 {
 	int rc;
 
diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
index a2900cb85357..1e4f80a4e71c 100644
--- a/security/integrity/platform_certs/load_powerpc.c
+++ b/security/integrity/platform_certs/load_powerpc.c
@@ -18,7 +18,7 @@
 /*
  * Get a certificate list blob from the named secure variable.
  */
-static __init void *get_cert_list(u8 *key, unsigned long keylen, uint64_t *size)
+static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
 {
 	int rc;
 	void *db;
@@ -51,7 +51,7 @@ static __init void *get_cert_list(u8 *key, unsigned long keylen, uint64_t *size)
 static int __init load_powerpc_certs(void)
 {
 	void *db = NULL, *dbx = NULL;
-	uint64_t dbsize = 0, dbxsize = 0;
+	u64 dbsize = 0, dbxsize = 0;
 	int rc = 0;
 	struct device_node *node;
 
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 04/24] powerpc/secvar: Warn and error if multiple secvar ops are set
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

The secvar code only supports one consumer at a time.

Multiple consumers aren't possible at this point in time, but we'd want
it to be obvious if it ever could happen.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v4: Return an error and don't actually try to set secvar_operations if the
    warning is triggered (npiggin)
---
 arch/powerpc/include/asm/secvar.h            | 4 ++--
 arch/powerpc/kernel/secvar-ops.c             | 8 ++++++--
 arch/powerpc/platforms/powernv/opal-secvar.c | 4 +---
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 07ba36f868a7..4ce3f12c5613 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -21,11 +21,11 @@ struct secvar_operations {
 
 #ifdef CONFIG_PPC_SECURE_BOOT
 
-extern void set_secvar_ops(const struct secvar_operations *ops);
+extern int set_secvar_ops(const struct secvar_operations *ops);
 
 #else
 
-static inline void set_secvar_ops(const struct secvar_operations *ops) { }
+static inline int set_secvar_ops(const struct secvar_operations *ops) { return 0; }
 
 #endif
 
diff --git a/arch/powerpc/kernel/secvar-ops.c b/arch/powerpc/kernel/secvar-ops.c
index 6a29777d6a2d..9c8dd4e7c270 100644
--- a/arch/powerpc/kernel/secvar-ops.c
+++ b/arch/powerpc/kernel/secvar-ops.c
@@ -8,10 +8,14 @@
 
 #include <linux/cache.h>
 #include <asm/secvar.h>
+#include <asm/bug.h>
 
-const struct secvar_operations *secvar_ops __ro_after_init;
+const struct secvar_operations *secvar_ops __ro_after_init = NULL;
 
-void set_secvar_ops(const struct secvar_operations *ops)
+int set_secvar_ops(const struct secvar_operations *ops)
 {
+	if (WARN_ON_ONCE(secvar_ops))
+		return -1;
 	secvar_ops = ops;
+	return 0;
 }
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
index ef89861569e0..4c0a3b030fe0 100644
--- a/arch/powerpc/platforms/powernv/opal-secvar.c
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -113,9 +113,7 @@ static int opal_secvar_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	set_secvar_ops(&opal_secvar_ops);
-
-	return 0;
+	return set_secvar_ops(&opal_secvar_ops);
 }
 
 static const struct of_device_id opal_secvar_match[] = {
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 04/24] powerpc/secvar: Warn and error if multiple secvar ops are set
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

The secvar code only supports one consumer at a time.

Multiple consumers aren't possible at this point in time, but we'd want
it to be obvious if it ever could happen.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v4: Return an error and don't actually try to set secvar_operations if the
    warning is triggered (npiggin)
---
 arch/powerpc/include/asm/secvar.h            | 4 ++--
 arch/powerpc/kernel/secvar-ops.c             | 8 ++++++--
 arch/powerpc/platforms/powernv/opal-secvar.c | 4 +---
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 07ba36f868a7..4ce3f12c5613 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -21,11 +21,11 @@ struct secvar_operations {
 
 #ifdef CONFIG_PPC_SECURE_BOOT
 
-extern void set_secvar_ops(const struct secvar_operations *ops);
+extern int set_secvar_ops(const struct secvar_operations *ops);
 
 #else
 
-static inline void set_secvar_ops(const struct secvar_operations *ops) { }
+static inline int set_secvar_ops(const struct secvar_operations *ops) { return 0; }
 
 #endif
 
diff --git a/arch/powerpc/kernel/secvar-ops.c b/arch/powerpc/kernel/secvar-ops.c
index 6a29777d6a2d..9c8dd4e7c270 100644
--- a/arch/powerpc/kernel/secvar-ops.c
+++ b/arch/powerpc/kernel/secvar-ops.c
@@ -8,10 +8,14 @@
 
 #include <linux/cache.h>
 #include <asm/secvar.h>
+#include <asm/bug.h>
 
-const struct secvar_operations *secvar_ops __ro_after_init;
+const struct secvar_operations *secvar_ops __ro_after_init = NULL;
 
-void set_secvar_ops(const struct secvar_operations *ops)
+int set_secvar_ops(const struct secvar_operations *ops)
 {
+	if (WARN_ON_ONCE(secvar_ops))
+		return -1;
 	secvar_ops = ops;
+	return 0;
 }
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
index ef89861569e0..4c0a3b030fe0 100644
--- a/arch/powerpc/platforms/powernv/opal-secvar.c
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -113,9 +113,7 @@ static int opal_secvar_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	set_secvar_ops(&opal_secvar_ops);
-
-	return 0;
+	return set_secvar_ops(&opal_secvar_ops);
 }
 
 static const struct of_device_id opal_secvar_match[] = {
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 05/24] powerpc/secvar: Use sysfs_emit() instead of sprintf()
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

The secvar format string and object size sysfs files are both ASCII
text, and should use sysfs_emit().  No functional change.

Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v2: New patch (gregkh)
---
 arch/powerpc/kernel/secvar-sysfs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 001cdbcdb9d2..462cacc0ca60 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -35,7 +35,7 @@ static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
 	if (rc)
 		goto out;
 
-	rc = sprintf(buf, "%s\n", format);
+	rc = sysfs_emit(buf, "%s\n", format);
 
 out:
 	of_node_put(node);
@@ -57,7 +57,7 @@ static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
 		return rc;
 	}
 
-	return sprintf(buf, "%llu\n", dsize);
+	return sysfs_emit(buf, "%llu\n", dsize);
 }
 
 static ssize_t data_read(struct file *filep, struct kobject *kobj,
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 05/24] powerpc/secvar: Use sysfs_emit() instead of sprintf()
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

The secvar format string and object size sysfs files are both ASCII
text, and should use sysfs_emit().  No functional change.

Suggested-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v2: New patch (gregkh)
---
 arch/powerpc/kernel/secvar-sysfs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 001cdbcdb9d2..462cacc0ca60 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -35,7 +35,7 @@ static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
 	if (rc)
 		goto out;
 
-	rc = sprintf(buf, "%s\n", format);
+	rc = sysfs_emit(buf, "%s\n", format);
 
 out:
 	of_node_put(node);
@@ -57,7 +57,7 @@ static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
 		return rc;
 	}
 
-	return sprintf(buf, "%llu\n", dsize);
+	return sysfs_emit(buf, "%llu\n", dsize);
 }
 
 static ssize_t data_read(struct file *filep, struct kobject *kobj,
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 06/24] powerpc/secvar: Handle format string in the consumer
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

The code that handles the format string in secvar-sysfs.c is entirely
OPAL specific, so create a new "format" op in secvar_operations to make
the secvar code more generic.  No functional change.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v2: Use sysfs_emit() instead of sprintf() (gregkh)

v3: Enforce format string size limit (ruscur)

v4: Pass the buffer size as an argument, not using a macro (stefanb,
    npiggin)

    Fix error reporting (npiggin)
---
 arch/powerpc/include/asm/secvar.h            |  1 +
 arch/powerpc/kernel/secvar-sysfs.c           | 27 +++++++-------------
 arch/powerpc/platforms/powernv/opal-secvar.c | 25 ++++++++++++++++++
 3 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 4ce3f12c5613..2d9816dff128 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -17,6 +17,7 @@ struct secvar_operations {
 	int (*get)(const char *key, u64 key_len, u8 *data, u64 *data_size);
 	int (*get_next)(const char *key, u64 *key_len, u64 keybufsize);
 	int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
+	ssize_t (*format)(char *buf, size_t bufsize);
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 462cacc0ca60..4beec935f5e7 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -21,26 +21,17 @@ static struct kset *secvar_kset;
 static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
 			   char *buf)
 {
-	ssize_t rc = 0;
-	struct device_node *node;
-	const char *format;
-
-	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
-	if (!of_device_is_available(node)) {
-		rc = -ENODEV;
-		goto out;
-	}
+	char tmp[32];
+	ssize_t len = secvar_ops->format(tmp, sizeof(tmp));
 
-	rc = of_property_read_string(node, "format", &format);
-	if (rc)
-		goto out;
+	if (len > 0)
+		return sysfs_emit(buf, "%s\n", tmp);
+	else if (len < 0)
+		pr_err("Error %zd reading format string\n", len);
+	else
+		pr_err("Got empty format string from backend\n");
 
-	rc = sysfs_emit(buf, "%s\n", format);
-
-out:
-	of_node_put(node);
-
-	return rc;
+	return -EIO;
 }
 
 
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
index 4c0a3b030fe0..e33bb703ecbc 100644
--- a/arch/powerpc/platforms/powernv/opal-secvar.c
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -98,10 +98,35 @@ static int opal_set_variable(const char *key, u64 ksize, u8 *data, u64 dsize)
 	return opal_status_to_err(rc);
 }
 
+static ssize_t opal_secvar_format(char *buf, size_t bufsize)
+{
+	ssize_t rc = 0;
+	struct device_node *node;
+	const char *format;
+
+	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
+	if (!of_device_is_available(node)) {
+		rc = -ENODEV;
+		goto out;
+	}
+
+	rc = of_property_read_string(node, "format", &format);
+	if (rc)
+		goto out;
+
+	rc = snprintf(buf, bufsize, "%s", format);
+
+out:
+	of_node_put(node);
+
+	return rc;
+}
+
 static const struct secvar_operations opal_secvar_ops = {
 	.get = opal_get_variable,
 	.get_next = opal_get_next_variable,
 	.set = opal_set_variable,
+	.format = opal_secvar_format,
 };
 
 static int opal_secvar_probe(struct platform_device *pdev)
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 06/24] powerpc/secvar: Handle format string in the consumer
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

The code that handles the format string in secvar-sysfs.c is entirely
OPAL specific, so create a new "format" op in secvar_operations to make
the secvar code more generic.  No functional change.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v2: Use sysfs_emit() instead of sprintf() (gregkh)

v3: Enforce format string size limit (ruscur)

v4: Pass the buffer size as an argument, not using a macro (stefanb,
    npiggin)

    Fix error reporting (npiggin)
---
 arch/powerpc/include/asm/secvar.h            |  1 +
 arch/powerpc/kernel/secvar-sysfs.c           | 27 +++++++-------------
 arch/powerpc/platforms/powernv/opal-secvar.c | 25 ++++++++++++++++++
 3 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 4ce3f12c5613..2d9816dff128 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -17,6 +17,7 @@ struct secvar_operations {
 	int (*get)(const char *key, u64 key_len, u8 *data, u64 *data_size);
 	int (*get_next)(const char *key, u64 *key_len, u64 keybufsize);
 	int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
+	ssize_t (*format)(char *buf, size_t bufsize);
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 462cacc0ca60..4beec935f5e7 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -21,26 +21,17 @@ static struct kset *secvar_kset;
 static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
 			   char *buf)
 {
-	ssize_t rc = 0;
-	struct device_node *node;
-	const char *format;
-
-	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
-	if (!of_device_is_available(node)) {
-		rc = -ENODEV;
-		goto out;
-	}
+	char tmp[32];
+	ssize_t len = secvar_ops->format(tmp, sizeof(tmp));
 
-	rc = of_property_read_string(node, "format", &format);
-	if (rc)
-		goto out;
+	if (len > 0)
+		return sysfs_emit(buf, "%s\n", tmp);
+	else if (len < 0)
+		pr_err("Error %zd reading format string\n", len);
+	else
+		pr_err("Got empty format string from backend\n");
 
-	rc = sysfs_emit(buf, "%s\n", format);
-
-out:
-	of_node_put(node);
-
-	return rc;
+	return -EIO;
 }
 
 
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
index 4c0a3b030fe0..e33bb703ecbc 100644
--- a/arch/powerpc/platforms/powernv/opal-secvar.c
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -98,10 +98,35 @@ static int opal_set_variable(const char *key, u64 ksize, u8 *data, u64 dsize)
 	return opal_status_to_err(rc);
 }
 
+static ssize_t opal_secvar_format(char *buf, size_t bufsize)
+{
+	ssize_t rc = 0;
+	struct device_node *node;
+	const char *format;
+
+	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
+	if (!of_device_is_available(node)) {
+		rc = -ENODEV;
+		goto out;
+	}
+
+	rc = of_property_read_string(node, "format", &format);
+	if (rc)
+		goto out;
+
+	rc = snprintf(buf, bufsize, "%s", format);
+
+out:
+	of_node_put(node);
+
+	return rc;
+}
+
 static const struct secvar_operations opal_secvar_ops = {
 	.get = opal_get_variable,
 	.get_next = opal_get_next_variable,
 	.set = opal_set_variable,
+	.format = opal_secvar_format,
 };
 
 static int opal_secvar_probe(struct platform_device *pdev)
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 07/24] powerpc/secvar: Handle max object size in the consumer
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

Currently the max object size is handled in the core secvar code with an
entirely OPAL-specific implementation, so create a new max_size() op and
move the existing implementation into the powernv platform.  Should be
no functional change.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: Change uint64_t type to u64 (mpe)

v4: Return immediately if node is NULL (gjoyce)
---
 arch/powerpc/include/asm/secvar.h            |  1 +
 arch/powerpc/kernel/secvar-sysfs.c           | 17 +++------------
 arch/powerpc/platforms/powernv/opal-secvar.c | 22 ++++++++++++++++++++
 3 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 2d9816dff128..b97ab793cc8a 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -18,6 +18,7 @@ struct secvar_operations {
 	int (*get_next)(const char *key, u64 *key_len, u64 keybufsize);
 	int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
 	ssize_t (*format)(char *buf, size_t bufsize);
+	int (*max_size)(u64 *max_size);
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 4beec935f5e7..d2f65a67845c 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -132,27 +132,16 @@ static struct kobj_type secvar_ktype = {
 static int update_kobj_size(void)
 {
 
-	struct device_node *node;
 	u64 varsize;
-	int rc = 0;
+	int rc = secvar_ops->max_size(&varsize);
 
-	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
-	if (!of_device_is_available(node)) {
-		rc = -ENODEV;
-		goto out;
-	}
-
-	rc = of_property_read_u64(node, "max-var-size", &varsize);
 	if (rc)
-		goto out;
+		return rc;
 
 	data_attr.size = varsize;
 	update_attr.size = varsize;
 
-out:
-	of_node_put(node);
-
-	return rc;
+	return 0;
 }
 
 static int secvar_sysfs_load(void)
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
index e33bb703ecbc..a8436bf35e2f 100644
--- a/arch/powerpc/platforms/powernv/opal-secvar.c
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -122,11 +122,33 @@ static ssize_t opal_secvar_format(char *buf, size_t bufsize)
 	return rc;
 }
 
+static int opal_secvar_max_size(u64 *max_size)
+{
+	int rc;
+	struct device_node *node;
+
+	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
+	if (!node)
+		return -ENODEV;
+
+	if (!of_device_is_available(node)) {
+		rc = -ENODEV;
+		goto out;
+	}
+
+	rc = of_property_read_u64(node, "max-var-size", max_size);
+
+out:
+	of_node_put(node);
+	return rc;
+}
+
 static const struct secvar_operations opal_secvar_ops = {
 	.get = opal_get_variable,
 	.get_next = opal_get_next_variable,
 	.set = opal_set_variable,
 	.format = opal_secvar_format,
+	.max_size = opal_secvar_max_size,
 };
 
 static int opal_secvar_probe(struct platform_device *pdev)
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 07/24] powerpc/secvar: Handle max object size in the consumer
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

Currently the max object size is handled in the core secvar code with an
entirely OPAL-specific implementation, so create a new max_size() op and
move the existing implementation into the powernv platform.  Should be
no functional change.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: Change uint64_t type to u64 (mpe)

v4: Return immediately if node is NULL (gjoyce)
---
 arch/powerpc/include/asm/secvar.h            |  1 +
 arch/powerpc/kernel/secvar-sysfs.c           | 17 +++------------
 arch/powerpc/platforms/powernv/opal-secvar.c | 22 ++++++++++++++++++++
 3 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 2d9816dff128..b97ab793cc8a 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -18,6 +18,7 @@ struct secvar_operations {
 	int (*get_next)(const char *key, u64 *key_len, u64 keybufsize);
 	int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
 	ssize_t (*format)(char *buf, size_t bufsize);
+	int (*max_size)(u64 *max_size);
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 4beec935f5e7..d2f65a67845c 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -132,27 +132,16 @@ static struct kobj_type secvar_ktype = {
 static int update_kobj_size(void)
 {
 
-	struct device_node *node;
 	u64 varsize;
-	int rc = 0;
+	int rc = secvar_ops->max_size(&varsize);
 
-	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
-	if (!of_device_is_available(node)) {
-		rc = -ENODEV;
-		goto out;
-	}
-
-	rc = of_property_read_u64(node, "max-var-size", &varsize);
 	if (rc)
-		goto out;
+		return rc;
 
 	data_attr.size = varsize;
 	update_attr.size = varsize;
 
-out:
-	of_node_put(node);
-
-	return rc;
+	return 0;
 }
 
 static int secvar_sysfs_load(void)
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
index e33bb703ecbc..a8436bf35e2f 100644
--- a/arch/powerpc/platforms/powernv/opal-secvar.c
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -122,11 +122,33 @@ static ssize_t opal_secvar_format(char *buf, size_t bufsize)
 	return rc;
 }
 
+static int opal_secvar_max_size(u64 *max_size)
+{
+	int rc;
+	struct device_node *node;
+
+	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
+	if (!node)
+		return -ENODEV;
+
+	if (!of_device_is_available(node)) {
+		rc = -ENODEV;
+		goto out;
+	}
+
+	rc = of_property_read_u64(node, "max-var-size", max_size);
+
+out:
+	of_node_put(node);
+	return rc;
+}
+
 static const struct secvar_operations opal_secvar_ops = {
 	.get = opal_get_variable,
 	.get_next = opal_get_next_variable,
 	.set = opal_set_variable,
 	.format = opal_secvar_format,
+	.max_size = opal_secvar_max_size,
 };
 
 static int opal_secvar_probe(struct platform_device *pdev)
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 08/24] powerpc/secvar: Clean up init error messages
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

Remove unnecessary prefixes from error messages in secvar_sysfs_init()
(the file defines pr_fmt, so putting "secvar:" in every message is
unnecessary). Make capitalisation and punctuation more consistent.

Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch (ajd)
---
 arch/powerpc/kernel/secvar-sysfs.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index d2f65a67845c..53ac01e0eb0b 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -194,13 +194,13 @@ static int secvar_sysfs_init(void)
 	int rc;
 
 	if (!secvar_ops) {
-		pr_warn("secvar: failed to retrieve secvar operations.\n");
+		pr_warn("Failed to retrieve secvar operations\n");
 		return -ENODEV;
 	}
 
 	secvar_kobj = kobject_create_and_add("secvar", firmware_kobj);
 	if (!secvar_kobj) {
-		pr_err("secvar: Failed to create firmware kobj\n");
+		pr_err("Failed to create firmware kobj\n");
 		return -ENOMEM;
 	}
 
@@ -212,7 +212,7 @@ static int secvar_sysfs_init(void)
 
 	secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
 	if (!secvar_kset) {
-		pr_err("secvar: sysfs kobject registration failed.\n");
+		pr_err("sysfs kobject registration failed\n");
 		kobject_put(secvar_kobj);
 		return -ENOMEM;
 	}
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 08/24] powerpc/secvar: Clean up init error messages
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

Remove unnecessary prefixes from error messages in secvar_sysfs_init()
(the file defines pr_fmt, so putting "secvar:" in every message is
unnecessary). Make capitalisation and punctuation more consistent.

Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch (ajd)
---
 arch/powerpc/kernel/secvar-sysfs.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index d2f65a67845c..53ac01e0eb0b 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -194,13 +194,13 @@ static int secvar_sysfs_init(void)
 	int rc;
 
 	if (!secvar_ops) {
-		pr_warn("secvar: failed to retrieve secvar operations.\n");
+		pr_warn("Failed to retrieve secvar operations\n");
 		return -ENODEV;
 	}
 
 	secvar_kobj = kobject_create_and_add("secvar", firmware_kobj);
 	if (!secvar_kobj) {
-		pr_err("secvar: Failed to create firmware kobj\n");
+		pr_err("Failed to create firmware kobj\n");
 		return -ENOMEM;
 	}
 
@@ -212,7 +212,7 @@ static int secvar_sysfs_init(void)
 
 	secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
 	if (!secvar_kset) {
-		pr_err("secvar: sysfs kobject registration failed.\n");
+		pr_err("sysfs kobject registration failed\n");
 		kobject_put(secvar_kobj);
 		return -ENOMEM;
 	}
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 09/24] powerpc/secvar: Extend sysfs to include config vars
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

The forthcoming pseries consumer of the secvar API wants to expose a
number of config variables.  Allowing secvar implementations to provide
their own sysfs attributes makes it easy for consumers to expose what
they need to.

This is not being used by the OPAL secvar implementation at present, and
the config directory will not be created if no attributes are set.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: Remove unnecessary "secvar:" prefix from error messages (ajd)

    Merge config attributes into secvar_operations (mpe)
---
 arch/powerpc/include/asm/secvar.h  |  2 ++
 arch/powerpc/kernel/secvar-sysfs.c | 33 +++++++++++++++++++++++++-----
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index b97ab793cc8a..5ed141c711b0 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -10,6 +10,7 @@
 
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/sysfs.h>
 
 extern const struct secvar_operations *secvar_ops;
 
@@ -19,6 +20,7 @@ struct secvar_operations {
 	int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
 	ssize_t (*format)(char *buf, size_t bufsize);
 	int (*max_size)(u64 *max_size);
+	const struct attribute **config_attrs;
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 53ac01e0eb0b..d7936d8c7478 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -144,6 +144,19 @@ static int update_kobj_size(void)
 	return 0;
 }
 
+static int secvar_sysfs_config(struct kobject *kobj)
+{
+	struct attribute_group config_group = {
+		.name = "config",
+		.attrs = (struct attribute **)secvar_ops->config_attrs,
+	};
+
+	if (secvar_ops->config_attrs)
+		return sysfs_create_group(kobj, &config_group);
+
+	return 0;
+}
+
 static int secvar_sysfs_load(void)
 {
 	struct kobject *kobj;
@@ -206,26 +219,36 @@ static int secvar_sysfs_init(void)
 
 	rc = sysfs_create_file(secvar_kobj, &format_attr.attr);
 	if (rc) {
-		kobject_put(secvar_kobj);
-		return -ENOMEM;
+		pr_err("Failed to create format object\n");
+		rc = -ENOMEM;
+		goto err;
 	}
 
 	secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
 	if (!secvar_kset) {
 		pr_err("sysfs kobject registration failed\n");
-		kobject_put(secvar_kobj);
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto err;
 	}
 
 	rc = update_kobj_size();
 	if (rc) {
 		pr_err("Cannot read the size of the attribute\n");
-		return rc;
+		goto err;
+	}
+
+	rc = secvar_sysfs_config(secvar_kobj);
+	if (rc) {
+		pr_err("Failed to create config directory\n");
+		goto err;
 	}
 
 	secvar_sysfs_load();
 
 	return 0;
+err:
+	kobject_put(secvar_kobj);
+	return rc;
 }
 
 late_initcall(secvar_sysfs_init);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 09/24] powerpc/secvar: Extend sysfs to include config vars
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

The forthcoming pseries consumer of the secvar API wants to expose a
number of config variables.  Allowing secvar implementations to provide
their own sysfs attributes makes it easy for consumers to expose what
they need to.

This is not being used by the OPAL secvar implementation at present, and
the config directory will not be created if no attributes are set.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: Remove unnecessary "secvar:" prefix from error messages (ajd)

    Merge config attributes into secvar_operations (mpe)
---
 arch/powerpc/include/asm/secvar.h  |  2 ++
 arch/powerpc/kernel/secvar-sysfs.c | 33 +++++++++++++++++++++++++-----
 2 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index b97ab793cc8a..5ed141c711b0 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -10,6 +10,7 @@
 
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/sysfs.h>
 
 extern const struct secvar_operations *secvar_ops;
 
@@ -19,6 +20,7 @@ struct secvar_operations {
 	int (*set)(const char *key, u64 key_len, u8 *data, u64 data_size);
 	ssize_t (*format)(char *buf, size_t bufsize);
 	int (*max_size)(u64 *max_size);
+	const struct attribute **config_attrs;
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 53ac01e0eb0b..d7936d8c7478 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -144,6 +144,19 @@ static int update_kobj_size(void)
 	return 0;
 }
 
+static int secvar_sysfs_config(struct kobject *kobj)
+{
+	struct attribute_group config_group = {
+		.name = "config",
+		.attrs = (struct attribute **)secvar_ops->config_attrs,
+	};
+
+	if (secvar_ops->config_attrs)
+		return sysfs_create_group(kobj, &config_group);
+
+	return 0;
+}
+
 static int secvar_sysfs_load(void)
 {
 	struct kobject *kobj;
@@ -206,26 +219,36 @@ static int secvar_sysfs_init(void)
 
 	rc = sysfs_create_file(secvar_kobj, &format_attr.attr);
 	if (rc) {
-		kobject_put(secvar_kobj);
-		return -ENOMEM;
+		pr_err("Failed to create format object\n");
+		rc = -ENOMEM;
+		goto err;
 	}
 
 	secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
 	if (!secvar_kset) {
 		pr_err("sysfs kobject registration failed\n");
-		kobject_put(secvar_kobj);
-		return -ENOMEM;
+		rc = -ENOMEM;
+		goto err;
 	}
 
 	rc = update_kobj_size();
 	if (rc) {
 		pr_err("Cannot read the size of the attribute\n");
-		return rc;
+		goto err;
+	}
+
+	rc = secvar_sysfs_config(secvar_kobj);
+	if (rc) {
+		pr_err("Failed to create config directory\n");
+		goto err;
 	}
 
 	secvar_sysfs_load();
 
 	return 0;
+err:
+	kobject_put(secvar_kobj);
+	return rc;
 }
 
 late_initcall(secvar_sysfs_init);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 10/24] powerpc/secvar: Allow backend to populate static list of variable names
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

Currently, the list of variables is populated by calling
secvar_ops->get_next() repeatedly, which is explicitly modelled on the
OPAL API (including the keylen parameter).

For the upcoming PLPKS backend, we have a static list of variable names.
It is messy to fit that into get_next(), so instead, let the backend put
a NULL-terminated array of variable names into secvar_ops->var_names,
which will be used if get_next() is undefined.

Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch (ajd/mpe)
---
 arch/powerpc/include/asm/secvar.h  |  4 ++
 arch/powerpc/kernel/secvar-sysfs.c | 67 ++++++++++++++++++++----------
 2 files changed, 50 insertions(+), 21 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 5ed141c711b0..467f83c24084 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -21,6 +21,10 @@ struct secvar_operations {
 	ssize_t (*format)(char *buf, size_t bufsize);
 	int (*max_size)(u64 *max_size);
 	const struct attribute **config_attrs;
+
+	// NULL-terminated array of fixed variable names
+	// Only used if get_next() isn't provided
+	const char * const *var_names;
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index d7936d8c7478..e1d4c70dd327 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -157,9 +157,31 @@ static int secvar_sysfs_config(struct kobject *kobj)
 	return 0;
 }
 
-static int secvar_sysfs_load(void)
+static int add_var(const char *name)
 {
 	struct kobject *kobj;
+	int rc;
+
+	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+	if (!kobj)
+		return -ENOMEM;
+
+	kobject_init(kobj, &secvar_ktype);
+
+	rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
+	if (rc) {
+		pr_warn("kobject_add error %d for attribute: %s\n", rc,
+			name);
+		kobject_put(kobj);
+		return rc;
+	}
+
+	kobject_uevent(kobj, KOBJ_ADD);
+	return 0;
+}
+
+static int secvar_sysfs_load(void)
+{
 	u64 namesize = 0;
 	char *name;
 	int rc;
@@ -177,31 +199,26 @@ static int secvar_sysfs_load(void)
 			break;
 		}
 
-		kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
-		if (!kobj) {
-			rc = -ENOMEM;
-			break;
-		}
-
-		kobject_init(kobj, &secvar_ktype);
-
-		rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
-		if (rc) {
-			pr_warn("kobject_add error %d for attribute: %s\n", rc,
-				name);
-			kobject_put(kobj);
-			kobj = NULL;
-		}
-
-		if (kobj)
-			kobject_uevent(kobj, KOBJ_ADD);
-
+		rc = add_var(name);
 	} while (!rc);
 
 	kfree(name);
 	return rc;
 }
 
+static int secvar_sysfs_load_static(void)
+{
+	const char * const *name_ptr = secvar_ops->var_names;
+	int rc;
+	while (*name_ptr) {
+		rc = add_var(*name_ptr);
+		if (rc)
+			return rc;
+		name_ptr++;
+	}
+	return 0;
+}
+
 static int secvar_sysfs_init(void)
 {
 	int rc;
@@ -243,7 +260,15 @@ static int secvar_sysfs_init(void)
 		goto err;
 	}
 
-	secvar_sysfs_load();
+	if (secvar_ops->get_next)
+		rc = secvar_sysfs_load();
+	else
+		rc = secvar_sysfs_load_static();
+
+	if (rc) {
+		pr_err("Failed to create variable attributes\n");
+		goto err;
+	}
 
 	return 0;
 err:
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 10/24] powerpc/secvar: Allow backend to populate static list of variable names
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

Currently, the list of variables is populated by calling
secvar_ops->get_next() repeatedly, which is explicitly modelled on the
OPAL API (including the keylen parameter).

For the upcoming PLPKS backend, we have a static list of variable names.
It is messy to fit that into get_next(), so instead, let the backend put
a NULL-terminated array of variable names into secvar_ops->var_names,
which will be used if get_next() is undefined.

Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch (ajd/mpe)
---
 arch/powerpc/include/asm/secvar.h  |  4 ++
 arch/powerpc/kernel/secvar-sysfs.c | 67 ++++++++++++++++++++----------
 2 files changed, 50 insertions(+), 21 deletions(-)

diff --git a/arch/powerpc/include/asm/secvar.h b/arch/powerpc/include/asm/secvar.h
index 5ed141c711b0..467f83c24084 100644
--- a/arch/powerpc/include/asm/secvar.h
+++ b/arch/powerpc/include/asm/secvar.h
@@ -21,6 +21,10 @@ struct secvar_operations {
 	ssize_t (*format)(char *buf, size_t bufsize);
 	int (*max_size)(u64 *max_size);
 	const struct attribute **config_attrs;
+
+	// NULL-terminated array of fixed variable names
+	// Only used if get_next() isn't provided
+	const char * const *var_names;
 };
 
 #ifdef CONFIG_PPC_SECURE_BOOT
diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index d7936d8c7478..e1d4c70dd327 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -157,9 +157,31 @@ static int secvar_sysfs_config(struct kobject *kobj)
 	return 0;
 }
 
-static int secvar_sysfs_load(void)
+static int add_var(const char *name)
 {
 	struct kobject *kobj;
+	int rc;
+
+	kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+	if (!kobj)
+		return -ENOMEM;
+
+	kobject_init(kobj, &secvar_ktype);
+
+	rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
+	if (rc) {
+		pr_warn("kobject_add error %d for attribute: %s\n", rc,
+			name);
+		kobject_put(kobj);
+		return rc;
+	}
+
+	kobject_uevent(kobj, KOBJ_ADD);
+	return 0;
+}
+
+static int secvar_sysfs_load(void)
+{
 	u64 namesize = 0;
 	char *name;
 	int rc;
@@ -177,31 +199,26 @@ static int secvar_sysfs_load(void)
 			break;
 		}
 
-		kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
-		if (!kobj) {
-			rc = -ENOMEM;
-			break;
-		}
-
-		kobject_init(kobj, &secvar_ktype);
-
-		rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
-		if (rc) {
-			pr_warn("kobject_add error %d for attribute: %s\n", rc,
-				name);
-			kobject_put(kobj);
-			kobj = NULL;
-		}
-
-		if (kobj)
-			kobject_uevent(kobj, KOBJ_ADD);
-
+		rc = add_var(name);
 	} while (!rc);
 
 	kfree(name);
 	return rc;
 }
 
+static int secvar_sysfs_load_static(void)
+{
+	const char * const *name_ptr = secvar_ops->var_names;
+	int rc;
+	while (*name_ptr) {
+		rc = add_var(*name_ptr);
+		if (rc)
+			return rc;
+		name_ptr++;
+	}
+	return 0;
+}
+
 static int secvar_sysfs_init(void)
 {
 	int rc;
@@ -243,7 +260,15 @@ static int secvar_sysfs_init(void)
 		goto err;
 	}
 
-	secvar_sysfs_load();
+	if (secvar_ops->get_next)
+		rc = secvar_sysfs_load();
+	else
+		rc = secvar_sysfs_load_static();
+
+	if (rc) {
+		pr_err("Failed to create variable attributes\n");
+		goto err;
+	}
 
 	return 0;
 err:
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 11/24] powerpc/secvar: Warn when PAGE_SIZE is smaller than max object size
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

Due to sysfs constraints, when writing to a variable, we can only handle
writes of up to PAGE_SIZE.

It's possible that the maximum object size is larger than PAGE_SIZE, in
which case, print a warning on boot so that the user is aware.

Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch (ajd)
---
 arch/powerpc/kernel/secvar-sysfs.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index e1d4c70dd327..6dd9b4f6f87c 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -221,6 +221,7 @@ static int secvar_sysfs_load_static(void)
 
 static int secvar_sysfs_init(void)
 {
+	u64 max_size;
 	int rc;
 
 	if (!secvar_ops) {
@@ -270,6 +271,14 @@ static int secvar_sysfs_init(void)
 		goto err;
 	}
 
+	// Due to sysfs limitations, we will only ever get a write buffer of
+	// up to 1 page in size. Print a warning if this is potentially going
+	// to cause problems, so that the user is aware.
+	secvar_ops->max_size(&max_size);
+	if (max_size > PAGE_SIZE)
+		pr_warn_ratelimited("PAGE_SIZE (%lu) is smaller than maximum object size (%llu), writes are limited to PAGE_SIZE\n",
+				    PAGE_SIZE, max_size);
+
 	return 0;
 err:
 	kobject_put(secvar_kobj);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 11/24] powerpc/secvar: Warn when PAGE_SIZE is smaller than max object size
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

Due to sysfs constraints, when writing to a variable, we can only handle
writes of up to PAGE_SIZE.

It's possible that the maximum object size is larger than PAGE_SIZE, in
which case, print a warning on boot so that the user is aware.

Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch (ajd)
---
 arch/powerpc/kernel/secvar-sysfs.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index e1d4c70dd327..6dd9b4f6f87c 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -221,6 +221,7 @@ static int secvar_sysfs_load_static(void)
 
 static int secvar_sysfs_init(void)
 {
+	u64 max_size;
 	int rc;
 
 	if (!secvar_ops) {
@@ -270,6 +271,14 @@ static int secvar_sysfs_init(void)
 		goto err;
 	}
 
+	// Due to sysfs limitations, we will only ever get a write buffer of
+	// up to 1 page in size. Print a warning if this is potentially going
+	// to cause problems, so that the user is aware.
+	secvar_ops->max_size(&max_size);
+	if (max_size > PAGE_SIZE)
+		pr_warn_ratelimited("PAGE_SIZE (%lu) is smaller than maximum object size (%llu), writes are limited to PAGE_SIZE\n",
+				    PAGE_SIZE, max_size);
+
 	return 0;
 err:
 	kobject_put(secvar_kobj);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 12/24] powerpc/secvar: Don't print error on ENOENT when reading variables
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

If attempting to read the size or data attributes of a  non-existent
variable (which will be possible after a later patch to expose the PLPKS
via the secvar interface), don't spam the kernel log with error messages.
Only print errors for return codes that aren't ENOENT.

Reported-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 arch/powerpc/kernel/secvar-sysfs.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 6dd9b4f6f87c..33d1797851ba 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -43,8 +43,8 @@ static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
 
 	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
 	if (rc) {
-		pr_err("Error retrieving %s variable size %d\n", kobj->name,
-		       rc);
+		if (rc != -ENOENT)
+			pr_err("Error retrieving %s variable size %d\n", kobj->name, rc);
 		return rc;
 	}
 
@@ -61,7 +61,8 @@ static ssize_t data_read(struct file *filep, struct kobject *kobj,
 
 	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
 	if (rc) {
-		pr_err("Error getting %s variable size %d\n", kobj->name, rc);
+		if (rc != -ENOENT)
+			pr_err("Error getting %s variable size %d\n", kobj->name, rc);
 		return rc;
 	}
 	pr_debug("dsize is %llu\n", dsize);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 12/24] powerpc/secvar: Don't print error on ENOENT when reading variables
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

If attempting to read the size or data attributes of a  non-existent
variable (which will be possible after a later patch to expose the PLPKS
via the secvar interface), don't spam the kernel log with error messages.
Only print errors for return codes that aren't ENOENT.

Reported-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 arch/powerpc/kernel/secvar-sysfs.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/secvar-sysfs.c b/arch/powerpc/kernel/secvar-sysfs.c
index 6dd9b4f6f87c..33d1797851ba 100644
--- a/arch/powerpc/kernel/secvar-sysfs.c
+++ b/arch/powerpc/kernel/secvar-sysfs.c
@@ -43,8 +43,8 @@ static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
 
 	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
 	if (rc) {
-		pr_err("Error retrieving %s variable size %d\n", kobj->name,
-		       rc);
+		if (rc != -ENOENT)
+			pr_err("Error retrieving %s variable size %d\n", kobj->name, rc);
 		return rc;
 	}
 
@@ -61,7 +61,8 @@ static ssize_t data_read(struct file *filep, struct kobject *kobj,
 
 	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
 	if (rc) {
-		pr_err("Error getting %s variable size %d\n", kobj->name, rc);
+		if (rc != -ENOENT)
+			pr_err("Error getting %s variable size %d\n", kobj->name, rc);
 		return rc;
 	}
 	pr_debug("dsize is %llu\n", dsize);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 13/24] powerpc/pseries: Move plpks.h to include directory
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

Move plpks.h from platforms/pseries/ to include/asm/. This is necessary
for later patches to make use of the PLPKS from code in other subsystems.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 .../powerpc/{platforms/pseries => include/asm}/plpks.h | 10 +++++++---
 arch/powerpc/platforms/pseries/plpks.c                 |  3 +--
 2 files changed, 8 insertions(+), 5 deletions(-)
 rename arch/powerpc/{platforms/pseries => include/asm}/plpks.h (89%)

diff --git a/arch/powerpc/platforms/pseries/plpks.h b/arch/powerpc/include/asm/plpks.h
similarity index 89%
rename from arch/powerpc/platforms/pseries/plpks.h
rename to arch/powerpc/include/asm/plpks.h
index 275ccd86bfb5..8295502ee93b 100644
--- a/arch/powerpc/platforms/pseries/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -6,8 +6,10 @@
  * Platform keystore for pseries LPAR(PLPKS).
  */
 
-#ifndef _PSERIES_PLPKS_H
-#define _PSERIES_PLPKS_H
+#ifndef _ASM_POWERPC_PLPKS_H
+#define _ASM_POWERPC_PLPKS_H
+
+#ifdef CONFIG_PSERIES_PLPKS
 
 #include <linux/types.h>
 #include <linux/list.h>
@@ -68,4 +70,6 @@ int plpks_read_fw_var(struct plpks_var *var);
  */
 int plpks_read_bootloader_var(struct plpks_var *var);
 
-#endif
+#endif // CONFIG_PSERIES_PLPKS
+
+#endif // _ASM_POWERPC_PLPKS_H
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index a01cf2ff140a..13e6daadb179 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -18,8 +18,7 @@
 #include <linux/types.h>
 #include <asm/hvcall.h>
 #include <asm/machdep.h>
-
-#include "plpks.h"
+#include <asm/plpks.h>
 
 #define PKS_FW_OWNER	     0x1
 #define PKS_BOOTLOADER_OWNER 0x2
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 13/24] powerpc/pseries: Move plpks.h to include directory
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

Move plpks.h from platforms/pseries/ to include/asm/. This is necessary
for later patches to make use of the PLPKS from code in other subsystems.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 .../powerpc/{platforms/pseries => include/asm}/plpks.h | 10 +++++++---
 arch/powerpc/platforms/pseries/plpks.c                 |  3 +--
 2 files changed, 8 insertions(+), 5 deletions(-)
 rename arch/powerpc/{platforms/pseries => include/asm}/plpks.h (89%)

diff --git a/arch/powerpc/platforms/pseries/plpks.h b/arch/powerpc/include/asm/plpks.h
similarity index 89%
rename from arch/powerpc/platforms/pseries/plpks.h
rename to arch/powerpc/include/asm/plpks.h
index 275ccd86bfb5..8295502ee93b 100644
--- a/arch/powerpc/platforms/pseries/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -6,8 +6,10 @@
  * Platform keystore for pseries LPAR(PLPKS).
  */
 
-#ifndef _PSERIES_PLPKS_H
-#define _PSERIES_PLPKS_H
+#ifndef _ASM_POWERPC_PLPKS_H
+#define _ASM_POWERPC_PLPKS_H
+
+#ifdef CONFIG_PSERIES_PLPKS
 
 #include <linux/types.h>
 #include <linux/list.h>
@@ -68,4 +70,6 @@ int plpks_read_fw_var(struct plpks_var *var);
  */
 int plpks_read_bootloader_var(struct plpks_var *var);
 
-#endif
+#endif // CONFIG_PSERIES_PLPKS
+
+#endif // _ASM_POWERPC_PLPKS_H
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index a01cf2ff140a..13e6daadb179 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -18,8 +18,7 @@
 #include <linux/types.h>
 #include <asm/hvcall.h>
 #include <asm/machdep.h>
-
-#include "plpks.h"
+#include <asm/plpks.h>
 
 #define PKS_FW_OWNER	     0x1
 #define PKS_BOOTLOADER_OWNER 0x2
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 14/24] powerpc/pseries: Move PLPKS constants to header file
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

Move the constants defined in plpks.c to plpks.h, and standardise their
naming, so that PLPKS consumers can make use of them later on.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 arch/powerpc/include/asm/plpks.h       | 36 +++++++++++++---
 arch/powerpc/platforms/pseries/plpks.c | 57 ++++++++++----------------
 2 files changed, 53 insertions(+), 40 deletions(-)

diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index 8295502ee93b..6466aadd7145 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -14,14 +14,40 @@
 #include <linux/types.h>
 #include <linux/list.h>
 
-#define OSSECBOOTAUDIT 0x40000000
-#define OSSECBOOTENFORCE 0x20000000
-#define WORLDREADABLE 0x08000000
-#define SIGNEDUPDATE 0x01000000
+// Object policy flags from supported_policies
+#define PLPKS_OSSECBOOTAUDIT	PPC_BIT32(1) // OS secure boot must be audit/enforce
+#define PLPKS_OSSECBOOTENFORCE	PPC_BIT32(2) // OS secure boot must be enforce
+#define PLPKS_PWSET		PPC_BIT32(3) // No access without password set
+#define PLPKS_WORLDREADABLE	PPC_BIT32(4) // Readable without authentication
+#define PLPKS_IMMUTABLE		PPC_BIT32(5) // Once written, object cannot be removed
+#define PLPKS_TRANSIENT		PPC_BIT32(6) // Object does not persist through reboot
+#define PLPKS_SIGNEDUPDATE	PPC_BIT32(7) // Object can only be modified by signed updates
+#define PLPKS_HVPROVISIONED	PPC_BIT32(28) // Hypervisor has provisioned this object
 
-#define PLPKS_VAR_LINUX	0x02
+// Signature algorithm flags from signed_update_algorithms
+#define PLPKS_ALG_RSA2048	PPC_BIT(0)
+#define PLPKS_ALG_RSA4096	PPC_BIT(1)
+
+// Object label OS metadata flags
+#define PLPKS_VAR_LINUX		0x02
 #define PLPKS_VAR_COMMON	0x04
 
+// Flags for which consumer owns an object is owned by
+#define PLPKS_FW_OWNER			0x1
+#define PLPKS_BOOTLOADER_OWNER		0x2
+#define PLPKS_OS_OWNER			0x3
+
+// Flags for label metadata fields
+#define PLPKS_LABEL_VERSION		0
+#define PLPKS_MAX_LABEL_ATTR_SIZE	16
+#define PLPKS_MAX_NAME_SIZE		239
+#define PLPKS_MAX_DATA_SIZE		4000
+
+// Timeouts for PLPKS operations
+#define PLPKS_MAX_TIMEOUT		5000 // msec
+#define PLPKS_FLUSH_SLEEP		10 // msec
+#define PLPKS_FLUSH_SLEEP_RANGE		400
+
 struct plpks_var {
 	char *component;
 	u8 *name;
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 13e6daadb179..91f3f623a2c7 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -20,19 +20,6 @@
 #include <asm/machdep.h>
 #include <asm/plpks.h>
 
-#define PKS_FW_OWNER	     0x1
-#define PKS_BOOTLOADER_OWNER 0x2
-#define PKS_OS_OWNER	     0x3
-
-#define LABEL_VERSION	    0
-#define MAX_LABEL_ATTR_SIZE 16
-#define MAX_NAME_SIZE	    239
-#define MAX_DATA_SIZE	    4000
-
-#define PKS_FLUSH_MAX_TIMEOUT 5000 //msec
-#define PKS_FLUSH_SLEEP	      10 //msec
-#define PKS_FLUSH_SLEEP_RANGE 400
-
 static u8 *ospassword;
 static u16 ospasswordlength;
 
@@ -59,7 +46,7 @@ struct label_attr {
 
 struct label {
 	struct label_attr attr;
-	u8 name[MAX_NAME_SIZE];
+	u8 name[PLPKS_MAX_NAME_SIZE];
 	size_t size;
 };
 
@@ -122,7 +109,7 @@ static int pseries_status_to_err(int rc)
 static int plpks_gen_password(void)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
-	u8 *password, consumer = PKS_OS_OWNER;
+	u8 *password, consumer = PLPKS_OS_OWNER;
 	int rc;
 
 	// The password must not cross a page boundary, so we align to the next power of 2
@@ -159,7 +146,7 @@ static struct plpks_auth *construct_auth(u8 consumer)
 {
 	struct plpks_auth *auth;
 
-	if (consumer > PKS_OS_OWNER)
+	if (consumer > PLPKS_OS_OWNER)
 		return ERR_PTR(-EINVAL);
 
 	// The auth structure must not cross a page boundary and must be
@@ -171,7 +158,7 @@ static struct plpks_auth *construct_auth(u8 consumer)
 	auth->version = 1;
 	auth->consumer = consumer;
 
-	if (consumer == PKS_FW_OWNER || consumer == PKS_BOOTLOADER_OWNER)
+	if (consumer == PLPKS_FW_OWNER || consumer == PLPKS_BOOTLOADER_OWNER)
 		return auth;
 
 	memcpy(auth->password, ospassword, ospasswordlength);
@@ -191,7 +178,7 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 	struct label *label;
 	size_t slen;
 
-	if (!name || namelen > MAX_NAME_SIZE)
+	if (!name || namelen > PLPKS_MAX_NAME_SIZE)
 		return ERR_PTR(-EINVAL);
 
 	slen = strlen(component);
@@ -206,9 +193,9 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 	if (component)
 		memcpy(&label->attr.prefix, component, slen);
 
-	label->attr.version = LABEL_VERSION;
+	label->attr.version = PLPKS_LABEL_VERSION;
 	label->attr.os = varos;
-	label->attr.length = MAX_LABEL_ATTR_SIZE;
+	label->attr.length = PLPKS_MAX_LABEL_ATTR_SIZE;
 	memcpy(&label->name, name, namelen);
 
 	label->size = sizeof(struct label_attr) + namelen;
@@ -274,10 +261,10 @@ static int plpks_confirm_object_flushed(struct label *label,
 			break;
 		}
 
-		usleep_range(PKS_FLUSH_SLEEP,
-			     PKS_FLUSH_SLEEP + PKS_FLUSH_SLEEP_RANGE);
-		timeout = timeout + PKS_FLUSH_SLEEP;
-	} while (timeout < PKS_FLUSH_MAX_TIMEOUT);
+		usleep_range(PLPKS_FLUSH_SLEEP,
+			     PLPKS_FLUSH_SLEEP + PLPKS_FLUSH_SLEEP_RANGE);
+		timeout = timeout + PLPKS_FLUSH_SLEEP;
+	} while (timeout < PLPKS_MAX_TIMEOUT);
 
 	if (timed_out)
 		return -ETIMEDOUT;
@@ -293,13 +280,13 @@ int plpks_write_var(struct plpks_var var)
 	int rc;
 
 	if (!var.component || !var.data || var.datalen <= 0 ||
-	    var.namelen > MAX_NAME_SIZE || var.datalen > MAX_DATA_SIZE)
+	    var.namelen > PLPKS_MAX_NAME_SIZE || var.datalen > PLPKS_MAX_DATA_SIZE)
 		return -EINVAL;
 
-	if (var.policy & SIGNEDUPDATE)
+	if (var.policy & PLPKS_SIGNEDUPDATE)
 		return -EINVAL;
 
-	auth = construct_auth(PKS_OS_OWNER);
+	auth = construct_auth(PLPKS_OS_OWNER);
 	if (IS_ERR(auth))
 		return PTR_ERR(auth);
 
@@ -331,10 +318,10 @@ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname)
 	struct label *label;
 	int rc;
 
-	if (!component || vname.namelen > MAX_NAME_SIZE)
+	if (!component || vname.namelen > PLPKS_MAX_NAME_SIZE)
 		return -EINVAL;
 
-	auth = construct_auth(PKS_OS_OWNER);
+	auth = construct_auth(PLPKS_OS_OWNER);
 	if (IS_ERR(auth))
 		return PTR_ERR(auth);
 
@@ -366,14 +353,14 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
 	u8 *output;
 	int rc;
 
-	if (var->namelen > MAX_NAME_SIZE)
+	if (var->namelen > PLPKS_MAX_NAME_SIZE)
 		return -EINVAL;
 
 	auth = construct_auth(consumer);
 	if (IS_ERR(auth))
 		return PTR_ERR(auth);
 
-	if (consumer == PKS_OS_OWNER) {
+	if (consumer == PLPKS_OS_OWNER) {
 		label = construct_label(var->component, var->os, var->name,
 					var->namelen);
 		if (IS_ERR(label)) {
@@ -388,7 +375,7 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
 		goto out_free_label;
 	}
 
-	if (consumer == PKS_OS_OWNER)
+	if (consumer == PLPKS_OS_OWNER)
 		rc = plpar_hcall(H_PKS_READ_OBJECT, retbuf, virt_to_phys(auth),
 				 virt_to_phys(label), label->size, virt_to_phys(output),
 				 maxobjsize);
@@ -428,17 +415,17 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
 
 int plpks_read_os_var(struct plpks_var *var)
 {
-	return plpks_read_var(PKS_OS_OWNER, var);
+	return plpks_read_var(PLPKS_OS_OWNER, var);
 }
 
 int plpks_read_fw_var(struct plpks_var *var)
 {
-	return plpks_read_var(PKS_FW_OWNER, var);
+	return plpks_read_var(PLPKS_FW_OWNER, var);
 }
 
 int plpks_read_bootloader_var(struct plpks_var *var)
 {
-	return plpks_read_var(PKS_BOOTLOADER_OWNER, var);
+	return plpks_read_var(PLPKS_BOOTLOADER_OWNER, var);
 }
 
 static __init int pseries_plpks_init(void)
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 14/24] powerpc/pseries: Move PLPKS constants to header file
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

Move the constants defined in plpks.c to plpks.h, and standardise their
naming, so that PLPKS consumers can make use of them later on.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 arch/powerpc/include/asm/plpks.h       | 36 +++++++++++++---
 arch/powerpc/platforms/pseries/plpks.c | 57 ++++++++++----------------
 2 files changed, 53 insertions(+), 40 deletions(-)

diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index 8295502ee93b..6466aadd7145 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -14,14 +14,40 @@
 #include <linux/types.h>
 #include <linux/list.h>
 
-#define OSSECBOOTAUDIT 0x40000000
-#define OSSECBOOTENFORCE 0x20000000
-#define WORLDREADABLE 0x08000000
-#define SIGNEDUPDATE 0x01000000
+// Object policy flags from supported_policies
+#define PLPKS_OSSECBOOTAUDIT	PPC_BIT32(1) // OS secure boot must be audit/enforce
+#define PLPKS_OSSECBOOTENFORCE	PPC_BIT32(2) // OS secure boot must be enforce
+#define PLPKS_PWSET		PPC_BIT32(3) // No access without password set
+#define PLPKS_WORLDREADABLE	PPC_BIT32(4) // Readable without authentication
+#define PLPKS_IMMUTABLE		PPC_BIT32(5) // Once written, object cannot be removed
+#define PLPKS_TRANSIENT		PPC_BIT32(6) // Object does not persist through reboot
+#define PLPKS_SIGNEDUPDATE	PPC_BIT32(7) // Object can only be modified by signed updates
+#define PLPKS_HVPROVISIONED	PPC_BIT32(28) // Hypervisor has provisioned this object
 
-#define PLPKS_VAR_LINUX	0x02
+// Signature algorithm flags from signed_update_algorithms
+#define PLPKS_ALG_RSA2048	PPC_BIT(0)
+#define PLPKS_ALG_RSA4096	PPC_BIT(1)
+
+// Object label OS metadata flags
+#define PLPKS_VAR_LINUX		0x02
 #define PLPKS_VAR_COMMON	0x04
 
+// Flags for which consumer owns an object is owned by
+#define PLPKS_FW_OWNER			0x1
+#define PLPKS_BOOTLOADER_OWNER		0x2
+#define PLPKS_OS_OWNER			0x3
+
+// Flags for label metadata fields
+#define PLPKS_LABEL_VERSION		0
+#define PLPKS_MAX_LABEL_ATTR_SIZE	16
+#define PLPKS_MAX_NAME_SIZE		239
+#define PLPKS_MAX_DATA_SIZE		4000
+
+// Timeouts for PLPKS operations
+#define PLPKS_MAX_TIMEOUT		5000 // msec
+#define PLPKS_FLUSH_SLEEP		10 // msec
+#define PLPKS_FLUSH_SLEEP_RANGE		400
+
 struct plpks_var {
 	char *component;
 	u8 *name;
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 13e6daadb179..91f3f623a2c7 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -20,19 +20,6 @@
 #include <asm/machdep.h>
 #include <asm/plpks.h>
 
-#define PKS_FW_OWNER	     0x1
-#define PKS_BOOTLOADER_OWNER 0x2
-#define PKS_OS_OWNER	     0x3
-
-#define LABEL_VERSION	    0
-#define MAX_LABEL_ATTR_SIZE 16
-#define MAX_NAME_SIZE	    239
-#define MAX_DATA_SIZE	    4000
-
-#define PKS_FLUSH_MAX_TIMEOUT 5000 //msec
-#define PKS_FLUSH_SLEEP	      10 //msec
-#define PKS_FLUSH_SLEEP_RANGE 400
-
 static u8 *ospassword;
 static u16 ospasswordlength;
 
@@ -59,7 +46,7 @@ struct label_attr {
 
 struct label {
 	struct label_attr attr;
-	u8 name[MAX_NAME_SIZE];
+	u8 name[PLPKS_MAX_NAME_SIZE];
 	size_t size;
 };
 
@@ -122,7 +109,7 @@ static int pseries_status_to_err(int rc)
 static int plpks_gen_password(void)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
-	u8 *password, consumer = PKS_OS_OWNER;
+	u8 *password, consumer = PLPKS_OS_OWNER;
 	int rc;
 
 	// The password must not cross a page boundary, so we align to the next power of 2
@@ -159,7 +146,7 @@ static struct plpks_auth *construct_auth(u8 consumer)
 {
 	struct plpks_auth *auth;
 
-	if (consumer > PKS_OS_OWNER)
+	if (consumer > PLPKS_OS_OWNER)
 		return ERR_PTR(-EINVAL);
 
 	// The auth structure must not cross a page boundary and must be
@@ -171,7 +158,7 @@ static struct plpks_auth *construct_auth(u8 consumer)
 	auth->version = 1;
 	auth->consumer = consumer;
 
-	if (consumer == PKS_FW_OWNER || consumer == PKS_BOOTLOADER_OWNER)
+	if (consumer == PLPKS_FW_OWNER || consumer == PLPKS_BOOTLOADER_OWNER)
 		return auth;
 
 	memcpy(auth->password, ospassword, ospasswordlength);
@@ -191,7 +178,7 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 	struct label *label;
 	size_t slen;
 
-	if (!name || namelen > MAX_NAME_SIZE)
+	if (!name || namelen > PLPKS_MAX_NAME_SIZE)
 		return ERR_PTR(-EINVAL);
 
 	slen = strlen(component);
@@ -206,9 +193,9 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 	if (component)
 		memcpy(&label->attr.prefix, component, slen);
 
-	label->attr.version = LABEL_VERSION;
+	label->attr.version = PLPKS_LABEL_VERSION;
 	label->attr.os = varos;
-	label->attr.length = MAX_LABEL_ATTR_SIZE;
+	label->attr.length = PLPKS_MAX_LABEL_ATTR_SIZE;
 	memcpy(&label->name, name, namelen);
 
 	label->size = sizeof(struct label_attr) + namelen;
@@ -274,10 +261,10 @@ static int plpks_confirm_object_flushed(struct label *label,
 			break;
 		}
 
-		usleep_range(PKS_FLUSH_SLEEP,
-			     PKS_FLUSH_SLEEP + PKS_FLUSH_SLEEP_RANGE);
-		timeout = timeout + PKS_FLUSH_SLEEP;
-	} while (timeout < PKS_FLUSH_MAX_TIMEOUT);
+		usleep_range(PLPKS_FLUSH_SLEEP,
+			     PLPKS_FLUSH_SLEEP + PLPKS_FLUSH_SLEEP_RANGE);
+		timeout = timeout + PLPKS_FLUSH_SLEEP;
+	} while (timeout < PLPKS_MAX_TIMEOUT);
 
 	if (timed_out)
 		return -ETIMEDOUT;
@@ -293,13 +280,13 @@ int plpks_write_var(struct plpks_var var)
 	int rc;
 
 	if (!var.component || !var.data || var.datalen <= 0 ||
-	    var.namelen > MAX_NAME_SIZE || var.datalen > MAX_DATA_SIZE)
+	    var.namelen > PLPKS_MAX_NAME_SIZE || var.datalen > PLPKS_MAX_DATA_SIZE)
 		return -EINVAL;
 
-	if (var.policy & SIGNEDUPDATE)
+	if (var.policy & PLPKS_SIGNEDUPDATE)
 		return -EINVAL;
 
-	auth = construct_auth(PKS_OS_OWNER);
+	auth = construct_auth(PLPKS_OS_OWNER);
 	if (IS_ERR(auth))
 		return PTR_ERR(auth);
 
@@ -331,10 +318,10 @@ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname)
 	struct label *label;
 	int rc;
 
-	if (!component || vname.namelen > MAX_NAME_SIZE)
+	if (!component || vname.namelen > PLPKS_MAX_NAME_SIZE)
 		return -EINVAL;
 
-	auth = construct_auth(PKS_OS_OWNER);
+	auth = construct_auth(PLPKS_OS_OWNER);
 	if (IS_ERR(auth))
 		return PTR_ERR(auth);
 
@@ -366,14 +353,14 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
 	u8 *output;
 	int rc;
 
-	if (var->namelen > MAX_NAME_SIZE)
+	if (var->namelen > PLPKS_MAX_NAME_SIZE)
 		return -EINVAL;
 
 	auth = construct_auth(consumer);
 	if (IS_ERR(auth))
 		return PTR_ERR(auth);
 
-	if (consumer == PKS_OS_OWNER) {
+	if (consumer == PLPKS_OS_OWNER) {
 		label = construct_label(var->component, var->os, var->name,
 					var->namelen);
 		if (IS_ERR(label)) {
@@ -388,7 +375,7 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
 		goto out_free_label;
 	}
 
-	if (consumer == PKS_OS_OWNER)
+	if (consumer == PLPKS_OS_OWNER)
 		rc = plpar_hcall(H_PKS_READ_OBJECT, retbuf, virt_to_phys(auth),
 				 virt_to_phys(label), label->size, virt_to_phys(output),
 				 maxobjsize);
@@ -428,17 +415,17 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
 
 int plpks_read_os_var(struct plpks_var *var)
 {
-	return plpks_read_var(PKS_OS_OWNER, var);
+	return plpks_read_var(PLPKS_OS_OWNER, var);
 }
 
 int plpks_read_fw_var(struct plpks_var *var)
 {
-	return plpks_read_var(PKS_FW_OWNER, var);
+	return plpks_read_var(PLPKS_FW_OWNER, var);
 }
 
 int plpks_read_bootloader_var(struct plpks_var *var)
 {
-	return plpks_read_var(PKS_BOOTLOADER_OWNER, var);
+	return plpks_read_var(PLPKS_BOOTLOADER_OWNER, var);
 }
 
 static __init int pseries_plpks_init(void)
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 15/24] powerpc/pseries: Expose PLPKS config values, support additional fields
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Nayna Jain <nayna@linux.ibm.com>

The plpks driver uses the H_PKS_GET_CONFIG hcall to retrieve configuration
and status information about the PKS from the hypervisor.

Update _plpks_get_config() to handle some additional fields. Add getter
functions to allow the PKS configuration information to be accessed from
other files. Validate that the values we're getting comply with the spec.

While we're here, move the config struct in _plpks_get_config() off the
stack - it's getting large and we also need to make sure it doesn't cross
a page boundary.

Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
[ajd: split patch, extend to support additional v3 API fields, minor fixes]
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: Merge plpks fixes and signed update series with secvar series

    Refresh config values in plpks_get_usedspace() (ajd)

    Validate the config values being returned comply with spec (ruscur)

    Return maxobjlabelsize as is (ruscur)

    Move plpks.h to include/asm (ruscur)

    Fix checkpatch checks (ruscur)
---
 arch/powerpc/include/asm/plpks.h       |  58 ++++++++++
 arch/powerpc/platforms/pseries/plpks.c | 149 +++++++++++++++++++++++--
 2 files changed, 195 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index 6466aadd7145..7c5f51a9af7c 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -96,6 +96,64 @@ int plpks_read_fw_var(struct plpks_var *var);
  */
 int plpks_read_bootloader_var(struct plpks_var *var);
 
+/**
+ * Returns if PKS is available on this LPAR.
+ */
+bool plpks_is_available(void);
+
+/**
+ * Returns version of the Platform KeyStore.
+ */
+u8 plpks_get_version(void);
+
+/**
+ * Returns hypervisor storage overhead per object, not including the size of
+ * the object or label. Only valid for config version >= 2
+ */
+u16 plpks_get_objoverhead(void);
+
+/**
+ * Returns maximum password size. Must be >= 32 bytes
+ */
+u16 plpks_get_maxpwsize(void);
+
+/**
+ * Returns maximum object size supported by Platform KeyStore.
+ */
+u16 plpks_get_maxobjectsize(void);
+
+/**
+ * Returns maximum object label size supported by Platform KeyStore.
+ */
+u16 plpks_get_maxobjectlabelsize(void);
+
+/**
+ * Returns total size of the configured Platform KeyStore.
+ */
+u32 plpks_get_totalsize(void);
+
+/**
+ * Returns used space from the total size of the Platform KeyStore.
+ */
+u32 plpks_get_usedspace(void);
+
+/**
+ * Returns bitmask of policies supported by the hypervisor.
+ */
+u32 plpks_get_supportedpolicies(void);
+
+/**
+ * Returns maximum byte size of a single object supported by the hypervisor.
+ * Only valid for config version >= 3
+ */
+u32 plpks_get_maxlargeobjectsize(void);
+
+/**
+ * Returns bitmask of signature algorithms supported for signed updates.
+ * Only valid for config version >= 3
+ */
+u64 plpks_get_signedupdatealgorithms(void);
+
 #endif // CONFIG_PSERIES_PLPKS
 
 #endif // _ASM_POWERPC_PLPKS_H
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 91f3f623a2c7..1189246b03dc 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -24,8 +24,16 @@ static u8 *ospassword;
 static u16 ospasswordlength;
 
 // Retrieved with H_PKS_GET_CONFIG
+static u8 version;
+static u16 objoverhead;
 static u16 maxpwsize;
 static u16 maxobjsize;
+static s16 maxobjlabelsize;
+static u32 totalsize;
+static u32 usedspace;
+static u32 supportedpolicies;
+static u32 maxlargeobjectsize;
+static u64 signedupdatealgorithms;
 
 struct plpks_auth {
 	u8 version;
@@ -206,32 +214,149 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 static int _plpks_get_config(void)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
-	struct {
+	struct config {
 		u8 version;
 		u8 flags;
-		__be32 rsvd0;
+		__be16 rsvd0;
+		__be16 objoverhead;
 		__be16 maxpwsize;
 		__be16 maxobjlabelsize;
 		__be16 maxobjsize;
 		__be32 totalsize;
 		__be32 usedspace;
 		__be32 supportedpolicies;
-		__be64 rsvd1;
-	} __packed config;
+		__be32 maxlargeobjectsize;
+		__be64 signedupdatealgorithms;
+		u8 rsvd1[476];
+	} __packed * config;
 	size_t size;
-	int rc;
+	int rc = 0;
+
+	size = sizeof(*config);
+
+	// Config struct must not cross a page boundary. So long as the struct
+	// size is a power of 2, this should be fine as alignment is guaranteed
+	config = kzalloc(size, GFP_KERNEL);
+	if (!config) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	rc = plpar_hcall(H_PKS_GET_CONFIG, retbuf, virt_to_phys(config), size);
+
+	if (rc != H_SUCCESS) {
+		rc = pseries_status_to_err(rc);
+		goto err;
+	}
+
+	version = config->version;
+	objoverhead = be16_to_cpu(config->objoverhead);
+	maxpwsize = be16_to_cpu(config->maxpwsize);
+	maxobjsize = be16_to_cpu(config->maxobjsize);
+	maxobjlabelsize = be16_to_cpu(config->maxobjlabelsize);
+	totalsize = be32_to_cpu(config->totalsize);
+	usedspace = be32_to_cpu(config->usedspace);
+	supportedpolicies = be32_to_cpu(config->supportedpolicies);
+	maxlargeobjectsize = be32_to_cpu(config->maxlargeobjectsize);
+	signedupdatealgorithms = be64_to_cpu(config->signedupdatealgorithms);
+
+	// Validate that the numbers we get back match the requirements of the spec
+	if (maxpwsize < 32) {
+		pr_err("Invalid Max Password Size received from hypervisor (%d < 32)\n", maxpwsize);
+		rc = -EIO;
+		goto err;
+	}
+
+	if (maxobjlabelsize < 255) {
+		pr_err("Invalid Max Object Label Size received from hypervisor (%d < 255)\n",
+		       maxobjlabelsize);
+		rc = -EIO;
+		goto err;
+	}
 
-	size = sizeof(config);
+	if (totalsize < 4096) {
+		pr_err("Invalid Total Size received from hypervisor (%d < 4096)\n", totalsize);
+		rc = -EIO;
+		goto err;
+	}
+
+	if (version >= 3 && maxlargeobjectsize >= 65536 && maxobjsize != 0xFFFF) {
+		pr_err("Invalid Max Object Size (0x%x != 0xFFFF)\n", maxobjsize);
+		rc = -EIO;
+		goto err;
+	}
+
+err:
+	kfree(config);
+	return rc;
+}
+
+u8 plpks_get_version(void)
+{
+	return version;
+}
 
-	rc = plpar_hcall(H_PKS_GET_CONFIG, retbuf, virt_to_phys(&config), size);
+u16 plpks_get_objoverhead(void)
+{
+	return objoverhead;
+}
 
-	if (rc != H_SUCCESS)
-		return pseries_status_to_err(rc);
+u16 plpks_get_maxpwsize(void)
+{
+	return maxpwsize;
+}
 
-	maxpwsize = be16_to_cpu(config.maxpwsize);
-	maxobjsize = be16_to_cpu(config.maxobjsize);
+u16 plpks_get_maxobjectsize(void)
+{
+	return maxobjsize;
+}
+
+u16 plpks_get_maxobjectlabelsize(void)
+{
+	return maxobjlabelsize;
+}
+
+u32 plpks_get_totalsize(void)
+{
+	return totalsize;
+}
+
+u32 plpks_get_usedspace(void)
+{
+	// Unlike other config values, usedspace regularly changes as objects
+	// are updated, so we need to refresh.
+	int rc = _plpks_get_config();
+	if (rc) {
+		pr_err("Couldn't get config, rc: %d\n", rc);
+		return 0;
+	}
+	return usedspace;
+}
+
+u32 plpks_get_supportedpolicies(void)
+{
+	return supportedpolicies;
+}
+
+u32 plpks_get_maxlargeobjectsize(void)
+{
+	return maxlargeobjectsize;
+}
+
+u64 plpks_get_signedupdatealgorithms(void)
+{
+	return signedupdatealgorithms;
+}
+
+bool plpks_is_available(void)
+{
+	int rc;
+
+	rc = _plpks_get_config();
+	if (rc)
+		return false;
 
-	return 0;
+	return true;
 }
 
 static int plpks_confirm_object_flushed(struct label *label,
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 15/24] powerpc/pseries: Expose PLPKS config values, support additional fields
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Nayna Jain <nayna@linux.ibm.com>

The plpks driver uses the H_PKS_GET_CONFIG hcall to retrieve configuration
and status information about the PKS from the hypervisor.

Update _plpks_get_config() to handle some additional fields. Add getter
functions to allow the PKS configuration information to be accessed from
other files. Validate that the values we're getting comply with the spec.

While we're here, move the config struct in _plpks_get_config() off the
stack - it's getting large and we also need to make sure it doesn't cross
a page boundary.

Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
[ajd: split patch, extend to support additional v3 API fields, minor fixes]
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: Merge plpks fixes and signed update series with secvar series

    Refresh config values in plpks_get_usedspace() (ajd)

    Validate the config values being returned comply with spec (ruscur)

    Return maxobjlabelsize as is (ruscur)

    Move plpks.h to include/asm (ruscur)

    Fix checkpatch checks (ruscur)
---
 arch/powerpc/include/asm/plpks.h       |  58 ++++++++++
 arch/powerpc/platforms/pseries/plpks.c | 149 +++++++++++++++++++++++--
 2 files changed, 195 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index 6466aadd7145..7c5f51a9af7c 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -96,6 +96,64 @@ int plpks_read_fw_var(struct plpks_var *var);
  */
 int plpks_read_bootloader_var(struct plpks_var *var);
 
+/**
+ * Returns if PKS is available on this LPAR.
+ */
+bool plpks_is_available(void);
+
+/**
+ * Returns version of the Platform KeyStore.
+ */
+u8 plpks_get_version(void);
+
+/**
+ * Returns hypervisor storage overhead per object, not including the size of
+ * the object or label. Only valid for config version >= 2
+ */
+u16 plpks_get_objoverhead(void);
+
+/**
+ * Returns maximum password size. Must be >= 32 bytes
+ */
+u16 plpks_get_maxpwsize(void);
+
+/**
+ * Returns maximum object size supported by Platform KeyStore.
+ */
+u16 plpks_get_maxobjectsize(void);
+
+/**
+ * Returns maximum object label size supported by Platform KeyStore.
+ */
+u16 plpks_get_maxobjectlabelsize(void);
+
+/**
+ * Returns total size of the configured Platform KeyStore.
+ */
+u32 plpks_get_totalsize(void);
+
+/**
+ * Returns used space from the total size of the Platform KeyStore.
+ */
+u32 plpks_get_usedspace(void);
+
+/**
+ * Returns bitmask of policies supported by the hypervisor.
+ */
+u32 plpks_get_supportedpolicies(void);
+
+/**
+ * Returns maximum byte size of a single object supported by the hypervisor.
+ * Only valid for config version >= 3
+ */
+u32 plpks_get_maxlargeobjectsize(void);
+
+/**
+ * Returns bitmask of signature algorithms supported for signed updates.
+ * Only valid for config version >= 3
+ */
+u64 plpks_get_signedupdatealgorithms(void);
+
 #endif // CONFIG_PSERIES_PLPKS
 
 #endif // _ASM_POWERPC_PLPKS_H
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 91f3f623a2c7..1189246b03dc 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -24,8 +24,16 @@ static u8 *ospassword;
 static u16 ospasswordlength;
 
 // Retrieved with H_PKS_GET_CONFIG
+static u8 version;
+static u16 objoverhead;
 static u16 maxpwsize;
 static u16 maxobjsize;
+static s16 maxobjlabelsize;
+static u32 totalsize;
+static u32 usedspace;
+static u32 supportedpolicies;
+static u32 maxlargeobjectsize;
+static u64 signedupdatealgorithms;
 
 struct plpks_auth {
 	u8 version;
@@ -206,32 +214,149 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 static int _plpks_get_config(void)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
-	struct {
+	struct config {
 		u8 version;
 		u8 flags;
-		__be32 rsvd0;
+		__be16 rsvd0;
+		__be16 objoverhead;
 		__be16 maxpwsize;
 		__be16 maxobjlabelsize;
 		__be16 maxobjsize;
 		__be32 totalsize;
 		__be32 usedspace;
 		__be32 supportedpolicies;
-		__be64 rsvd1;
-	} __packed config;
+		__be32 maxlargeobjectsize;
+		__be64 signedupdatealgorithms;
+		u8 rsvd1[476];
+	} __packed * config;
 	size_t size;
-	int rc;
+	int rc = 0;
+
+	size = sizeof(*config);
+
+	// Config struct must not cross a page boundary. So long as the struct
+	// size is a power of 2, this should be fine as alignment is guaranteed
+	config = kzalloc(size, GFP_KERNEL);
+	if (!config) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	rc = plpar_hcall(H_PKS_GET_CONFIG, retbuf, virt_to_phys(config), size);
+
+	if (rc != H_SUCCESS) {
+		rc = pseries_status_to_err(rc);
+		goto err;
+	}
+
+	version = config->version;
+	objoverhead = be16_to_cpu(config->objoverhead);
+	maxpwsize = be16_to_cpu(config->maxpwsize);
+	maxobjsize = be16_to_cpu(config->maxobjsize);
+	maxobjlabelsize = be16_to_cpu(config->maxobjlabelsize);
+	totalsize = be32_to_cpu(config->totalsize);
+	usedspace = be32_to_cpu(config->usedspace);
+	supportedpolicies = be32_to_cpu(config->supportedpolicies);
+	maxlargeobjectsize = be32_to_cpu(config->maxlargeobjectsize);
+	signedupdatealgorithms = be64_to_cpu(config->signedupdatealgorithms);
+
+	// Validate that the numbers we get back match the requirements of the spec
+	if (maxpwsize < 32) {
+		pr_err("Invalid Max Password Size received from hypervisor (%d < 32)\n", maxpwsize);
+		rc = -EIO;
+		goto err;
+	}
+
+	if (maxobjlabelsize < 255) {
+		pr_err("Invalid Max Object Label Size received from hypervisor (%d < 255)\n",
+		       maxobjlabelsize);
+		rc = -EIO;
+		goto err;
+	}
 
-	size = sizeof(config);
+	if (totalsize < 4096) {
+		pr_err("Invalid Total Size received from hypervisor (%d < 4096)\n", totalsize);
+		rc = -EIO;
+		goto err;
+	}
+
+	if (version >= 3 && maxlargeobjectsize >= 65536 && maxobjsize != 0xFFFF) {
+		pr_err("Invalid Max Object Size (0x%x != 0xFFFF)\n", maxobjsize);
+		rc = -EIO;
+		goto err;
+	}
+
+err:
+	kfree(config);
+	return rc;
+}
+
+u8 plpks_get_version(void)
+{
+	return version;
+}
 
-	rc = plpar_hcall(H_PKS_GET_CONFIG, retbuf, virt_to_phys(&config), size);
+u16 plpks_get_objoverhead(void)
+{
+	return objoverhead;
+}
 
-	if (rc != H_SUCCESS)
-		return pseries_status_to_err(rc);
+u16 plpks_get_maxpwsize(void)
+{
+	return maxpwsize;
+}
 
-	maxpwsize = be16_to_cpu(config.maxpwsize);
-	maxobjsize = be16_to_cpu(config.maxobjsize);
+u16 plpks_get_maxobjectsize(void)
+{
+	return maxobjsize;
+}
+
+u16 plpks_get_maxobjectlabelsize(void)
+{
+	return maxobjlabelsize;
+}
+
+u32 plpks_get_totalsize(void)
+{
+	return totalsize;
+}
+
+u32 plpks_get_usedspace(void)
+{
+	// Unlike other config values, usedspace regularly changes as objects
+	// are updated, so we need to refresh.
+	int rc = _plpks_get_config();
+	if (rc) {
+		pr_err("Couldn't get config, rc: %d\n", rc);
+		return 0;
+	}
+	return usedspace;
+}
+
+u32 plpks_get_supportedpolicies(void)
+{
+	return supportedpolicies;
+}
+
+u32 plpks_get_maxlargeobjectsize(void)
+{
+	return maxlargeobjectsize;
+}
+
+u64 plpks_get_signedupdatealgorithms(void)
+{
+	return signedupdatealgorithms;
+}
+
+bool plpks_is_available(void)
+{
+	int rc;
+
+	rc = _plpks_get_config();
+	if (rc)
+		return false;
 
-	return 0;
+	return true;
 }
 
 static int plpks_confirm_object_flushed(struct label *label,
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 16/24] powerpc/pseries: Implement signed update for PLPKS objects
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Nayna Jain <nayna@linux.ibm.com>

The Platform Keystore provides a signed update interface which can be used
to create, replace or append to certain variables in the PKS in a secure
fashion, with the hypervisor requiring that the update be signed using the
Platform Key.

Implement an interface to the H_PKS_SIGNED_UPDATE hcall in the plpks
driver to allow signed updates to PKS objects.

(The plpks driver doesn't need to do any cryptography or otherwise handle
the actual signed variable contents - that will be handled by userspace
tooling.)

Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
[ajd: split patch, add timeout handling and misc cleanups]
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: Merge plpks fixes and signed update series with secvar series

    Fix error code handling in plpks_confirm_object_flushed() (ruscur)

    Pass plpks_var struct to plpks_signed_update_var() by reference (mpe)

    Consistent constant naming scheme (ruscur)

v4: Fix MAX_HCALL_OPCODE rebasing issue (npiggin)
---
 arch/powerpc/include/asm/hvcall.h      |  1 +
 arch/powerpc/include/asm/plpks.h       |  5 ++
 arch/powerpc/platforms/pseries/plpks.c | 71 ++++++++++++++++++++++++--
 3 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 95fd7f9485d5..c099780385dd 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -335,6 +335,7 @@
 #define H_RPT_INVALIDATE	0x448
 #define H_SCM_FLUSH		0x44C
 #define H_GET_ENERGY_SCALE_INFO	0x450
+#define H_PKS_SIGNED_UPDATE	0x454
 #define H_WATCHDOG		0x45C
 #define MAX_HCALL_OPCODE	H_WATCHDOG
 
diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index 7c5f51a9af7c..e7204e6c0ca4 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -68,6 +68,11 @@ struct plpks_var_name_list {
 	struct plpks_var_name varlist[];
 };
 
+/**
+ * Updates the authenticated variable. It expects NULL as the component.
+ */
+int plpks_signed_update_var(struct plpks_var *var, u64 flags);
+
 /**
  * Writes the specified var and its data to PKS.
  * Any caller of PKS driver should present a valid component type for
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 1189246b03dc..796ed5544ee5 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -81,6 +81,12 @@ static int pseries_status_to_err(int rc)
 		err = -ENOENT;
 		break;
 	case H_BUSY:
+	case H_LONG_BUSY_ORDER_1_MSEC:
+	case H_LONG_BUSY_ORDER_10_MSEC:
+	case H_LONG_BUSY_ORDER_100_MSEC:
+	case H_LONG_BUSY_ORDER_1_SEC:
+	case H_LONG_BUSY_ORDER_10_SEC:
+	case H_LONG_BUSY_ORDER_100_SEC:
 		err = -EBUSY;
 		break;
 	case H_AUTHORITY:
@@ -184,14 +190,17 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 				     u16 namelen)
 {
 	struct label *label;
-	size_t slen;
+	size_t slen = 0;
 
 	if (!name || namelen > PLPKS_MAX_NAME_SIZE)
 		return ERR_PTR(-EINVAL);
 
-	slen = strlen(component);
-	if (component && slen > sizeof(label->attr.prefix))
-		return ERR_PTR(-EINVAL);
+	// Support NULL component for signed updates
+	if (component) {
+		slen = strlen(component);
+		if (slen > sizeof(label->attr.prefix))
+			return ERR_PTR(-EINVAL);
+	}
 
 	// The label structure must not cross a page boundary, so we align to the next power of 2
 	label = kzalloc(roundup_pow_of_two(sizeof(*label)), GFP_KERNEL);
@@ -397,6 +406,58 @@ static int plpks_confirm_object_flushed(struct label *label,
 	return pseries_status_to_err(rc);
 }
 
+int plpks_signed_update_var(struct plpks_var *var, u64 flags)
+{
+	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = {0};
+	int rc;
+	struct label *label;
+	struct plpks_auth *auth;
+	u64 continuetoken = 0;
+	u64 timeout = 0;
+
+	if (!var->data || var->datalen <= 0 || var->namelen > PLPKS_MAX_NAME_SIZE)
+		return -EINVAL;
+
+	if (!(var->policy & PLPKS_SIGNEDUPDATE))
+		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;
+	}
+
+	do {
+		rc = plpar_hcall9(H_PKS_SIGNED_UPDATE, retbuf,
+				  virt_to_phys(auth), virt_to_phys(label),
+				  label->size, var->policy, flags,
+				  virt_to_phys(var->data), var->datalen,
+				  continuetoken);
+
+		continuetoken = retbuf[0];
+		if (pseries_status_to_err(rc) == -EBUSY) {
+			int delay_ms = get_longbusy_msecs(rc);
+			mdelay(delay_ms);
+			timeout += delay_ms;
+		}
+		rc = pseries_status_to_err(rc);
+	} while (rc == -EBUSY && timeout < PLPKS_MAX_TIMEOUT);
+
+	if (!rc)
+		rc = plpks_confirm_object_flushed(label, auth);
+
+	kfree(label);
+out:
+	kfree(auth);
+
+	return rc;
+}
+EXPORT_SYMBOL(plpks_signed_update_var);
+
 int plpks_write_var(struct plpks_var var)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
@@ -443,7 +504,7 @@ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname)
 	struct label *label;
 	int rc;
 
-	if (!component || vname.namelen > PLPKS_MAX_NAME_SIZE)
+	if (vname.namelen > PLPKS_MAX_NAME_SIZE)
 		return -EINVAL;
 
 	auth = construct_auth(PLPKS_OS_OWNER);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 16/24] powerpc/pseries: Implement signed update for PLPKS objects
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Nayna Jain <nayna@linux.ibm.com>

The Platform Keystore provides a signed update interface which can be used
to create, replace or append to certain variables in the PKS in a secure
fashion, with the hypervisor requiring that the update be signed using the
Platform Key.

Implement an interface to the H_PKS_SIGNED_UPDATE hcall in the plpks
driver to allow signed updates to PKS objects.

(The plpks driver doesn't need to do any cryptography or otherwise handle
the actual signed variable contents - that will be handled by userspace
tooling.)

Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
[ajd: split patch, add timeout handling and misc cleanups]
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: Merge plpks fixes and signed update series with secvar series

    Fix error code handling in plpks_confirm_object_flushed() (ruscur)

    Pass plpks_var struct to plpks_signed_update_var() by reference (mpe)

    Consistent constant naming scheme (ruscur)

v4: Fix MAX_HCALL_OPCODE rebasing issue (npiggin)
---
 arch/powerpc/include/asm/hvcall.h      |  1 +
 arch/powerpc/include/asm/plpks.h       |  5 ++
 arch/powerpc/platforms/pseries/plpks.c | 71 ++++++++++++++++++++++++--
 3 files changed, 72 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 95fd7f9485d5..c099780385dd 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -335,6 +335,7 @@
 #define H_RPT_INVALIDATE	0x448
 #define H_SCM_FLUSH		0x44C
 #define H_GET_ENERGY_SCALE_INFO	0x450
+#define H_PKS_SIGNED_UPDATE	0x454
 #define H_WATCHDOG		0x45C
 #define MAX_HCALL_OPCODE	H_WATCHDOG
 
diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index 7c5f51a9af7c..e7204e6c0ca4 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -68,6 +68,11 @@ struct plpks_var_name_list {
 	struct plpks_var_name varlist[];
 };
 
+/**
+ * Updates the authenticated variable. It expects NULL as the component.
+ */
+int plpks_signed_update_var(struct plpks_var *var, u64 flags);
+
 /**
  * Writes the specified var and its data to PKS.
  * Any caller of PKS driver should present a valid component type for
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 1189246b03dc..796ed5544ee5 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -81,6 +81,12 @@ static int pseries_status_to_err(int rc)
 		err = -ENOENT;
 		break;
 	case H_BUSY:
+	case H_LONG_BUSY_ORDER_1_MSEC:
+	case H_LONG_BUSY_ORDER_10_MSEC:
+	case H_LONG_BUSY_ORDER_100_MSEC:
+	case H_LONG_BUSY_ORDER_1_SEC:
+	case H_LONG_BUSY_ORDER_10_SEC:
+	case H_LONG_BUSY_ORDER_100_SEC:
 		err = -EBUSY;
 		break;
 	case H_AUTHORITY:
@@ -184,14 +190,17 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
 				     u16 namelen)
 {
 	struct label *label;
-	size_t slen;
+	size_t slen = 0;
 
 	if (!name || namelen > PLPKS_MAX_NAME_SIZE)
 		return ERR_PTR(-EINVAL);
 
-	slen = strlen(component);
-	if (component && slen > sizeof(label->attr.prefix))
-		return ERR_PTR(-EINVAL);
+	// Support NULL component for signed updates
+	if (component) {
+		slen = strlen(component);
+		if (slen > sizeof(label->attr.prefix))
+			return ERR_PTR(-EINVAL);
+	}
 
 	// The label structure must not cross a page boundary, so we align to the next power of 2
 	label = kzalloc(roundup_pow_of_two(sizeof(*label)), GFP_KERNEL);
@@ -397,6 +406,58 @@ static int plpks_confirm_object_flushed(struct label *label,
 	return pseries_status_to_err(rc);
 }
 
+int plpks_signed_update_var(struct plpks_var *var, u64 flags)
+{
+	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = {0};
+	int rc;
+	struct label *label;
+	struct plpks_auth *auth;
+	u64 continuetoken = 0;
+	u64 timeout = 0;
+
+	if (!var->data || var->datalen <= 0 || var->namelen > PLPKS_MAX_NAME_SIZE)
+		return -EINVAL;
+
+	if (!(var->policy & PLPKS_SIGNEDUPDATE))
+		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;
+	}
+
+	do {
+		rc = plpar_hcall9(H_PKS_SIGNED_UPDATE, retbuf,
+				  virt_to_phys(auth), virt_to_phys(label),
+				  label->size, var->policy, flags,
+				  virt_to_phys(var->data), var->datalen,
+				  continuetoken);
+
+		continuetoken = retbuf[0];
+		if (pseries_status_to_err(rc) == -EBUSY) {
+			int delay_ms = get_longbusy_msecs(rc);
+			mdelay(delay_ms);
+			timeout += delay_ms;
+		}
+		rc = pseries_status_to_err(rc);
+	} while (rc == -EBUSY && timeout < PLPKS_MAX_TIMEOUT);
+
+	if (!rc)
+		rc = plpks_confirm_object_flushed(label, auth);
+
+	kfree(label);
+out:
+	kfree(auth);
+
+	return rc;
+}
+EXPORT_SYMBOL(plpks_signed_update_var);
+
 int plpks_write_var(struct plpks_var var)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
@@ -443,7 +504,7 @@ int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname)
 	struct label *label;
 	int rc;
 
-	if (!component || vname.namelen > PLPKS_MAX_NAME_SIZE)
+	if (vname.namelen > PLPKS_MAX_NAME_SIZE)
 		return -EINVAL;
 
 	auth = construct_auth(PLPKS_OS_OWNER);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 17/24] powerpc/pseries: Log hcall return codes for PLPKS debug
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:42   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

The plpks code converts hypervisor return codes into their Linux
equivalents so that users can understand them.  Having access to the
original return codes is really useful for debugging, so add a
pr_debug() so we don't lose information from the conversion.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
---
 arch/powerpc/platforms/pseries/plpks.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 796ed5544ee5..96a026a37285 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -117,6 +117,8 @@ static int pseries_status_to_err(int rc)
 		err = -EINVAL;
 	}
 
+	pr_debug("Converted hypervisor code %d to Linux %d\n", rc, err);
+
 	return err;
 }
 
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 17/24] powerpc/pseries: Log hcall return codes for PLPKS debug
@ 2023-01-20  7:42   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:42 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

The plpks code converts hypervisor return codes into their Linux
equivalents so that users can understand them.  Having access to the
original return codes is really useful for debugging, so add a
pr_debug() so we don't lose information from the conversion.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
---
 arch/powerpc/platforms/pseries/plpks.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 796ed5544ee5..96a026a37285 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -117,6 +117,8 @@ static int pseries_status_to_err(int rc)
 		err = -EINVAL;
 	}
 
+	pr_debug("Converted hypervisor code %d to Linux %d\n", rc, err);
+
 	return err;
 }
 
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 18/24] powerpc/pseries: Make caller pass buffer to plpks_read_var()
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:43   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

Currently, plpks_read_var() allocates a buffer to pass to the
H_PKS_READ_OBJECT hcall, then allocates another buffer, of the caller's
preferred size if necessary, into which the data is copied, and returns
that buffer to the caller.

This is a bit over the top - while we probably still want to allocate a
separate buffer to pass to the hypervisor in the hcall, we can let the
caller allocate the final buffer and specify the size.

Don't allocate var->data in plpks_read_var(), instead expect the caller to
allocate it. If the caller needs to discover the size, it can set
var->data to NULL and var->datalen will be populated. Update header file
to document this.

Suggested-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch (mpe)
---
 arch/powerpc/include/asm/plpks.h       | 12 ++++++++++++
 arch/powerpc/platforms/pseries/plpks.c | 11 ++++-------
 2 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index e7204e6c0ca4..0c49969b0864 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -88,16 +88,28 @@ int plpks_remove_var(char *component, u8 varos,
 
 /**
  * Returns the data for the specified os variable.
+ *
+ * Caller must allocate a buffer in var->data with length in var->datalen.
+ * If no buffer is provided, var->datalen will be populated with the object's
+ * size.
  */
 int plpks_read_os_var(struct plpks_var *var);
 
 /**
  * Returns the data for the specified firmware variable.
+ *
+ * Caller must allocate a buffer in var->data with length in var->datalen.
+ * If no buffer is provided, var->datalen will be populated with the object's
+ * size.
  */
 int plpks_read_fw_var(struct plpks_var *var);
 
 /**
  * Returns the data for the specified bootloader variable.
+ *
+ * Caller must allocate a buffer in var->data with length in var->datalen.
+ * If no buffer is provided, var->datalen will be populated with the object's
+ * size.
  */
 int plpks_read_bootloader_var(struct plpks_var *var);
 
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 96a026a37285..5d9c6a3b2014 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -578,17 +578,14 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
 		goto out_free_output;
 	}
 
-	if (var->datalen == 0 || var->datalen > retbuf[0])
+	if (!var->data || var->datalen > retbuf[0])
 		var->datalen = retbuf[0];
 
-	var->data = kzalloc(var->datalen, GFP_KERNEL);
-	if (!var->data) {
-		rc = -ENOMEM;
-		goto out_free_output;
-	}
 	var->policy = retbuf[1];
 
-	memcpy(var->data, output, var->datalen);
+	if (var->data)
+		memcpy(var->data, output, var->datalen);
+
 	rc = 0;
 
 out_free_output:
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 18/24] powerpc/pseries: Make caller pass buffer to plpks_read_var()
@ 2023-01-20  7:43   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

Currently, plpks_read_var() allocates a buffer to pass to the
H_PKS_READ_OBJECT hcall, then allocates another buffer, of the caller's
preferred size if necessary, into which the data is copied, and returns
that buffer to the caller.

This is a bit over the top - while we probably still want to allocate a
separate buffer to pass to the hypervisor in the hcall, we can let the
caller allocate the final buffer and specify the size.

Don't allocate var->data in plpks_read_var(), instead expect the caller to
allocate it. If the caller needs to discover the size, it can set
var->data to NULL and var->datalen will be populated. Update header file
to document this.

Suggested-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch (mpe)
---
 arch/powerpc/include/asm/plpks.h       | 12 ++++++++++++
 arch/powerpc/platforms/pseries/plpks.c | 11 ++++-------
 2 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index e7204e6c0ca4..0c49969b0864 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -88,16 +88,28 @@ int plpks_remove_var(char *component, u8 varos,
 
 /**
  * Returns the data for the specified os variable.
+ *
+ * Caller must allocate a buffer in var->data with length in var->datalen.
+ * If no buffer is provided, var->datalen will be populated with the object's
+ * size.
  */
 int plpks_read_os_var(struct plpks_var *var);
 
 /**
  * Returns the data for the specified firmware variable.
+ *
+ * Caller must allocate a buffer in var->data with length in var->datalen.
+ * If no buffer is provided, var->datalen will be populated with the object's
+ * size.
  */
 int plpks_read_fw_var(struct plpks_var *var);
 
 /**
  * Returns the data for the specified bootloader variable.
+ *
+ * Caller must allocate a buffer in var->data with length in var->datalen.
+ * If no buffer is provided, var->datalen will be populated with the object's
+ * size.
  */
 int plpks_read_bootloader_var(struct plpks_var *var);
 
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 96a026a37285..5d9c6a3b2014 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -578,17 +578,14 @@ static int plpks_read_var(u8 consumer, struct plpks_var *var)
 		goto out_free_output;
 	}
 
-	if (var->datalen == 0 || var->datalen > retbuf[0])
+	if (!var->data || var->datalen > retbuf[0])
 		var->datalen = retbuf[0];
 
-	var->data = kzalloc(var->datalen, GFP_KERNEL);
-	if (!var->data) {
-		rc = -ENOMEM;
-		goto out_free_output;
-	}
 	var->policy = retbuf[1];
 
-	memcpy(var->data, output, var->datalen);
+	if (var->data)
+		memcpy(var->data, output, var->datalen);
+
 	rc = 0;
 
 out_free_output:
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 19/24] powerpc/pseries: Turn PSERIES_PLPKS into a hidden option
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:43   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

It seems a bit unnecessary for the PLPKS code to have a user-visible
config option when it doesn't do anything on its own, and there's existing
options for enabling Secure Boot-related features.

It should be enabled by PPC_SECURE_BOOT, which will eventually be what
uses PLPKS to populate keyrings.

However, we can't get of the separate option completely, because it will
also be used for SED Opal purposes.

Change PSERIES_PLPKS into a hidden option, which is selected by
PPC_SECURE_BOOT.

Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch
---
 arch/powerpc/Kconfig                   |  1 +
 arch/powerpc/platforms/pseries/Kconfig | 11 +----------
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index b8c4ac56bddc..d4ed46101bec 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1029,6 +1029,7 @@ config PPC_SECURE_BOOT
 	depends on PPC_POWERNV || PPC_PSERIES
 	depends on IMA_ARCH_POLICY
 	imply IMA_SECURE_AND_OR_TRUSTED_BOOT
+	select PSERIES_PLPKS if PPC_PSERIES
 	help
 	  Systems with firmware secure boot enabled need to define security
 	  policies to extend secure boot to the OS. This config allows a user
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index a3b4d99567cb..82b6f993be0f 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -151,16 +151,7 @@ config IBMEBUS
 
 config PSERIES_PLPKS
 	depends on PPC_PSERIES
-	bool "Support for the Platform Key Storage"
-	help
-	  PowerVM provides an isolated Platform Keystore(PKS) storage
-	  allocation for each LPAR with individually managed access
-	  controls to store sensitive information securely. It can be
-	  used to store asymmetric public keys or secrets as required
-	  by different usecases. Select this config to enable
-	  operating system interface to hypervisor to access this space.
-
-	  If unsure, select N.
+	bool
 
 config PAPR_SCM
 	depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 19/24] powerpc/pseries: Turn PSERIES_PLPKS into a hidden option
@ 2023-01-20  7:43   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

It seems a bit unnecessary for the PLPKS code to have a user-visible
config option when it doesn't do anything on its own, and there's existing
options for enabling Secure Boot-related features.

It should be enabled by PPC_SECURE_BOOT, which will eventually be what
uses PLPKS to populate keyrings.

However, we can't get of the separate option completely, because it will
also be used for SED Opal purposes.

Change PSERIES_PLPKS into a hidden option, which is selected by
PPC_SECURE_BOOT.

Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v3: New patch
---
 arch/powerpc/Kconfig                   |  1 +
 arch/powerpc/platforms/pseries/Kconfig | 11 +----------
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index b8c4ac56bddc..d4ed46101bec 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1029,6 +1029,7 @@ config PPC_SECURE_BOOT
 	depends on PPC_POWERNV || PPC_PSERIES
 	depends on IMA_ARCH_POLICY
 	imply IMA_SECURE_AND_OR_TRUSTED_BOOT
+	select PSERIES_PLPKS if PPC_PSERIES
 	help
 	  Systems with firmware secure boot enabled need to define security
 	  policies to extend secure boot to the OS. This config allows a user
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index a3b4d99567cb..82b6f993be0f 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -151,16 +151,7 @@ config IBMEBUS
 
 config PSERIES_PLPKS
 	depends on PPC_PSERIES
-	bool "Support for the Platform Key Storage"
-	help
-	  PowerVM provides an isolated Platform Keystore(PKS) storage
-	  allocation for each LPAR with individually managed access
-	  controls to store sensitive information securely. It can be
-	  used to store asymmetric public keys or secrets as required
-	  by different usecases. Select this config to enable
-	  operating system interface to hypervisor to access this space.
-
-	  If unsure, select N.
+	bool
 
 config PAPR_SCM
 	depends on PPC_PSERIES && MEMORY_HOTPLUG && LIBNVDIMM
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 20/24] powerpc/pseries: Add helpers to get PLPKS password
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:43   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

Add helper functions to get the PLPKS password. This will be used in a
later patch to support passing the password between kernels over kexec.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 arch/powerpc/include/asm/plpks.h       | 11 +++++++++++
 arch/powerpc/platforms/pseries/plpks.c | 10 ++++++++++
 2 files changed, 21 insertions(+)

diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index 0c49969b0864..08355c89f5fd 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -171,6 +171,17 @@ u32 plpks_get_maxlargeobjectsize(void);
  */
 u64 plpks_get_signedupdatealgorithms(void);
 
+/**
+ * Returns the PLPKS password generated by the hypervisor.
+ * Should only be used to prepare a different OS to use the PLPKS, i.e. kexec.
+ */
+u8 *plpks_get_password(void);
+
+/**
+ * Returns the length of the PLPKS password in bytes.
+ */
+u16 plpks_get_passwordlen(void);
+
 #endif // CONFIG_PSERIES_PLPKS
 
 #endif // _ASM_POWERPC_PLPKS_H
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 5d9c6a3b2014..b3c7410a4f13 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -359,6 +359,16 @@ u64 plpks_get_signedupdatealgorithms(void)
 	return signedupdatealgorithms;
 }
 
+u8 *plpks_get_password(void)
+{
+	return ospassword;
+}
+
+u16 plpks_get_passwordlen(void)
+{
+	return ospasswordlength;
+}
+
 bool plpks_is_available(void)
 {
 	int rc;
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 20/24] powerpc/pseries: Add helpers to get PLPKS password
@ 2023-01-20  7:43   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

Add helper functions to get the PLPKS password. This will be used in a
later patch to support passing the password between kernels over kexec.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 arch/powerpc/include/asm/plpks.h       | 11 +++++++++++
 arch/powerpc/platforms/pseries/plpks.c | 10 ++++++++++
 2 files changed, 21 insertions(+)

diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
index 0c49969b0864..08355c89f5fd 100644
--- a/arch/powerpc/include/asm/plpks.h
+++ b/arch/powerpc/include/asm/plpks.h
@@ -171,6 +171,17 @@ u32 plpks_get_maxlargeobjectsize(void);
  */
 u64 plpks_get_signedupdatealgorithms(void);
 
+/**
+ * Returns the PLPKS password generated by the hypervisor.
+ * Should only be used to prepare a different OS to use the PLPKS, i.e. kexec.
+ */
+u8 *plpks_get_password(void);
+
+/**
+ * Returns the length of the PLPKS password in bytes.
+ */
+u16 plpks_get_passwordlen(void);
+
 #endif // CONFIG_PSERIES_PLPKS
 
 #endif // _ASM_POWERPC_PLPKS_H
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index 5d9c6a3b2014..b3c7410a4f13 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -359,6 +359,16 @@ u64 plpks_get_signedupdatealgorithms(void)
 	return signedupdatealgorithms;
 }
 
+u8 *plpks_get_password(void)
+{
+	return ospassword;
+}
+
+u16 plpks_get_passwordlen(void)
+{
+	return ospasswordlength;
+}
+
 bool plpks_is_available(void)
 {
 	int rc;
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:43   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

Before interacting with the PLPKS, we ask the hypervisor to generate a
password for the current boot, which is then required for most further
PLPKS operations.

If we kexec into a new kernel, the new kernel will try and fail to
generate a new password, as the password has already been set.

Pass the password through to the new kernel via the device tree, in
/chosen/plpks-pw. Check for the presence of this property before trying
to generate a new password - if it exists, use the existing password and
remove it from the device tree.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch

v4: Fix compile when CONFIG_PSERIES_PLPKS=n (snowpatch)

    Fix error handling on fdt_path_offset() call (ruscur)
---
 arch/powerpc/kexec/file_load_64.c      | 18 ++++++++++++++++++
 arch/powerpc/platforms/pseries/plpks.c | 18 +++++++++++++++++-
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c
index af8854f9eae3..0c9130af60cc 100644
--- a/arch/powerpc/kexec/file_load_64.c
+++ b/arch/powerpc/kexec/file_load_64.c
@@ -27,6 +27,7 @@
 #include <asm/kexec_ranges.h>
 #include <asm/crashdump-ppc64.h>
 #include <asm/prom.h>
+#include <asm/plpks.h>
 
 struct umem_info {
 	u64 *buf;		/* data buffer for usable-memory property */
@@ -1156,6 +1157,9 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
 {
 	struct crash_mem *umem = NULL, *rmem = NULL;
 	int i, nr_ranges, ret;
+#ifdef CONFIG_PSERIES_PLPKS
+	int chosen_offset;
+#endif
 
 	/*
 	 * Restrict memory usage for kdump kernel by setting up
@@ -1230,6 +1234,20 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
 		}
 	}
 
+#ifdef CONFIG_PSERIES_PLPKS
+	// If we have PLPKS active, we need to provide the password
+	if (plpks_is_available()) {
+		chosen_offset = fdt_path_offset(fdt, "/chosen");
+		if (chosen_offset < 0) {
+			pr_err("Can't find chosen node: %s\n",
+			       fdt_strerror(chosen_offset));
+			goto out;
+		}
+		ret = fdt_setprop(fdt, chosen_offset, "ibm,plpks-pw",
+				  plpks_get_password(), plpks_get_passwordlen());
+	}
+#endif // CONFIG_PSERIES_PLPKS
+
 out:
 	kfree(rmem);
 	kfree(umem);
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index b3c7410a4f13..0350f10e1755 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/of.h>
 #include <asm/hvcall.h>
 #include <asm/machdep.h>
 #include <asm/plpks.h>
@@ -126,7 +127,22 @@ static int plpks_gen_password(void)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
 	u8 *password, consumer = PLPKS_OS_OWNER;
-	int rc;
+	struct property *prop;
+	int rc, len;
+
+	// Before we generate the password, we may have been booted by kexec and
+	// provided with a previous password.  Check for that first.
+	prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
+	if (prop) {
+		ospasswordlength = (u16)len;
+		ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
+		if (!ospassword) {
+			of_remove_property(of_chosen, prop);
+			return -ENOMEM;
+		}
+		memcpy(ospassword, prop->value, len);
+		return of_remove_property(of_chosen, prop);
+	}
 
 	// The password must not cross a page boundary, so we align to the next power of 2
 	password = kzalloc(roundup_pow_of_two(maxpwsize), GFP_KERNEL);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
@ 2023-01-20  7:43   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

Before interacting with the PLPKS, we ask the hypervisor to generate a
password for the current boot, which is then required for most further
PLPKS operations.

If we kexec into a new kernel, the new kernel will try and fail to
generate a new password, as the password has already been set.

Pass the password through to the new kernel via the device tree, in
/chosen/plpks-pw. Check for the presence of this property before trying
to generate a new password - if it exists, use the existing password and
remove it from the device tree.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch

v4: Fix compile when CONFIG_PSERIES_PLPKS=n (snowpatch)

    Fix error handling on fdt_path_offset() call (ruscur)
---
 arch/powerpc/kexec/file_load_64.c      | 18 ++++++++++++++++++
 arch/powerpc/platforms/pseries/plpks.c | 18 +++++++++++++++++-
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c
index af8854f9eae3..0c9130af60cc 100644
--- a/arch/powerpc/kexec/file_load_64.c
+++ b/arch/powerpc/kexec/file_load_64.c
@@ -27,6 +27,7 @@
 #include <asm/kexec_ranges.h>
 #include <asm/crashdump-ppc64.h>
 #include <asm/prom.h>
+#include <asm/plpks.h>
 
 struct umem_info {
 	u64 *buf;		/* data buffer for usable-memory property */
@@ -1156,6 +1157,9 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
 {
 	struct crash_mem *umem = NULL, *rmem = NULL;
 	int i, nr_ranges, ret;
+#ifdef CONFIG_PSERIES_PLPKS
+	int chosen_offset;
+#endif
 
 	/*
 	 * Restrict memory usage for kdump kernel by setting up
@@ -1230,6 +1234,20 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
 		}
 	}
 
+#ifdef CONFIG_PSERIES_PLPKS
+	// If we have PLPKS active, we need to provide the password
+	if (plpks_is_available()) {
+		chosen_offset = fdt_path_offset(fdt, "/chosen");
+		if (chosen_offset < 0) {
+			pr_err("Can't find chosen node: %s\n",
+			       fdt_strerror(chosen_offset));
+			goto out;
+		}
+		ret = fdt_setprop(fdt, chosen_offset, "ibm,plpks-pw",
+				  plpks_get_password(), plpks_get_passwordlen());
+	}
+#endif // CONFIG_PSERIES_PLPKS
+
 out:
 	kfree(rmem);
 	kfree(umem);
diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
index b3c7410a4f13..0350f10e1755 100644
--- a/arch/powerpc/platforms/pseries/plpks.c
+++ b/arch/powerpc/platforms/pseries/plpks.c
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/of.h>
 #include <asm/hvcall.h>
 #include <asm/machdep.h>
 #include <asm/plpks.h>
@@ -126,7 +127,22 @@ static int plpks_gen_password(void)
 {
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
 	u8 *password, consumer = PLPKS_OS_OWNER;
-	int rc;
+	struct property *prop;
+	int rc, len;
+
+	// Before we generate the password, we may have been booted by kexec and
+	// provided with a previous password.  Check for that first.
+	prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
+	if (prop) {
+		ospasswordlength = (u16)len;
+		ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
+		if (!ospassword) {
+			of_remove_property(of_chosen, prop);
+			return -ENOMEM;
+		}
+		memcpy(ospassword, prop->value, len);
+		return of_remove_property(of_chosen, prop);
+	}
 
 	// The password must not cross a page boundary, so we align to the next power of 2
 	password = kzalloc(roundup_pow_of_two(maxpwsize), GFP_KERNEL);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:43   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

The pseries platform can support dynamic secure boot (i.e. secure boot
using user-defined keys) using variables contained with the PowerVM LPAR
Platform KeyStore (PLPKS).  Using the powerpc secvar API, expose the
relevant variables for pseries dynamic secure boot through the existing
secvar filesystem layout.

The relevant variables for dynamic secure boot are signed in the
keystore, and can only be modified using the H_PKS_SIGNED_UPDATE hcall.
Object labels in the keystore are encoded using ucs2 format.  With our
fixed variable names we don't have to care about encoding outside of the
necessary byte padding.

When a user writes to a variable, the first 8 bytes of data must contain
the signed update flags as defined by the hypervisor.

When a user reads a variable, the first 4 bytes of data contain the
policies defined for the object.

Limitations exist due to the underlying implementation of sysfs binary
attributes, as is the case for the OPAL secvar implementation -
partial writes are unsupported and writes cannot be larger than PAGE_SIZE.
(Even when using bin_attributes, which can be larger than a single page,
sysfs only gives us one page's worth of write buffer at a time, and the
hypervisor does not expose an interface for partial writes.)

Co-developed-by: Nayna Jain <nayna@linux.ibm.com>
Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v2: Remove unnecessary config vars from sysfs and document the others,
    thanks to review from Greg.  If we end up needing to expose more, we
    can add them later and update the docs.

    Use sysfs_emit() instead of sprintf(), thanks to Greg.

    Change the size of the sysfs binary attributes to include the 8-byte
    flags header, preventing truncation of large writes.

v3: plpks_set_variable(): pass var to plpks_signed_update_var() as a
    pointer (mpe)

    Update copyright date (ajd)

    Consistent comment style (ajd)

    Change device_initcall() to machine_arch_initcall(pseries...) so we
    don't try to load on powernv and kill the machine (mpe)

    Add config attributes into plpks_secvar_ops (mpe)

    Get rid of PLPKS_SECVAR_COUNT macro (mpe)

    Reworded descriptions in ABI documentation (mpe)

    Switch to using secvar_ops->var_names rather than
    secvar_ops->get_next() (ajd/mpe)

    Optimise allocation/copying of buffers (mpe)

    Elaborate the comment documenting the "format" string (mpe)

    Return -EIO on errors in the read case (mpe)

    Add "grubdbx" variable (Sudhakar Kuppusamy)

    Use utf8s_to_utf16s() rather than our own "UCS-2" conversion code (mpe)

    Change uint64_t to u64 (mpe)

    Fix SB_VERSION data length (ruscur)

    Stop prepending policy data on read (ruscur)

    Enforce max format length on format string (not strictly needed, but
    makes the length limit clear) (ajd)

    Update include of plpks.h to reflect new path (ruscur)

    Consistent constant naming scheme (ruscur)

v4: Return set_secvar_ops() return code

    Pass buffer size to plpks_secvar_format() (stefanb, npiggin)

    Add missing null check (stefanb)

    Add comment to commit message explaining PAGE_SIZE write limit (joel)
---
 Documentation/ABI/testing/sysfs-secvar        |  75 +++++-
 arch/powerpc/platforms/pseries/Makefile       |   4 +-
 arch/powerpc/platforms/pseries/plpks-secvar.c | 215 ++++++++++++++++++
 3 files changed, 291 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks-secvar.c

diff --git a/Documentation/ABI/testing/sysfs-secvar b/Documentation/ABI/testing/sysfs-secvar
index feebb8c57294..a19f4d5fcec6 100644
--- a/Documentation/ABI/testing/sysfs-secvar
+++ b/Documentation/ABI/testing/sysfs-secvar
@@ -18,6 +18,14 @@ Description:	A string indicating which backend is in use by the firmware.
 		This determines the format of the variable and the accepted
 		format of variable updates.
 
+		On powernv/OPAL, this value is provided by the OPAL firmware
+		and is expected to be "ibm,edk2-compat-v1".
+
+		On pseries/PLPKS, this is generated by the kernel based on the
+		version number in the SB_VERSION variable in the keystore, and
+		has the form "ibm,plpks-sb-v<version>", or
+		"ibm,plpks-sb-unknown" if there is no SB_VERSION variable.
+
 What:		/sys/firmware/secvar/vars/<variable name>
 Date:		August 2019
 Contact:	Nayna Jain <nayna@linux.ibm.com>
@@ -34,7 +42,7 @@ Description:	An integer representation of the size of the content of the
 
 What:		/sys/firmware/secvar/vars/<variable_name>/data
 Date:		August 2019
-Contact:	Nayna Jain h<nayna@linux.ibm.com>
+Contact:	Nayna Jain <nayna@linux.ibm.com>
 Description:	A read-only file containing the value of the variable. The size
 		of the file represents the maximum size of the variable data.
 
@@ -44,3 +52,68 @@ Contact:	Nayna Jain <nayna@linux.ibm.com>
 Description:	A write-only file that is used to submit the new value for the
 		variable. The size of the file represents the maximum size of
 		the variable data that can be written.
+
+What:		/sys/firmware/secvar/config
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	This optional directory contains read-only config attributes as
+		defined by the secure variable implementation.  All data is in
+		ASCII format. The directory is only created if the backing
+		implementation provides variables to populate it, which at
+		present is only PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/version
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Config version as reported by the hypervisor in ASCII decimal
+		format.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/max_object_size
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Maximum allowed size of	objects in the keystore in bytes,
+		represented in ASCII decimal format.
+
+		This is not necessarily the same as the max size that can be
+		written to an update file as writes can contain more than
+		object data, you should use the size of the update file for
+		that purpose.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/total_size
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Total size of the PLPKS in bytes, represented in ASCII decimal
+		format.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/used_space
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Current space consumed by the key store, in bytes, represented
+		in ASCII decimal format.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/supported_policies
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Bitmask of supported policy flags by the hypervisor,
+		represented as an 8 byte hexadecimal ASCII string. Consult the
+		hypervisor documentation for what these flags are.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/signed_update_algorithms
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Bitmask of flags indicating which algorithms the hypervisor
+		supports for signed update of objects, represented as a 16 byte
+		hexadecimal ASCII string. Consult the hypervisor documentation
+		for what these flags mean.
+
+		Currently only provided by PLPKS on the pseries platform.
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 92310202bdd7..d52b7ec1a678 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -27,8 +27,8 @@ obj-$(CONFIG_PAPR_SCM)		+= papr_scm.o
 obj-$(CONFIG_PPC_SPLPAR)	+= vphn.o
 obj-$(CONFIG_PPC_SVM)		+= svm.o
 obj-$(CONFIG_FA_DUMP)		+= rtas-fadump.o
-obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
-
+obj-$(CONFIG_PSERIES_PLPKS)	+= plpks.o
+obj-$(CONFIG_PPC_SECVAR_SYSFS)	+= plpks-secvar.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_PPC_VAS)		+= vas.o vas-sysfs.o
 
diff --git a/arch/powerpc/platforms/pseries/plpks-secvar.c b/arch/powerpc/platforms/pseries/plpks-secvar.c
new file mode 100644
index 000000000000..a80d9f9469f9
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks-secvar.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+// Secure variable implementation using the PowerVM LPAR Platform KeyStore (PLPKS)
+//
+// Copyright 2022, 2023 IBM Corporation
+// Authors: Russell Currey
+//          Andrew Donnellan
+//          Nayna Jain
+
+#define pr_fmt(fmt) "secvar: "fmt
+
+#include <linux/printk.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/kobject.h>
+#include <linux/nls.h>
+#include <asm/machdep.h>
+#include <asm/secvar.h>
+#include <asm/plpks.h>
+
+// Config attributes for sysfs
+#define PLPKS_CONFIG_ATTR(name, fmt, func)			\
+	static ssize_t name##_show(struct kobject *kobj,	\
+				   struct kobj_attribute *attr,	\
+				   char *buf)			\
+	{							\
+		return sysfs_emit(buf, fmt, func());		\
+	}							\
+	static struct kobj_attribute attr_##name = __ATTR_RO(name)
+
+PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version);
+PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize);
+PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize);
+PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace);
+PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicies);
+PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms);
+
+static const struct attribute *config_attrs[] = {
+	&attr_version.attr,
+	&attr_max_object_size.attr,
+	&attr_total_size.attr,
+	&attr_used_space.attr,
+	&attr_supported_policies.attr,
+	&attr_signed_update_algorithms.attr,
+	NULL,
+};
+
+static u32 get_policy(const char *name)
+{
+	if ((strcmp(name, "db") == 0) ||
+	    (strcmp(name, "dbx") == 0) ||
+	    (strcmp(name, "grubdb") == 0) ||
+	    (strcmp(name, "grubdbx") == 0) ||
+	    (strcmp(name, "sbat") == 0))
+		return (PLPKS_WORLDREADABLE | PLPKS_SIGNEDUPDATE);
+	else
+		return PLPKS_SIGNEDUPDATE;
+}
+
+static const char * const plpks_var_names[] = {
+	"PK",
+	"KEK",
+	"db",
+	"dbx",
+	"grubdb",
+	"grubdbx",
+	"sbat",
+	"moduledb",
+	"trustedcadb",
+	NULL,
+};
+
+static int plpks_get_variable(const char *key, u64 key_len, u8 *data,
+			      u64 *data_size)
+{
+	struct plpks_var var = {0};
+	int rc = 0;
+
+	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
+	if (!var.name)
+		return -ENOMEM;
+	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
+			     key_len - 1);
+	if (rc < 0)
+		goto err;
+	var.namelen = rc * 2;
+
+	var.os = PLPKS_VAR_LINUX;
+	if (data) {
+		var.data = data;
+		var.datalen = *data_size;
+	}
+	rc = plpks_read_os_var(&var);
+
+	if (rc)
+		goto err;
+
+	*data_size = var.datalen;
+
+err:
+	kfree(var.name);
+	if (rc && rc != -ENOENT) {
+		pr_err("Failed to read variable '%s': %d\n", key, rc);
+		// Return -EIO since userspace probably doesn't care about the
+		// specific error
+		rc = -EIO;
+	}
+	return rc;
+}
+
+static int plpks_set_variable(const char *key, u64 key_len, u8 *data,
+			      u64 data_size)
+{
+	struct plpks_var var = {0};
+	int rc = 0;
+	u64 flags;
+
+	// Secure variables need to be prefixed with 8 bytes of flags.
+	// We only want to perform the write if we have at least one byte of data.
+	if (data_size <= sizeof(flags))
+		return -EINVAL;
+
+	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
+	if (!var.name)
+		return -ENOMEM;
+	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
+			     key_len - 1);
+	if (rc < 0)
+		goto err;
+	var.namelen = rc * 2;
+
+	memcpy(&flags, data, sizeof(flags));
+
+	var.datalen = data_size - sizeof(flags);
+	var.data = data + sizeof(flags);
+	var.os = PLPKS_VAR_LINUX;
+	var.policy = get_policy(key);
+
+	// Unlike in the read case, the plpks error code can be useful to
+	// userspace on write, so we return it rather than just -EIO
+	rc = plpks_signed_update_var(&var, flags);
+
+err:
+	kfree(var.name);
+	return rc;
+}
+
+// PLPKS dynamic secure boot doesn't give us a format string in the same way OPAL does.
+// Instead, report the format using the SB_VERSION variable in the keystore.
+static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
+{
+	struct plpks_var var = {0};
+	ssize_t ret;
+
+	var.component = NULL;
+	// Only the signed variables have null bytes in their names, this one doesn't
+	var.name = "SB_VERSION";
+	var.namelen = 10;
+	var.datalen = 1;
+	var.data = kzalloc(1, GFP_KERNEL);
+	if (!var.data)
+		return -ENOMEM;
+
+	// Unlike the other vars, SB_VERSION is owned by firmware instead of the OS
+	ret = plpks_read_fw_var(&var);
+	if (ret) {
+		if (ret == -ENOENT) {
+			ret = snprintf(buf, bufsize, "ibm,plpks-sb-unknown");
+		} else {
+			pr_err("Error %ld reading SB_VERSION from firmware\n", ret);
+			ret = -EIO;
+		}
+		goto err;
+	}
+
+	// This string is made up by us - the hypervisor doesn't provide us
+	// with a format string in the way that OPAL firmware does. Hypervisor
+	// defines SB_VERSION as a "1 byte unsigned integer value".
+	ret = snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu", var.data[0]);
+
+err:
+	kfree(var.data);
+	return ret;
+}
+
+static int plpks_max_size(u64 *max_size)
+{
+	// The max object size reported by the hypervisor is accurate for the
+	// object itself, but we use the first 8 bytes of data on write as the
+	// signed update flags, so the max size a user can write is larger.
+	*max_size = (u64)plpks_get_maxobjectsize() + 8;
+
+	return 0;
+}
+
+
+static const struct secvar_operations plpks_secvar_ops = {
+	.get = plpks_get_variable,
+	.set = plpks_set_variable,
+	.format = plpks_secvar_format,
+	.max_size = plpks_max_size,
+	.config_attrs = config_attrs,
+	.var_names = plpks_var_names,
+};
+
+static int plpks_secvar_init(void)
+{
+	if (!plpks_is_available())
+		return -ENODEV;
+
+	return set_secvar_ops(&plpks_secvar_ops);
+}
+machine_device_initcall(pseries, plpks_secvar_init);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
@ 2023-01-20  7:43   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

The pseries platform can support dynamic secure boot (i.e. secure boot
using user-defined keys) using variables contained with the PowerVM LPAR
Platform KeyStore (PLPKS).  Using the powerpc secvar API, expose the
relevant variables for pseries dynamic secure boot through the existing
secvar filesystem layout.

The relevant variables for dynamic secure boot are signed in the
keystore, and can only be modified using the H_PKS_SIGNED_UPDATE hcall.
Object labels in the keystore are encoded using ucs2 format.  With our
fixed variable names we don't have to care about encoding outside of the
necessary byte padding.

When a user writes to a variable, the first 8 bytes of data must contain
the signed update flags as defined by the hypervisor.

When a user reads a variable, the first 4 bytes of data contain the
policies defined for the object.

Limitations exist due to the underlying implementation of sysfs binary
attributes, as is the case for the OPAL secvar implementation -
partial writes are unsupported and writes cannot be larger than PAGE_SIZE.
(Even when using bin_attributes, which can be larger than a single page,
sysfs only gives us one page's worth of write buffer at a time, and the
hypervisor does not expose an interface for partial writes.)

Co-developed-by: Nayna Jain <nayna@linux.ibm.com>
Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
Signed-off-by: Russell Currey <ruscur@russell.cc>

---

v2: Remove unnecessary config vars from sysfs and document the others,
    thanks to review from Greg.  If we end up needing to expose more, we
    can add them later and update the docs.

    Use sysfs_emit() instead of sprintf(), thanks to Greg.

    Change the size of the sysfs binary attributes to include the 8-byte
    flags header, preventing truncation of large writes.

v3: plpks_set_variable(): pass var to plpks_signed_update_var() as a
    pointer (mpe)

    Update copyright date (ajd)

    Consistent comment style (ajd)

    Change device_initcall() to machine_arch_initcall(pseries...) so we
    don't try to load on powernv and kill the machine (mpe)

    Add config attributes into plpks_secvar_ops (mpe)

    Get rid of PLPKS_SECVAR_COUNT macro (mpe)

    Reworded descriptions in ABI documentation (mpe)

    Switch to using secvar_ops->var_names rather than
    secvar_ops->get_next() (ajd/mpe)

    Optimise allocation/copying of buffers (mpe)

    Elaborate the comment documenting the "format" string (mpe)

    Return -EIO on errors in the read case (mpe)

    Add "grubdbx" variable (Sudhakar Kuppusamy)

    Use utf8s_to_utf16s() rather than our own "UCS-2" conversion code (mpe)

    Change uint64_t to u64 (mpe)

    Fix SB_VERSION data length (ruscur)

    Stop prepending policy data on read (ruscur)

    Enforce max format length on format string (not strictly needed, but
    makes the length limit clear) (ajd)

    Update include of plpks.h to reflect new path (ruscur)

    Consistent constant naming scheme (ruscur)

v4: Return set_secvar_ops() return code

    Pass buffer size to plpks_secvar_format() (stefanb, npiggin)

    Add missing null check (stefanb)

    Add comment to commit message explaining PAGE_SIZE write limit (joel)
---
 Documentation/ABI/testing/sysfs-secvar        |  75 +++++-
 arch/powerpc/platforms/pseries/Makefile       |   4 +-
 arch/powerpc/platforms/pseries/plpks-secvar.c | 215 ++++++++++++++++++
 3 files changed, 291 insertions(+), 3 deletions(-)
 create mode 100644 arch/powerpc/platforms/pseries/plpks-secvar.c

diff --git a/Documentation/ABI/testing/sysfs-secvar b/Documentation/ABI/testing/sysfs-secvar
index feebb8c57294..a19f4d5fcec6 100644
--- a/Documentation/ABI/testing/sysfs-secvar
+++ b/Documentation/ABI/testing/sysfs-secvar
@@ -18,6 +18,14 @@ Description:	A string indicating which backend is in use by the firmware.
 		This determines the format of the variable and the accepted
 		format of variable updates.
 
+		On powernv/OPAL, this value is provided by the OPAL firmware
+		and is expected to be "ibm,edk2-compat-v1".
+
+		On pseries/PLPKS, this is generated by the kernel based on the
+		version number in the SB_VERSION variable in the keystore, and
+		has the form "ibm,plpks-sb-v<version>", or
+		"ibm,plpks-sb-unknown" if there is no SB_VERSION variable.
+
 What:		/sys/firmware/secvar/vars/<variable name>
 Date:		August 2019
 Contact:	Nayna Jain <nayna@linux.ibm.com>
@@ -34,7 +42,7 @@ Description:	An integer representation of the size of the content of the
 
 What:		/sys/firmware/secvar/vars/<variable_name>/data
 Date:		August 2019
-Contact:	Nayna Jain h<nayna@linux.ibm.com>
+Contact:	Nayna Jain <nayna@linux.ibm.com>
 Description:	A read-only file containing the value of the variable. The size
 		of the file represents the maximum size of the variable data.
 
@@ -44,3 +52,68 @@ Contact:	Nayna Jain <nayna@linux.ibm.com>
 Description:	A write-only file that is used to submit the new value for the
 		variable. The size of the file represents the maximum size of
 		the variable data that can be written.
+
+What:		/sys/firmware/secvar/config
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	This optional directory contains read-only config attributes as
+		defined by the secure variable implementation.  All data is in
+		ASCII format. The directory is only created if the backing
+		implementation provides variables to populate it, which at
+		present is only PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/version
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Config version as reported by the hypervisor in ASCII decimal
+		format.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/max_object_size
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Maximum allowed size of	objects in the keystore in bytes,
+		represented in ASCII decimal format.
+
+		This is not necessarily the same as the max size that can be
+		written to an update file as writes can contain more than
+		object data, you should use the size of the update file for
+		that purpose.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/total_size
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Total size of the PLPKS in bytes, represented in ASCII decimal
+		format.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/used_space
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Current space consumed by the key store, in bytes, represented
+		in ASCII decimal format.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/supported_policies
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Bitmask of supported policy flags by the hypervisor,
+		represented as an 8 byte hexadecimal ASCII string. Consult the
+		hypervisor documentation for what these flags are.
+
+		Currently only provided by PLPKS on the pseries platform.
+
+What:		/sys/firmware/secvar/config/signed_update_algorithms
+Date:		December 2022
+Contact:	Nayna Jain <nayna@linux.ibm.com>
+Description:	Bitmask of flags indicating which algorithms the hypervisor
+		supports for signed update of objects, represented as a 16 byte
+		hexadecimal ASCII string. Consult the hypervisor documentation
+		for what these flags mean.
+
+		Currently only provided by PLPKS on the pseries platform.
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 92310202bdd7..d52b7ec1a678 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -27,8 +27,8 @@ obj-$(CONFIG_PAPR_SCM)		+= papr_scm.o
 obj-$(CONFIG_PPC_SPLPAR)	+= vphn.o
 obj-$(CONFIG_PPC_SVM)		+= svm.o
 obj-$(CONFIG_FA_DUMP)		+= rtas-fadump.o
-obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
-
+obj-$(CONFIG_PSERIES_PLPKS)	+= plpks.o
+obj-$(CONFIG_PPC_SECVAR_SYSFS)	+= plpks-secvar.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_PPC_VAS)		+= vas.o vas-sysfs.o
 
diff --git a/arch/powerpc/platforms/pseries/plpks-secvar.c b/arch/powerpc/platforms/pseries/plpks-secvar.c
new file mode 100644
index 000000000000..a80d9f9469f9
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/plpks-secvar.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+// Secure variable implementation using the PowerVM LPAR Platform KeyStore (PLPKS)
+//
+// Copyright 2022, 2023 IBM Corporation
+// Authors: Russell Currey
+//          Andrew Donnellan
+//          Nayna Jain
+
+#define pr_fmt(fmt) "secvar: "fmt
+
+#include <linux/printk.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/kobject.h>
+#include <linux/nls.h>
+#include <asm/machdep.h>
+#include <asm/secvar.h>
+#include <asm/plpks.h>
+
+// Config attributes for sysfs
+#define PLPKS_CONFIG_ATTR(name, fmt, func)			\
+	static ssize_t name##_show(struct kobject *kobj,	\
+				   struct kobj_attribute *attr,	\
+				   char *buf)			\
+	{							\
+		return sysfs_emit(buf, fmt, func());		\
+	}							\
+	static struct kobj_attribute attr_##name = __ATTR_RO(name)
+
+PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version);
+PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize);
+PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize);
+PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace);
+PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicies);
+PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms);
+
+static const struct attribute *config_attrs[] = {
+	&attr_version.attr,
+	&attr_max_object_size.attr,
+	&attr_total_size.attr,
+	&attr_used_space.attr,
+	&attr_supported_policies.attr,
+	&attr_signed_update_algorithms.attr,
+	NULL,
+};
+
+static u32 get_policy(const char *name)
+{
+	if ((strcmp(name, "db") == 0) ||
+	    (strcmp(name, "dbx") == 0) ||
+	    (strcmp(name, "grubdb") == 0) ||
+	    (strcmp(name, "grubdbx") == 0) ||
+	    (strcmp(name, "sbat") == 0))
+		return (PLPKS_WORLDREADABLE | PLPKS_SIGNEDUPDATE);
+	else
+		return PLPKS_SIGNEDUPDATE;
+}
+
+static const char * const plpks_var_names[] = {
+	"PK",
+	"KEK",
+	"db",
+	"dbx",
+	"grubdb",
+	"grubdbx",
+	"sbat",
+	"moduledb",
+	"trustedcadb",
+	NULL,
+};
+
+static int plpks_get_variable(const char *key, u64 key_len, u8 *data,
+			      u64 *data_size)
+{
+	struct plpks_var var = {0};
+	int rc = 0;
+
+	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
+	if (!var.name)
+		return -ENOMEM;
+	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
+			     key_len - 1);
+	if (rc < 0)
+		goto err;
+	var.namelen = rc * 2;
+
+	var.os = PLPKS_VAR_LINUX;
+	if (data) {
+		var.data = data;
+		var.datalen = *data_size;
+	}
+	rc = plpks_read_os_var(&var);
+
+	if (rc)
+		goto err;
+
+	*data_size = var.datalen;
+
+err:
+	kfree(var.name);
+	if (rc && rc != -ENOENT) {
+		pr_err("Failed to read variable '%s': %d\n", key, rc);
+		// Return -EIO since userspace probably doesn't care about the
+		// specific error
+		rc = -EIO;
+	}
+	return rc;
+}
+
+static int plpks_set_variable(const char *key, u64 key_len, u8 *data,
+			      u64 data_size)
+{
+	struct plpks_var var = {0};
+	int rc = 0;
+	u64 flags;
+
+	// Secure variables need to be prefixed with 8 bytes of flags.
+	// We only want to perform the write if we have at least one byte of data.
+	if (data_size <= sizeof(flags))
+		return -EINVAL;
+
+	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
+	if (!var.name)
+		return -ENOMEM;
+	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
+			     key_len - 1);
+	if (rc < 0)
+		goto err;
+	var.namelen = rc * 2;
+
+	memcpy(&flags, data, sizeof(flags));
+
+	var.datalen = data_size - sizeof(flags);
+	var.data = data + sizeof(flags);
+	var.os = PLPKS_VAR_LINUX;
+	var.policy = get_policy(key);
+
+	// Unlike in the read case, the plpks error code can be useful to
+	// userspace on write, so we return it rather than just -EIO
+	rc = plpks_signed_update_var(&var, flags);
+
+err:
+	kfree(var.name);
+	return rc;
+}
+
+// PLPKS dynamic secure boot doesn't give us a format string in the same way OPAL does.
+// Instead, report the format using the SB_VERSION variable in the keystore.
+static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
+{
+	struct plpks_var var = {0};
+	ssize_t ret;
+
+	var.component = NULL;
+	// Only the signed variables have null bytes in their names, this one doesn't
+	var.name = "SB_VERSION";
+	var.namelen = 10;
+	var.datalen = 1;
+	var.data = kzalloc(1, GFP_KERNEL);
+	if (!var.data)
+		return -ENOMEM;
+
+	// Unlike the other vars, SB_VERSION is owned by firmware instead of the OS
+	ret = plpks_read_fw_var(&var);
+	if (ret) {
+		if (ret == -ENOENT) {
+			ret = snprintf(buf, bufsize, "ibm,plpks-sb-unknown");
+		} else {
+			pr_err("Error %ld reading SB_VERSION from firmware\n", ret);
+			ret = -EIO;
+		}
+		goto err;
+	}
+
+	// This string is made up by us - the hypervisor doesn't provide us
+	// with a format string in the way that OPAL firmware does. Hypervisor
+	// defines SB_VERSION as a "1 byte unsigned integer value".
+	ret = snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu", var.data[0]);
+
+err:
+	kfree(var.data);
+	return ret;
+}
+
+static int plpks_max_size(u64 *max_size)
+{
+	// The max object size reported by the hypervisor is accurate for the
+	// object itself, but we use the first 8 bytes of data on write as the
+	// signed update flags, so the max size a user can write is larger.
+	*max_size = (u64)plpks_get_maxobjectsize() + 8;
+
+	return 0;
+}
+
+
+static const struct secvar_operations plpks_secvar_ops = {
+	.get = plpks_get_variable,
+	.set = plpks_set_variable,
+	.format = plpks_secvar_format,
+	.max_size = plpks_max_size,
+	.config_attrs = config_attrs,
+	.var_names = plpks_var_names,
+};
+
+static int plpks_secvar_init(void)
+{
+	if (!plpks_is_available())
+		return -ENODEV;
+
+	return set_secvar_ops(&plpks_secvar_ops);
+}
+machine_device_initcall(pseries, plpks_secvar_init);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 23/24] integrity/powerpc: Improve error handling & reporting when loading certs
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:43   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

A few improvements to load_powerpc.c:

 - include integrity.h for the pr_fmt()
 - move all error reporting out of get_cert_list()
 - use ERR_PTR() to better preserve error detail
 - don't use pr_err() for missing keys

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 .../integrity/platform_certs/load_powerpc.c   | 26 ++++++++++++++-----
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
index 1e4f80a4e71c..dee51606d5f4 100644
--- a/security/integrity/platform_certs/load_powerpc.c
+++ b/security/integrity/platform_certs/load_powerpc.c
@@ -14,9 +14,15 @@
 #include <asm/secure_boot.h>
 #include <asm/secvar.h>
 #include "keyring_handler.h"
+#include "../integrity.h"
 
 /*
  * Get a certificate list blob from the named secure variable.
+ *
+ * Returns:
+ *  - a pointer to a kmalloc'd buffer containing the cert list on success
+ *  - NULL if the key does not exist
+ *  - an ERR_PTR on error
  */
 static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
 {
@@ -25,19 +31,19 @@ static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
 
 	rc = secvar_ops->get(key, keylen, NULL, size);
 	if (rc) {
-		pr_err("Couldn't get size: %d\n", rc);
-		return NULL;
+		if (rc == -ENOENT)
+			return NULL;
+		return ERR_PTR(rc);
 	}
 
 	db = kmalloc(*size, GFP_KERNEL);
 	if (!db)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	rc = secvar_ops->get(key, keylen, db, size);
 	if (rc) {
 		kfree(db);
-		pr_err("Error reading %s var: %d\n", key, rc);
-		return NULL;
+		return ERR_PTR(rc);
 	}
 
 	return db;
@@ -69,7 +75,11 @@ static int __init load_powerpc_certs(void)
 	 */
 	db = get_cert_list("db", 3, &dbsize);
 	if (!db) {
-		pr_err("Couldn't get db list from firmware\n");
+		pr_info("Couldn't get db list from firmware\n");
+	} else if (IS_ERR(db)) {
+		rc = PTR_ERR(db);
+		pr_err("Error reading db from firmware: %d\n", rc);
+		return rc;
 	} else {
 		rc = parse_efi_signature_list("powerpc:db", db, dbsize,
 					      get_handler_for_db);
@@ -81,6 +91,10 @@ static int __init load_powerpc_certs(void)
 	dbx = get_cert_list("dbx", 4,  &dbxsize);
 	if (!dbx) {
 		pr_info("Couldn't get dbx list from firmware\n");
+	} else if (IS_ERR(dbx)) {
+		rc = PTR_ERR(dbx);
+		pr_err("Error reading dbx from firmware: %d\n", rc);
+		return rc;
 	} else {
 		rc = parse_efi_signature_list("powerpc:dbx", dbx, dbxsize,
 					      get_handler_for_dbx);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 23/24] integrity/powerpc: Improve error handling & reporting when loading certs
@ 2023-01-20  7:43   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

A few improvements to load_powerpc.c:

 - include integrity.h for the pr_fmt()
 - move all error reporting out of get_cert_list()
 - use ERR_PTR() to better preserve error detail
 - don't use pr_err() for missing keys

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch
---
 .../integrity/platform_certs/load_powerpc.c   | 26 ++++++++++++++-----
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
index 1e4f80a4e71c..dee51606d5f4 100644
--- a/security/integrity/platform_certs/load_powerpc.c
+++ b/security/integrity/platform_certs/load_powerpc.c
@@ -14,9 +14,15 @@
 #include <asm/secure_boot.h>
 #include <asm/secvar.h>
 #include "keyring_handler.h"
+#include "../integrity.h"
 
 /*
  * Get a certificate list blob from the named secure variable.
+ *
+ * Returns:
+ *  - a pointer to a kmalloc'd buffer containing the cert list on success
+ *  - NULL if the key does not exist
+ *  - an ERR_PTR on error
  */
 static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
 {
@@ -25,19 +31,19 @@ static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
 
 	rc = secvar_ops->get(key, keylen, NULL, size);
 	if (rc) {
-		pr_err("Couldn't get size: %d\n", rc);
-		return NULL;
+		if (rc == -ENOENT)
+			return NULL;
+		return ERR_PTR(rc);
 	}
 
 	db = kmalloc(*size, GFP_KERNEL);
 	if (!db)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	rc = secvar_ops->get(key, keylen, db, size);
 	if (rc) {
 		kfree(db);
-		pr_err("Error reading %s var: %d\n", key, rc);
-		return NULL;
+		return ERR_PTR(rc);
 	}
 
 	return db;
@@ -69,7 +75,11 @@ static int __init load_powerpc_certs(void)
 	 */
 	db = get_cert_list("db", 3, &dbsize);
 	if (!db) {
-		pr_err("Couldn't get db list from firmware\n");
+		pr_info("Couldn't get db list from firmware\n");
+	} else if (IS_ERR(db)) {
+		rc = PTR_ERR(db);
+		pr_err("Error reading db from firmware: %d\n", rc);
+		return rc;
 	} else {
 		rc = parse_efi_signature_list("powerpc:db", db, dbsize,
 					      get_handler_for_db);
@@ -81,6 +91,10 @@ static int __init load_powerpc_certs(void)
 	dbx = get_cert_list("dbx", 4,  &dbxsize);
 	if (!dbx) {
 		pr_info("Couldn't get dbx list from firmware\n");
+	} else if (IS_ERR(dbx)) {
+		rc = PTR_ERR(dbx);
+		pr_err("Error reading dbx from firmware: %d\n", rc);
+		return rc;
 	} else {
 		rc = parse_efi_signature_list("powerpc:dbx", dbx, dbxsize,
 					      get_handler_for_dbx);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
  2023-01-20  7:42 ` Andrew Donnellan
@ 2023-01-20  7:43   ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, mpe,
	gjoyce, sudhakar, bgray, erichte, joel

From: Russell Currey <ruscur@russell.cc>

The secvar object format is only in the device tree under powernv.
We now have an API call to retrieve it in a generic way, so we should
use that instead of having to handle the DT here.

Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
The object format is expected to be the same, so there shouldn't be any
functional differences between objects retrieved from powernv and
pseries.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch

v4: Pass format buffer size (stefanb, npiggin)
---
 .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
index dee51606d5f4..d4ce91bf3fec 100644
--- a/security/integrity/platform_certs/load_powerpc.c
+++ b/security/integrity/platform_certs/load_powerpc.c
@@ -10,7 +10,6 @@
 #include <linux/cred.h>
 #include <linux/err.h>
 #include <linux/slab.h>
-#include <linux/of.h>
 #include <asm/secure_boot.h>
 #include <asm/secvar.h>
 #include "keyring_handler.h"
@@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
 	void *db = NULL, *dbx = NULL;
 	u64 dbsize = 0, dbxsize = 0;
 	int rc = 0;
-	struct device_node *node;
+	ssize_t len;
+	char buf[32];
 
 	if (!secvar_ops)
 		return -ENODEV;
 
-	/* The following only applies for the edk2-compat backend. */
-	node = of_find_compatible_node(NULL, NULL, "ibm,edk2-compat-v1");
-	if (!node)
+	len = secvar_ops->format(buf, 32);
+	if (len <= 0)
 		return -ENODEV;
 
+	// Check for known secure boot implementations from OPAL or PLPKS
+	if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-sb-v1", buf)) {
+		pr_err("Unsupported secvar implementation \"%s\", not loading certs\n", buf);
+		return -ENODEV;
+	}
+
 	/*
 	 * Get db, and dbx. They might not exist, so it isn't an error if we
 	 * can't get them.
@@ -103,8 +108,6 @@ static int __init load_powerpc_certs(void)
 		kfree(dbx);
 	}
 
-	of_node_put(node);
-
 	return rc;
 }
 late_initcall(load_powerpc_certs);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
@ 2023-01-20  7:43   ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-20  7:43 UTC (permalink / raw)
  To: linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

From: Russell Currey <ruscur@russell.cc>

The secvar object format is only in the device tree under powernv.
We now have an API call to retrieve it in a generic way, so we should
use that instead of having to handle the DT here.

Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
The object format is expected to be the same, so there shouldn't be any
functional differences between objects retrieved from powernv and
pseries.

Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

---

v3: New patch

v4: Pass format buffer size (stefanb, npiggin)
---
 .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
index dee51606d5f4..d4ce91bf3fec 100644
--- a/security/integrity/platform_certs/load_powerpc.c
+++ b/security/integrity/platform_certs/load_powerpc.c
@@ -10,7 +10,6 @@
 #include <linux/cred.h>
 #include <linux/err.h>
 #include <linux/slab.h>
-#include <linux/of.h>
 #include <asm/secure_boot.h>
 #include <asm/secvar.h>
 #include "keyring_handler.h"
@@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
 	void *db = NULL, *dbx = NULL;
 	u64 dbsize = 0, dbxsize = 0;
 	int rc = 0;
-	struct device_node *node;
+	ssize_t len;
+	char buf[32];
 
 	if (!secvar_ops)
 		return -ENODEV;
 
-	/* The following only applies for the edk2-compat backend. */
-	node = of_find_compatible_node(NULL, NULL, "ibm,edk2-compat-v1");
-	if (!node)
+	len = secvar_ops->format(buf, 32);
+	if (len <= 0)
 		return -ENODEV;
 
+	// Check for known secure boot implementations from OPAL or PLPKS
+	if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-sb-v1", buf)) {
+		pr_err("Unsupported secvar implementation \"%s\", not loading certs\n", buf);
+		return -ENODEV;
+	}
+
 	/*
 	 * Get db, and dbx. They might not exist, so it isn't an error if we
 	 * can't get them.
@@ -103,8 +108,6 @@ static int __init load_powerpc_certs(void)
 		kfree(dbx);
 	}
 
-	of_node_put(node);
-
 	return rc;
 }
 late_initcall(load_powerpc_certs);
-- 
2.39.0


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 16/24] powerpc/pseries: Implement signed update for PLPKS objects
  2023-01-20  7:42   ` Andrew Donnellan
@ 2023-01-24  4:16     ` Nicholas Piggin
  -1 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  4:16 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Fri Jan 20, 2023 at 5:42 PM AEST, Andrew Donnellan wrote:
> From: Nayna Jain <nayna@linux.ibm.com>
>
> The Platform Keystore provides a signed update interface which can be used
> to create, replace or append to certain variables in the PKS in a secure
> fashion, with the hypervisor requiring that the update be signed using the
> Platform Key.
>
> Implement an interface to the H_PKS_SIGNED_UPDATE hcall in the plpks
> driver to allow signed updates to PKS objects.
>
> (The plpks driver doesn't need to do any cryptography or otherwise handle
> the actual signed variable contents - that will be handled by userspace
> tooling.)
>
> Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
> [ajd: split patch, add timeout handling and misc cleanups]
> Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
>
> ---
>
> v3: Merge plpks fixes and signed update series with secvar series
>
>     Fix error code handling in plpks_confirm_object_flushed() (ruscur)
>
>     Pass plpks_var struct to plpks_signed_update_var() by reference (mpe)
>
>     Consistent constant naming scheme (ruscur)
>
> v4: Fix MAX_HCALL_OPCODE rebasing issue (npiggin)
> ---
>  arch/powerpc/include/asm/hvcall.h      |  1 +
>  arch/powerpc/include/asm/plpks.h       |  5 ++
>  arch/powerpc/platforms/pseries/plpks.c | 71 ++++++++++++++++++++++++--
>  3 files changed, 72 insertions(+), 5 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
> index 95fd7f9485d5..c099780385dd 100644
> --- a/arch/powerpc/include/asm/hvcall.h
> +++ b/arch/powerpc/include/asm/hvcall.h
> @@ -335,6 +335,7 @@
>  #define H_RPT_INVALIDATE	0x448
>  #define H_SCM_FLUSH		0x44C
>  #define H_GET_ENERGY_SCALE_INFO	0x450
> +#define H_PKS_SIGNED_UPDATE	0x454
>  #define H_WATCHDOG		0x45C
>  #define MAX_HCALL_OPCODE	H_WATCHDOG
>  
> diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
> index 7c5f51a9af7c..e7204e6c0ca4 100644
> --- a/arch/powerpc/include/asm/plpks.h
> +++ b/arch/powerpc/include/asm/plpks.h
> @@ -68,6 +68,11 @@ struct plpks_var_name_list {
>  	struct plpks_var_name varlist[];
>  };
>  
> +/**
> + * Updates the authenticated variable. It expects NULL as the component.
> + */
> +int plpks_signed_update_var(struct plpks_var *var, u64 flags);
> +
>  /**
>   * Writes the specified var and its data to PKS.
>   * Any caller of PKS driver should present a valid component type for
> diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
> index 1189246b03dc..796ed5544ee5 100644
> --- a/arch/powerpc/platforms/pseries/plpks.c
> +++ b/arch/powerpc/platforms/pseries/plpks.c
> @@ -81,6 +81,12 @@ static int pseries_status_to_err(int rc)
>  		err = -ENOENT;
>  		break;
>  	case H_BUSY:
> +	case H_LONG_BUSY_ORDER_1_MSEC:
> +	case H_LONG_BUSY_ORDER_10_MSEC:
> +	case H_LONG_BUSY_ORDER_100_MSEC:
> +	case H_LONG_BUSY_ORDER_1_SEC:
> +	case H_LONG_BUSY_ORDER_10_SEC:
> +	case H_LONG_BUSY_ORDER_100_SEC:
>  		err = -EBUSY;
>  		break;
>  	case H_AUTHORITY:

This is a bit sad to maintain here. It's duplicating bits with
hvcs_convert, and a bunch of open coded places. Probably not the
series to do anything about. Would be nice if we could standardise
it though.

> @@ -184,14 +190,17 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
>  				     u16 namelen)
>  {
>  	struct label *label;
> -	size_t slen;
> +	size_t slen = 0;
>  
>  	if (!name || namelen > PLPKS_MAX_NAME_SIZE)
>  		return ERR_PTR(-EINVAL);
>  
> -	slen = strlen(component);
> -	if (component && slen > sizeof(label->attr.prefix))
> -		return ERR_PTR(-EINVAL);
> +	// Support NULL component for signed updates
> +	if (component) {
> +		slen = strlen(component);
> +		if (slen > sizeof(label->attr.prefix))
> +			return ERR_PTR(-EINVAL);
> +	}

Is this already a bug? Code checks for component != NULL but previously
calls strlen which would oops on NULL component AFAIKS. Granted nothing
is actually using any of this these days.

It already seems like it's supposed to be allowed to rad NULL component
with read_var though? Why the differences, why not always allow NULL
component? (I assume there is some reason, I just don't know anything
about secvar or secure boot).

>  
>  	// The label structure must not cross a page boundary, so we align to the next power of 2
>  	label = kzalloc(roundup_pow_of_two(sizeof(*label)), GFP_KERNEL);
> @@ -397,6 +406,58 @@ static int plpks_confirm_object_flushed(struct label *label,
>  	return pseries_status_to_err(rc);
>  }
>  
> +int plpks_signed_update_var(struct plpks_var *var, u64 flags)
> +{
> +	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = {0};
> +	int rc;
> +	struct label *label;
> +	struct plpks_auth *auth;
> +	u64 continuetoken = 0;
> +	u64 timeout = 0;
> +
> +	if (!var->data || var->datalen <= 0 || var->namelen > PLPKS_MAX_NAME_SIZE)
> +		return -EINVAL;
> +
> +	if (!(var->policy & PLPKS_SIGNEDUPDATE))
> +		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;
> +	}
> +
> +	do {
> +		rc = plpar_hcall9(H_PKS_SIGNED_UPDATE, retbuf,
> +				  virt_to_phys(auth), virt_to_phys(label),
> +				  label->size, var->policy, flags,
> +				  virt_to_phys(var->data), var->datalen,
> +				  continuetoken);
> +
> +		continuetoken = retbuf[0];
> +		if (pseries_status_to_err(rc) == -EBUSY) {
> +			int delay_ms = get_longbusy_msecs(rc);
> +			mdelay(delay_ms);
> +			timeout += delay_ms;
> +		}
> +		rc = pseries_status_to_err(rc);
> +	} while (rc == -EBUSY && timeout < PLPKS_MAX_TIMEOUT);
> +
> +	if (!rc)
> +		rc = plpks_confirm_object_flushed(label, auth);
> +
> +	kfree(label);
> +out:
> +	kfree(auth);
> +
> +	return rc;
> +}
> +EXPORT_SYMBOL(plpks_signed_update_var);

Sorry I missed it before -- can this be a _GPL export?

Thanks,
Nick

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 16/24] powerpc/pseries: Implement signed update for PLPKS objects
@ 2023-01-24  4:16     ` Nicholas Piggin
  0 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  4:16 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Fri Jan 20, 2023 at 5:42 PM AEST, Andrew Donnellan wrote:
> From: Nayna Jain <nayna@linux.ibm.com>
>
> The Platform Keystore provides a signed update interface which can be used
> to create, replace or append to certain variables in the PKS in a secure
> fashion, with the hypervisor requiring that the update be signed using the
> Platform Key.
>
> Implement an interface to the H_PKS_SIGNED_UPDATE hcall in the plpks
> driver to allow signed updates to PKS objects.
>
> (The plpks driver doesn't need to do any cryptography or otherwise handle
> the actual signed variable contents - that will be handled by userspace
> tooling.)
>
> Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
> [ajd: split patch, add timeout handling and misc cleanups]
> Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
>
> ---
>
> v3: Merge plpks fixes and signed update series with secvar series
>
>     Fix error code handling in plpks_confirm_object_flushed() (ruscur)
>
>     Pass plpks_var struct to plpks_signed_update_var() by reference (mpe)
>
>     Consistent constant naming scheme (ruscur)
>
> v4: Fix MAX_HCALL_OPCODE rebasing issue (npiggin)
> ---
>  arch/powerpc/include/asm/hvcall.h      |  1 +
>  arch/powerpc/include/asm/plpks.h       |  5 ++
>  arch/powerpc/platforms/pseries/plpks.c | 71 ++++++++++++++++++++++++--
>  3 files changed, 72 insertions(+), 5 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
> index 95fd7f9485d5..c099780385dd 100644
> --- a/arch/powerpc/include/asm/hvcall.h
> +++ b/arch/powerpc/include/asm/hvcall.h
> @@ -335,6 +335,7 @@
>  #define H_RPT_INVALIDATE	0x448
>  #define H_SCM_FLUSH		0x44C
>  #define H_GET_ENERGY_SCALE_INFO	0x450
> +#define H_PKS_SIGNED_UPDATE	0x454
>  #define H_WATCHDOG		0x45C
>  #define MAX_HCALL_OPCODE	H_WATCHDOG
>  
> diff --git a/arch/powerpc/include/asm/plpks.h b/arch/powerpc/include/asm/plpks.h
> index 7c5f51a9af7c..e7204e6c0ca4 100644
> --- a/arch/powerpc/include/asm/plpks.h
> +++ b/arch/powerpc/include/asm/plpks.h
> @@ -68,6 +68,11 @@ struct plpks_var_name_list {
>  	struct plpks_var_name varlist[];
>  };
>  
> +/**
> + * Updates the authenticated variable. It expects NULL as the component.
> + */
> +int plpks_signed_update_var(struct plpks_var *var, u64 flags);
> +
>  /**
>   * Writes the specified var and its data to PKS.
>   * Any caller of PKS driver should present a valid component type for
> diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
> index 1189246b03dc..796ed5544ee5 100644
> --- a/arch/powerpc/platforms/pseries/plpks.c
> +++ b/arch/powerpc/platforms/pseries/plpks.c
> @@ -81,6 +81,12 @@ static int pseries_status_to_err(int rc)
>  		err = -ENOENT;
>  		break;
>  	case H_BUSY:
> +	case H_LONG_BUSY_ORDER_1_MSEC:
> +	case H_LONG_BUSY_ORDER_10_MSEC:
> +	case H_LONG_BUSY_ORDER_100_MSEC:
> +	case H_LONG_BUSY_ORDER_1_SEC:
> +	case H_LONG_BUSY_ORDER_10_SEC:
> +	case H_LONG_BUSY_ORDER_100_SEC:
>  		err = -EBUSY;
>  		break;
>  	case H_AUTHORITY:

This is a bit sad to maintain here. It's duplicating bits with
hvcs_convert, and a bunch of open coded places. Probably not the
series to do anything about. Would be nice if we could standardise
it though.

> @@ -184,14 +190,17 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
>  				     u16 namelen)
>  {
>  	struct label *label;
> -	size_t slen;
> +	size_t slen = 0;
>  
>  	if (!name || namelen > PLPKS_MAX_NAME_SIZE)
>  		return ERR_PTR(-EINVAL);
>  
> -	slen = strlen(component);
> -	if (component && slen > sizeof(label->attr.prefix))
> -		return ERR_PTR(-EINVAL);
> +	// Support NULL component for signed updates
> +	if (component) {
> +		slen = strlen(component);
> +		if (slen > sizeof(label->attr.prefix))
> +			return ERR_PTR(-EINVAL);
> +	}

Is this already a bug? Code checks for component != NULL but previously
calls strlen which would oops on NULL component AFAIKS. Granted nothing
is actually using any of this these days.

It already seems like it's supposed to be allowed to rad NULL component
with read_var though? Why the differences, why not always allow NULL
component? (I assume there is some reason, I just don't know anything
about secvar or secure boot).

>  
>  	// The label structure must not cross a page boundary, so we align to the next power of 2
>  	label = kzalloc(roundup_pow_of_two(sizeof(*label)), GFP_KERNEL);
> @@ -397,6 +406,58 @@ static int plpks_confirm_object_flushed(struct label *label,
>  	return pseries_status_to_err(rc);
>  }
>  
> +int plpks_signed_update_var(struct plpks_var *var, u64 flags)
> +{
> +	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = {0};
> +	int rc;
> +	struct label *label;
> +	struct plpks_auth *auth;
> +	u64 continuetoken = 0;
> +	u64 timeout = 0;
> +
> +	if (!var->data || var->datalen <= 0 || var->namelen > PLPKS_MAX_NAME_SIZE)
> +		return -EINVAL;
> +
> +	if (!(var->policy & PLPKS_SIGNEDUPDATE))
> +		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;
> +	}
> +
> +	do {
> +		rc = plpar_hcall9(H_PKS_SIGNED_UPDATE, retbuf,
> +				  virt_to_phys(auth), virt_to_phys(label),
> +				  label->size, var->policy, flags,
> +				  virt_to_phys(var->data), var->datalen,
> +				  continuetoken);
> +
> +		continuetoken = retbuf[0];
> +		if (pseries_status_to_err(rc) == -EBUSY) {
> +			int delay_ms = get_longbusy_msecs(rc);
> +			mdelay(delay_ms);
> +			timeout += delay_ms;
> +		}
> +		rc = pseries_status_to_err(rc);
> +	} while (rc == -EBUSY && timeout < PLPKS_MAX_TIMEOUT);
> +
> +	if (!rc)
> +		rc = plpks_confirm_object_flushed(label, auth);
> +
> +	kfree(label);
> +out:
> +	kfree(auth);
> +
> +	return rc;
> +}
> +EXPORT_SYMBOL(plpks_signed_update_var);

Sorry I missed it before -- can this be a _GPL export?

Thanks,
Nick

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 19/24] powerpc/pseries: Turn PSERIES_PLPKS into a hidden option
  2023-01-20  7:43   ` Andrew Donnellan
@ 2023-01-24  4:26     ` Nicholas Piggin
  -1 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  4:26 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> It seems a bit unnecessary for the PLPKS code to have a user-visible
> config option when it doesn't do anything on its own, and there's existing
> options for enabling Secure Boot-related features.
>
> It should be enabled by PPC_SECURE_BOOT, which will eventually be what
> uses PLPKS to populate keyrings.
>
> However, we can't get of the separate option completely, because it will
> also be used for SED Opal purposes.
>
> Change PSERIES_PLPKS into a hidden option, which is selected by
> PPC_SECURE_BOOT.
>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
>
> ---
>
> v3: New patch
> ---
>  arch/powerpc/Kconfig                   |  1 +
>  arch/powerpc/platforms/pseries/Kconfig | 11 +----------
>  2 files changed, 2 insertions(+), 10 deletions(-)
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index b8c4ac56bddc..d4ed46101bec 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -1029,6 +1029,7 @@ config PPC_SECURE_BOOT
>  	depends on PPC_POWERNV || PPC_PSERIES
>  	depends on IMA_ARCH_POLICY
>  	imply IMA_SECURE_AND_OR_TRUSTED_BOOT
> +	select PSERIES_PLPKS if PPC_PSERIES
>  	help
>  	  Systems with firmware secure boot enabled need to define security
>  	  policies to extend secure boot to the OS. This config allows a user
> diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
> index a3b4d99567cb..82b6f993be0f 100644
> --- a/arch/powerpc/platforms/pseries/Kconfig
> +++ b/arch/powerpc/platforms/pseries/Kconfig
> @@ -151,16 +151,7 @@ config IBMEBUS
>  
>  config PSERIES_PLPKS
>  	depends on PPC_PSERIES
> -	bool "Support for the Platform Key Storage"
> -	help
> -	  PowerVM provides an isolated Platform Keystore(PKS) storage
> -	  allocation for each LPAR with individually managed access
> -	  controls to store sensitive information securely. It can be
> -	  used to store asymmetric public keys or secrets as required
> -	  by different usecases. Select this config to enable
> -	  operating system interface to hypervisor to access this space.

Not a big deal but you could turn this into a small Kconfig comment
instead (people got strangely angry when I tried to just use help text
in hidden options as comments). But if it's easy enough to grep for and
pretty straightforward then maybe it doesn't matter. I like know what
these things do at a glance.

Thanks,
Nick

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 19/24] powerpc/pseries: Turn PSERIES_PLPKS into a hidden option
@ 2023-01-24  4:26     ` Nicholas Piggin
  0 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  4:26 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> It seems a bit unnecessary for the PLPKS code to have a user-visible
> config option when it doesn't do anything on its own, and there's existing
> options for enabling Secure Boot-related features.
>
> It should be enabled by PPC_SECURE_BOOT, which will eventually be what
> uses PLPKS to populate keyrings.
>
> However, we can't get of the separate option completely, because it will
> also be used for SED Opal purposes.
>
> Change PSERIES_PLPKS into a hidden option, which is selected by
> PPC_SECURE_BOOT.
>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
>
> ---
>
> v3: New patch
> ---
>  arch/powerpc/Kconfig                   |  1 +
>  arch/powerpc/platforms/pseries/Kconfig | 11 +----------
>  2 files changed, 2 insertions(+), 10 deletions(-)
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index b8c4ac56bddc..d4ed46101bec 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -1029,6 +1029,7 @@ config PPC_SECURE_BOOT
>  	depends on PPC_POWERNV || PPC_PSERIES
>  	depends on IMA_ARCH_POLICY
>  	imply IMA_SECURE_AND_OR_TRUSTED_BOOT
> +	select PSERIES_PLPKS if PPC_PSERIES
>  	help
>  	  Systems with firmware secure boot enabled need to define security
>  	  policies to extend secure boot to the OS. This config allows a user
> diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
> index a3b4d99567cb..82b6f993be0f 100644
> --- a/arch/powerpc/platforms/pseries/Kconfig
> +++ b/arch/powerpc/platforms/pseries/Kconfig
> @@ -151,16 +151,7 @@ config IBMEBUS
>  
>  config PSERIES_PLPKS
>  	depends on PPC_PSERIES
> -	bool "Support for the Platform Key Storage"
> -	help
> -	  PowerVM provides an isolated Platform Keystore(PKS) storage
> -	  allocation for each LPAR with individually managed access
> -	  controls to store sensitive information securely. It can be
> -	  used to store asymmetric public keys or secrets as required
> -	  by different usecases. Select this config to enable
> -	  operating system interface to hypervisor to access this space.

Not a big deal but you could turn this into a small Kconfig comment
instead (people got strangely angry when I tried to just use help text
in hidden options as comments). But if it's easy enough to grep for and
pretty straightforward then maybe it doesn't matter. I like know what
these things do at a glance.

Thanks,
Nick

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
  2023-01-20  7:43   ` Andrew Donnellan
@ 2023-01-24  4:36     ` Nicholas Piggin
  -1 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  4:36 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
>
> Before interacting with the PLPKS, we ask the hypervisor to generate a
> password for the current boot, which is then required for most further
> PLPKS operations.
>
> If we kexec into a new kernel, the new kernel will try and fail to
> generate a new password, as the password has already been set.
>
> Pass the password through to the new kernel via the device tree, in
> /chosen/plpks-pw. Check for the presence of this property before trying

In /chosen/ibm,plpks-pw

> to generate a new password - if it exists, use the existing password and
> remove it from the device tree.
>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
>
> ---
>
> v3: New patch
>
> v4: Fix compile when CONFIG_PSERIES_PLPKS=n (snowpatch)
>
>     Fix error handling on fdt_path_offset() call (ruscur)
> ---
>  arch/powerpc/kexec/file_load_64.c      | 18 ++++++++++++++++++
>  arch/powerpc/platforms/pseries/plpks.c | 18 +++++++++++++++++-
>  2 files changed, 35 insertions(+), 1 deletion(-)
>
> diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c
> index af8854f9eae3..0c9130af60cc 100644
> --- a/arch/powerpc/kexec/file_load_64.c
> +++ b/arch/powerpc/kexec/file_load_64.c
> @@ -27,6 +27,7 @@
>  #include <asm/kexec_ranges.h>
>  #include <asm/crashdump-ppc64.h>
>  #include <asm/prom.h>
> +#include <asm/plpks.h>
>  
>  struct umem_info {
>  	u64 *buf;		/* data buffer for usable-memory property */
> @@ -1156,6 +1157,9 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
>  {
>  	struct crash_mem *umem = NULL, *rmem = NULL;
>  	int i, nr_ranges, ret;
> +#ifdef CONFIG_PSERIES_PLPKS
> +	int chosen_offset;
> +#endif

Could put this in plpks_is_available and avoid an ifdef.

>  
>  	/*
>  	 * Restrict memory usage for kdump kernel by setting up
> @@ -1230,6 +1234,20 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
>  		}
>  	}
>  
> +#ifdef CONFIG_PSERIES_PLPKS
> +	// If we have PLPKS active, we need to provide the password
> +	if (plpks_is_available()) {
> +		chosen_offset = fdt_path_offset(fdt, "/chosen");
> +		if (chosen_offset < 0) {
> +			pr_err("Can't find chosen node: %s\n",
> +			       fdt_strerror(chosen_offset));
> +			goto out;
> +		}
> +		ret = fdt_setprop(fdt, chosen_offset, "ibm,plpks-pw",
> +				  plpks_get_password(), plpks_get_passwordlen());
> +	}
> +#endif // CONFIG_PSERIES_PLPKS

I think if you define plpks_get_password and plpks_get_passwordlen as
BUILD_BUG_ON when PLPKS is not configured and plpks_is_available as
false, you could remove the ifdef entirely.

> +
>  out:
>  	kfree(rmem);
>  	kfree(umem);
> diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
> index b3c7410a4f13..0350f10e1755 100644
> --- a/arch/powerpc/platforms/pseries/plpks.c
> +++ b/arch/powerpc/platforms/pseries/plpks.c
> @@ -16,6 +16,7 @@
>  #include <linux/slab.h>
>  #include <linux/string.h>
>  #include <linux/types.h>
> +#include <linux/of.h>
>  #include <asm/hvcall.h>
>  #include <asm/machdep.h>
>  #include <asm/plpks.h>
> @@ -126,7 +127,22 @@ static int plpks_gen_password(void)
>  {
>  	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
>  	u8 *password, consumer = PLPKS_OS_OWNER;
> -	int rc;
> +	struct property *prop;
> +	int rc, len;
> +
> +	// Before we generate the password, we may have been booted by kexec and
> +	// provided with a previous password.  Check for that first.

So not really generating the password then. Should it be in a different
function the caller makes first?

> +	prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
> +	if (prop) {
> +		ospasswordlength = (u16)len;
> +		ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
> +		if (!ospassword) {
> +			of_remove_property(of_chosen, prop);
> +			return -ENOMEM;
> +		}
> +		memcpy(ospassword, prop->value, len);
> +		return of_remove_property(of_chosen, prop);

Why do you remove the property afterward?

Thanks,
Nick

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
@ 2023-01-24  4:36     ` Nicholas Piggin
  0 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  4:36 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
>
> Before interacting with the PLPKS, we ask the hypervisor to generate a
> password for the current boot, which is then required for most further
> PLPKS operations.
>
> If we kexec into a new kernel, the new kernel will try and fail to
> generate a new password, as the password has already been set.
>
> Pass the password through to the new kernel via the device tree, in
> /chosen/plpks-pw. Check for the presence of this property before trying

In /chosen/ibm,plpks-pw

> to generate a new password - if it exists, use the existing password and
> remove it from the device tree.
>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
>
> ---
>
> v3: New patch
>
> v4: Fix compile when CONFIG_PSERIES_PLPKS=n (snowpatch)
>
>     Fix error handling on fdt_path_offset() call (ruscur)
> ---
>  arch/powerpc/kexec/file_load_64.c      | 18 ++++++++++++++++++
>  arch/powerpc/platforms/pseries/plpks.c | 18 +++++++++++++++++-
>  2 files changed, 35 insertions(+), 1 deletion(-)
>
> diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c
> index af8854f9eae3..0c9130af60cc 100644
> --- a/arch/powerpc/kexec/file_load_64.c
> +++ b/arch/powerpc/kexec/file_load_64.c
> @@ -27,6 +27,7 @@
>  #include <asm/kexec_ranges.h>
>  #include <asm/crashdump-ppc64.h>
>  #include <asm/prom.h>
> +#include <asm/plpks.h>
>  
>  struct umem_info {
>  	u64 *buf;		/* data buffer for usable-memory property */
> @@ -1156,6 +1157,9 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
>  {
>  	struct crash_mem *umem = NULL, *rmem = NULL;
>  	int i, nr_ranges, ret;
> +#ifdef CONFIG_PSERIES_PLPKS
> +	int chosen_offset;
> +#endif

Could put this in plpks_is_available and avoid an ifdef.

>  
>  	/*
>  	 * Restrict memory usage for kdump kernel by setting up
> @@ -1230,6 +1234,20 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
>  		}
>  	}
>  
> +#ifdef CONFIG_PSERIES_PLPKS
> +	// If we have PLPKS active, we need to provide the password
> +	if (plpks_is_available()) {
> +		chosen_offset = fdt_path_offset(fdt, "/chosen");
> +		if (chosen_offset < 0) {
> +			pr_err("Can't find chosen node: %s\n",
> +			       fdt_strerror(chosen_offset));
> +			goto out;
> +		}
> +		ret = fdt_setprop(fdt, chosen_offset, "ibm,plpks-pw",
> +				  plpks_get_password(), plpks_get_passwordlen());
> +	}
> +#endif // CONFIG_PSERIES_PLPKS

I think if you define plpks_get_password and plpks_get_passwordlen as
BUILD_BUG_ON when PLPKS is not configured and plpks_is_available as
false, you could remove the ifdef entirely.

> +
>  out:
>  	kfree(rmem);
>  	kfree(umem);
> diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
> index b3c7410a4f13..0350f10e1755 100644
> --- a/arch/powerpc/platforms/pseries/plpks.c
> +++ b/arch/powerpc/platforms/pseries/plpks.c
> @@ -16,6 +16,7 @@
>  #include <linux/slab.h>
>  #include <linux/string.h>
>  #include <linux/types.h>
> +#include <linux/of.h>
>  #include <asm/hvcall.h>
>  #include <asm/machdep.h>
>  #include <asm/plpks.h>
> @@ -126,7 +127,22 @@ static int plpks_gen_password(void)
>  {
>  	unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
>  	u8 *password, consumer = PLPKS_OS_OWNER;
> -	int rc;
> +	struct property *prop;
> +	int rc, len;
> +
> +	// Before we generate the password, we may have been booted by kexec and
> +	// provided with a previous password.  Check for that first.

So not really generating the password then. Should it be in a different
function the caller makes first?

> +	prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
> +	if (prop) {
> +		ospasswordlength = (u16)len;
> +		ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
> +		if (!ospassword) {
> +			of_remove_property(of_chosen, prop);
> +			return -ENOMEM;
> +		}
> +		memcpy(ospassword, prop->value, len);
> +		return of_remove_property(of_chosen, prop);

Why do you remove the property afterward?

Thanks,
Nick

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
  2023-01-24  4:36     ` Nicholas Piggin
@ 2023-01-24  4:40       ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-24  4:40 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Tue, 2023-01-24 at 14:36 +1000, Nicholas Piggin wrote:
> 
> > +       prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
> > +       if (prop) {
> > +               ospasswordlength = (u16)len;
> > +               ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
> > +               if (!ospassword) {
> > +                       of_remove_property(of_chosen, prop);
> > +                       return -ENOMEM;
> > +               }
> > +               memcpy(ospassword, prop->value, len);
> > +               return of_remove_property(of_chosen, prop);
> 
> Why do you remove the property afterward?

Because otherwise the password will be sitting around in /proc/device-
tree for the world to go and read.

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
@ 2023-01-24  4:40       ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-24  4:40 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Tue, 2023-01-24 at 14:36 +1000, Nicholas Piggin wrote:
> 
> > +       prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
> > +       if (prop) {
> > +               ospasswordlength = (u16)len;
> > +               ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
> > +               if (!ospassword) {
> > +                       of_remove_property(of_chosen, prop);
> > +                       return -ENOMEM;
> > +               }
> > +               memcpy(ospassword, prop->value, len);
> > +               return of_remove_property(of_chosen, prop);
> 
> Why do you remove the property afterward?

Because otherwise the password will be sitting around in /proc/device-
tree for the world to go and read.

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
  2023-01-20  7:43   ` Andrew Donnellan
@ 2023-01-24  5:17     ` Nicholas Piggin
  -1 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  5:17 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
>
> The pseries platform can support dynamic secure boot (i.e. secure boot
> using user-defined keys) using variables contained with the PowerVM LPAR
> Platform KeyStore (PLPKS).  Using the powerpc secvar API, expose the
> relevant variables for pseries dynamic secure boot through the existing
> secvar filesystem layout.
>
> The relevant variables for dynamic secure boot are signed in the
> keystore, and can only be modified using the H_PKS_SIGNED_UPDATE hcall.
> Object labels in the keystore are encoded using ucs2 format.  With our
> fixed variable names we don't have to care about encoding outside of the
> necessary byte padding.
>
> When a user writes to a variable, the first 8 bytes of data must contain
> the signed update flags as defined by the hypervisor.
>
> When a user reads a variable, the first 4 bytes of data contain the
> policies defined for the object.
>
> Limitations exist due to the underlying implementation of sysfs binary
> attributes, as is the case for the OPAL secvar implementation -
> partial writes are unsupported and writes cannot be larger than PAGE_SIZE.
> (Even when using bin_attributes, which can be larger than a single page,
> sysfs only gives us one page's worth of write buffer at a time, and the
> hypervisor does not expose an interface for partial writes.)
>
> Co-developed-by: Nayna Jain <nayna@linux.ibm.com>
> Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
> Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
>
> ---
>
> v2: Remove unnecessary config vars from sysfs and document the others,
>     thanks to review from Greg.  If we end up needing to expose more, we
>     can add them later and update the docs.
>
>     Use sysfs_emit() instead of sprintf(), thanks to Greg.
>
>     Change the size of the sysfs binary attributes to include the 8-byte
>     flags header, preventing truncation of large writes.
>
> v3: plpks_set_variable(): pass var to plpks_signed_update_var() as a
>     pointer (mpe)
>
>     Update copyright date (ajd)
>
>     Consistent comment style (ajd)
>
>     Change device_initcall() to machine_arch_initcall(pseries...) so we
>     don't try to load on powernv and kill the machine (mpe)
>
>     Add config attributes into plpks_secvar_ops (mpe)
>
>     Get rid of PLPKS_SECVAR_COUNT macro (mpe)
>
>     Reworded descriptions in ABI documentation (mpe)
>
>     Switch to using secvar_ops->var_names rather than
>     secvar_ops->get_next() (ajd/mpe)
>
>     Optimise allocation/copying of buffers (mpe)
>
>     Elaborate the comment documenting the "format" string (mpe)
>
>     Return -EIO on errors in the read case (mpe)
>
>     Add "grubdbx" variable (Sudhakar Kuppusamy)
>
>     Use utf8s_to_utf16s() rather than our own "UCS-2" conversion code (mpe)
>
>     Change uint64_t to u64 (mpe)
>
>     Fix SB_VERSION data length (ruscur)
>
>     Stop prepending policy data on read (ruscur)
>
>     Enforce max format length on format string (not strictly needed, but
>     makes the length limit clear) (ajd)
>
>     Update include of plpks.h to reflect new path (ruscur)
>
>     Consistent constant naming scheme (ruscur)
>
> v4: Return set_secvar_ops() return code
>
>     Pass buffer size to plpks_secvar_format() (stefanb, npiggin)
>
>     Add missing null check (stefanb)
>
>     Add comment to commit message explaining PAGE_SIZE write limit (joel)
> ---
>  Documentation/ABI/testing/sysfs-secvar        |  75 +++++-
>  arch/powerpc/platforms/pseries/Makefile       |   4 +-
>  arch/powerpc/platforms/pseries/plpks-secvar.c | 215 ++++++++++++++++++
>  3 files changed, 291 insertions(+), 3 deletions(-)
>  create mode 100644 arch/powerpc/platforms/pseries/plpks-secvar.c
>
> diff --git a/Documentation/ABI/testing/sysfs-secvar b/Documentation/ABI/testing/sysfs-secvar
> index feebb8c57294..a19f4d5fcec6 100644
> --- a/Documentation/ABI/testing/sysfs-secvar
> +++ b/Documentation/ABI/testing/sysfs-secvar
> @@ -18,6 +18,14 @@ Description:	A string indicating which backend is in use by the firmware.
>  		This determines the format of the variable and the accepted
>  		format of variable updates.
>  
> +		On powernv/OPAL, this value is provided by the OPAL firmware
> +		and is expected to be "ibm,edk2-compat-v1".
> +
> +		On pseries/PLPKS, this is generated by the kernel based on the
> +		version number in the SB_VERSION variable in the keystore, and
> +		has the form "ibm,plpks-sb-v<version>", or
> +		"ibm,plpks-sb-unknown" if there is no SB_VERSION variable.
> +
>  What:		/sys/firmware/secvar/vars/<variable name>
>  Date:		August 2019
>  Contact:	Nayna Jain <nayna@linux.ibm.com>
> @@ -34,7 +42,7 @@ Description:	An integer representation of the size of the content of the
>  
>  What:		/sys/firmware/secvar/vars/<variable_name>/data
>  Date:		August 2019
> -Contact:	Nayna Jain h<nayna@linux.ibm.com>
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
>  Description:	A read-only file containing the value of the variable. The size
>  		of the file represents the maximum size of the variable data.
>  
> @@ -44,3 +52,68 @@ Contact:	Nayna Jain <nayna@linux.ibm.com>
>  Description:	A write-only file that is used to submit the new value for the
>  		variable. The size of the file represents the maximum size of
>  		the variable data that can be written.
> +
> +What:		/sys/firmware/secvar/config
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	This optional directory contains read-only config attributes as
> +		defined by the secure variable implementation.  All data is in
> +		ASCII format. The directory is only created if the backing
> +		implementation provides variables to populate it, which at
> +		present is only PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/version
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Config version as reported by the hypervisor in ASCII decimal
> +		format.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/max_object_size
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Maximum allowed size of	objects in the keystore in bytes,
> +		represented in ASCII decimal format.
> +
> +		This is not necessarily the same as the max size that can be
> +		written to an update file as writes can contain more than
> +		object data, you should use the size of the update file for
> +		that purpose.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/total_size
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Total size of the PLPKS in bytes, represented in ASCII decimal
> +		format.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/used_space
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Current space consumed by the key store, in bytes, represented
> +		in ASCII decimal format.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/supported_policies
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Bitmask of supported policy flags by the hypervisor,
> +		represented as an 8 byte hexadecimal ASCII string. Consult the
> +		hypervisor documentation for what these flags are.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/signed_update_algorithms
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Bitmask of flags indicating which algorithms the hypervisor
> +		supports for signed update of objects, represented as a 16 byte
> +		hexadecimal ASCII string. Consult the hypervisor documentation
> +		for what these flags mean.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
> index 92310202bdd7..d52b7ec1a678 100644
> --- a/arch/powerpc/platforms/pseries/Makefile
> +++ b/arch/powerpc/platforms/pseries/Makefile
> @@ -27,8 +27,8 @@ obj-$(CONFIG_PAPR_SCM)		+= papr_scm.o
>  obj-$(CONFIG_PPC_SPLPAR)	+= vphn.o
>  obj-$(CONFIG_PPC_SVM)		+= svm.o
>  obj-$(CONFIG_FA_DUMP)		+= rtas-fadump.o
> -obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
> -
> +obj-$(CONFIG_PSERIES_PLPKS)	+= plpks.o
> +obj-$(CONFIG_PPC_SECVAR_SYSFS)	+= plpks-secvar.o
>  obj-$(CONFIG_SUSPEND)		+= suspend.o
>  obj-$(CONFIG_PPC_VAS)		+= vas.o vas-sysfs.o
>  
> diff --git a/arch/powerpc/platforms/pseries/plpks-secvar.c b/arch/powerpc/platforms/pseries/plpks-secvar.c
> new file mode 100644
> index 000000000000..a80d9f9469f9
> --- /dev/null
> +++ b/arch/powerpc/platforms/pseries/plpks-secvar.c
> @@ -0,0 +1,215 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +// Secure variable implementation using the PowerVM LPAR Platform KeyStore (PLPKS)
> +//
> +// Copyright 2022, 2023 IBM Corporation
> +// Authors: Russell Currey
> +//          Andrew Donnellan
> +//          Nayna Jain
> +
> +#define pr_fmt(fmt) "secvar: "fmt
> +
> +#include <linux/printk.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/kobject.h>
> +#include <linux/nls.h>
> +#include <asm/machdep.h>
> +#include <asm/secvar.h>
> +#include <asm/plpks.h>
> +
> +// Config attributes for sysfs
> +#define PLPKS_CONFIG_ATTR(name, fmt, func)			\
> +	static ssize_t name##_show(struct kobject *kobj,	\
> +				   struct kobj_attribute *attr,	\
> +				   char *buf)			\
> +	{							\
> +		return sysfs_emit(buf, fmt, func());		\
> +	}							\
> +	static struct kobj_attribute attr_##name = __ATTR_RO(name)
> +
> +PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version);
> +PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize);
> +PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize);
> +PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace);
> +PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicies);
> +PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms);
> +
> +static const struct attribute *config_attrs[] = {
> +	&attr_version.attr,
> +	&attr_max_object_size.attr,
> +	&attr_total_size.attr,
> +	&attr_used_space.attr,
> +	&attr_supported_policies.attr,
> +	&attr_signed_update_algorithms.attr,
> +	NULL,
> +};
> +
> +static u32 get_policy(const char *name)
> +{
> +	if ((strcmp(name, "db") == 0) ||
> +	    (strcmp(name, "dbx") == 0) ||
> +	    (strcmp(name, "grubdb") == 0) ||
> +	    (strcmp(name, "grubdbx") == 0) ||
> +	    (strcmp(name, "sbat") == 0))
> +		return (PLPKS_WORLDREADABLE | PLPKS_SIGNEDUPDATE);
> +	else
> +		return PLPKS_SIGNEDUPDATE;
> +}
> +
> +static const char * const plpks_var_names[] = {
> +	"PK",
> +	"KEK",
> +	"db",
> +	"dbx",
> +	"grubdb",
> +	"grubdbx",
> +	"sbat",
> +	"moduledb",
> +	"trustedcadb",
> +	NULL,
> +};

Var and key are used somewhat interchangeably? These are keys, I think?
And plpks could have other vars but we're only interested in (at least a
subset of) keys here if I understood right.

I guess the terminology is like that throughout secvar so maybe nothing
to be done.

> +
> +static int plpks_get_variable(const char *key, u64 key_len, u8 *data,
> +			      u64 *data_size)
> +{
> +	struct plpks_var var = {0};
> +	int rc = 0;
> +
> +	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
> +	if (!var.name)
> +		return -ENOMEM;
> +	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
> +			     key_len - 1);
> +	if (rc < 0)
> +		goto err;

Okay I can't work out why it's key_len - 1 rather than key_len.

> +	var.namelen = rc * 2;
> +
> +	var.os = PLPKS_VAR_LINUX;
> +	if (data) {
> +		var.data = data;
> +		var.datalen = *data_size;
> +	}
> +	rc = plpks_read_os_var(&var);
> +
> +	if (rc)
> +		goto err;
> +
> +	*data_size = var.datalen;
> +
> +err:
> +	kfree(var.name);
> +	if (rc && rc != -ENOENT) {
> +		pr_err("Failed to read variable '%s': %d\n", key, rc);
> +		// Return -EIO since userspace probably doesn't care about the
> +		// specific error
> +		rc = -EIO;
> +	}
> +	return rc;
> +}
> +
> +static int plpks_set_variable(const char *key, u64 key_len, u8 *data,
> +			      u64 data_size)
> +{
> +	struct plpks_var var = {0};
> +	int rc = 0;
> +	u64 flags;
> +
> +	// Secure variables need to be prefixed with 8 bytes of flags.
> +	// We only want to perform the write if we have at least one byte of data.
> +	if (data_size <= sizeof(flags))

So it's unstructured 8 byte of flags, not a u64 integer? Why not u8
flags[8] then?

> +		return -EINVAL;
> +
> +	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
> +	if (!var.name)
> +		return -ENOMEM;
> +	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
> +			     key_len - 1);
> +	if (rc < 0)
> +		goto err;
> +	var.namelen = rc * 2;
> +
> +	memcpy(&flags, data, sizeof(flags));
> +
> +	var.datalen = data_size - sizeof(flags);
> +	var.data = data + sizeof(flags);
> +	var.os = PLPKS_VAR_LINUX;
> +	var.policy = get_policy(key);
> +
> +	// Unlike in the read case, the plpks error code can be useful to
> +	// userspace on write, so we return it rather than just -EIO
> +	rc = plpks_signed_update_var(&var, flags);
> +
> +err:
> +	kfree(var.name);
> +	return rc;
> +}
> +
> +// PLPKS dynamic secure boot doesn't give us a format string in the same way OPAL does.
> +// Instead, report the format using the SB_VERSION variable in the keystore.
> +static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
> +{
> +	struct plpks_var var = {0};
> +	ssize_t ret;
> +
> +	var.component = NULL;
> +	// Only the signed variables have null bytes in their names, this one doesn't
> +	var.name = "SB_VERSION";
> +	var.namelen = 10;

Could you make that strlen(var.name) for the benefit of those of us with
missing fingers?

> +	var.datalen = 1;
> +	var.data = kzalloc(1, GFP_KERNEL);

This could just point to a u8 on stack I think?


> +	if (!var.data)
> +		return -ENOMEM;
> +
> +	// Unlike the other vars, SB_VERSION is owned by firmware instead of the OS
> +	ret = plpks_read_fw_var(&var);
> +	if (ret) {
> +		if (ret == -ENOENT) {
> +			ret = snprintf(buf, bufsize, "ibm,plpks-sb-unknown");
> +		} else {
> +			pr_err("Error %ld reading SB_VERSION from firmware\n", ret);
> +			ret = -EIO;
> +		}

Is there a meaningful distinction? Does anything good come of
advertising an unknown format like this?

> +		goto err;
> +	}
> +
> +	// This string is made up by us - the hypervisor doesn't provide us
> +	// with a format string in the way that OPAL firmware does. Hypervisor
> +	// defines SB_VERSION as a "1 byte unsigned integer value".

I'd put the comment about SB_VERSION at the top where you use/define it
or mention it in the comment.

> +	ret = snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu", var.data[0]);
> +
> +err:
> +	kfree(var.data);
> +	return ret;
> +}
> +
> +static int plpks_max_size(u64 *max_size)
> +{
> +	// The max object size reported by the hypervisor is accurate for the
> +	// object itself, but we use the first 8 bytes of data on write as the
> +	// signed update flags, so the max size a user can write is larger.
> +	*max_size = (u64)plpks_get_maxobjectsize() + 8;

You have this 8 open coded twice (once as sizeof(u64)). You could make
it a #define at the top with a brief overview of the hcall format so you
don't need so much commentage for it. Although a note here that the
objsize does not include the flags bytes is good to keep.

Thanks,
Nick

> +
> +	return 0;
> +}
> +
> +
> +static const struct secvar_operations plpks_secvar_ops = {
> +	.get = plpks_get_variable,
> +	.set = plpks_set_variable,
> +	.format = plpks_secvar_format,
> +	.max_size = plpks_max_size,
> +	.config_attrs = config_attrs,
> +	.var_names = plpks_var_names,
> +};
> +
> +static int plpks_secvar_init(void)
> +{
> +	if (!plpks_is_available())
> +		return -ENODEV;
> +
> +	return set_secvar_ops(&plpks_secvar_ops);
> +}
> +machine_device_initcall(pseries, plpks_secvar_init);
> -- 
> 2.39.0


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
@ 2023-01-24  5:17     ` Nicholas Piggin
  0 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  5:17 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
>
> The pseries platform can support dynamic secure boot (i.e. secure boot
> using user-defined keys) using variables contained with the PowerVM LPAR
> Platform KeyStore (PLPKS).  Using the powerpc secvar API, expose the
> relevant variables for pseries dynamic secure boot through the existing
> secvar filesystem layout.
>
> The relevant variables for dynamic secure boot are signed in the
> keystore, and can only be modified using the H_PKS_SIGNED_UPDATE hcall.
> Object labels in the keystore are encoded using ucs2 format.  With our
> fixed variable names we don't have to care about encoding outside of the
> necessary byte padding.
>
> When a user writes to a variable, the first 8 bytes of data must contain
> the signed update flags as defined by the hypervisor.
>
> When a user reads a variable, the first 4 bytes of data contain the
> policies defined for the object.
>
> Limitations exist due to the underlying implementation of sysfs binary
> attributes, as is the case for the OPAL secvar implementation -
> partial writes are unsupported and writes cannot be larger than PAGE_SIZE.
> (Even when using bin_attributes, which can be larger than a single page,
> sysfs only gives us one page's worth of write buffer at a time, and the
> hypervisor does not expose an interface for partial writes.)
>
> Co-developed-by: Nayna Jain <nayna@linux.ibm.com>
> Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
> Co-developed-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
>
> ---
>
> v2: Remove unnecessary config vars from sysfs and document the others,
>     thanks to review from Greg.  If we end up needing to expose more, we
>     can add them later and update the docs.
>
>     Use sysfs_emit() instead of sprintf(), thanks to Greg.
>
>     Change the size of the sysfs binary attributes to include the 8-byte
>     flags header, preventing truncation of large writes.
>
> v3: plpks_set_variable(): pass var to plpks_signed_update_var() as a
>     pointer (mpe)
>
>     Update copyright date (ajd)
>
>     Consistent comment style (ajd)
>
>     Change device_initcall() to machine_arch_initcall(pseries...) so we
>     don't try to load on powernv and kill the machine (mpe)
>
>     Add config attributes into plpks_secvar_ops (mpe)
>
>     Get rid of PLPKS_SECVAR_COUNT macro (mpe)
>
>     Reworded descriptions in ABI documentation (mpe)
>
>     Switch to using secvar_ops->var_names rather than
>     secvar_ops->get_next() (ajd/mpe)
>
>     Optimise allocation/copying of buffers (mpe)
>
>     Elaborate the comment documenting the "format" string (mpe)
>
>     Return -EIO on errors in the read case (mpe)
>
>     Add "grubdbx" variable (Sudhakar Kuppusamy)
>
>     Use utf8s_to_utf16s() rather than our own "UCS-2" conversion code (mpe)
>
>     Change uint64_t to u64 (mpe)
>
>     Fix SB_VERSION data length (ruscur)
>
>     Stop prepending policy data on read (ruscur)
>
>     Enforce max format length on format string (not strictly needed, but
>     makes the length limit clear) (ajd)
>
>     Update include of plpks.h to reflect new path (ruscur)
>
>     Consistent constant naming scheme (ruscur)
>
> v4: Return set_secvar_ops() return code
>
>     Pass buffer size to plpks_secvar_format() (stefanb, npiggin)
>
>     Add missing null check (stefanb)
>
>     Add comment to commit message explaining PAGE_SIZE write limit (joel)
> ---
>  Documentation/ABI/testing/sysfs-secvar        |  75 +++++-
>  arch/powerpc/platforms/pseries/Makefile       |   4 +-
>  arch/powerpc/platforms/pseries/plpks-secvar.c | 215 ++++++++++++++++++
>  3 files changed, 291 insertions(+), 3 deletions(-)
>  create mode 100644 arch/powerpc/platforms/pseries/plpks-secvar.c
>
> diff --git a/Documentation/ABI/testing/sysfs-secvar b/Documentation/ABI/testing/sysfs-secvar
> index feebb8c57294..a19f4d5fcec6 100644
> --- a/Documentation/ABI/testing/sysfs-secvar
> +++ b/Documentation/ABI/testing/sysfs-secvar
> @@ -18,6 +18,14 @@ Description:	A string indicating which backend is in use by the firmware.
>  		This determines the format of the variable and the accepted
>  		format of variable updates.
>  
> +		On powernv/OPAL, this value is provided by the OPAL firmware
> +		and is expected to be "ibm,edk2-compat-v1".
> +
> +		On pseries/PLPKS, this is generated by the kernel based on the
> +		version number in the SB_VERSION variable in the keystore, and
> +		has the form "ibm,plpks-sb-v<version>", or
> +		"ibm,plpks-sb-unknown" if there is no SB_VERSION variable.
> +
>  What:		/sys/firmware/secvar/vars/<variable name>
>  Date:		August 2019
>  Contact:	Nayna Jain <nayna@linux.ibm.com>
> @@ -34,7 +42,7 @@ Description:	An integer representation of the size of the content of the
>  
>  What:		/sys/firmware/secvar/vars/<variable_name>/data
>  Date:		August 2019
> -Contact:	Nayna Jain h<nayna@linux.ibm.com>
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
>  Description:	A read-only file containing the value of the variable. The size
>  		of the file represents the maximum size of the variable data.
>  
> @@ -44,3 +52,68 @@ Contact:	Nayna Jain <nayna@linux.ibm.com>
>  Description:	A write-only file that is used to submit the new value for the
>  		variable. The size of the file represents the maximum size of
>  		the variable data that can be written.
> +
> +What:		/sys/firmware/secvar/config
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	This optional directory contains read-only config attributes as
> +		defined by the secure variable implementation.  All data is in
> +		ASCII format. The directory is only created if the backing
> +		implementation provides variables to populate it, which at
> +		present is only PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/version
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Config version as reported by the hypervisor in ASCII decimal
> +		format.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/max_object_size
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Maximum allowed size of	objects in the keystore in bytes,
> +		represented in ASCII decimal format.
> +
> +		This is not necessarily the same as the max size that can be
> +		written to an update file as writes can contain more than
> +		object data, you should use the size of the update file for
> +		that purpose.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/total_size
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Total size of the PLPKS in bytes, represented in ASCII decimal
> +		format.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/used_space
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Current space consumed by the key store, in bytes, represented
> +		in ASCII decimal format.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/supported_policies
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Bitmask of supported policy flags by the hypervisor,
> +		represented as an 8 byte hexadecimal ASCII string. Consult the
> +		hypervisor documentation for what these flags are.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> +
> +What:		/sys/firmware/secvar/config/signed_update_algorithms
> +Date:		December 2022
> +Contact:	Nayna Jain <nayna@linux.ibm.com>
> +Description:	Bitmask of flags indicating which algorithms the hypervisor
> +		supports for signed update of objects, represented as a 16 byte
> +		hexadecimal ASCII string. Consult the hypervisor documentation
> +		for what these flags mean.
> +
> +		Currently only provided by PLPKS on the pseries platform.
> diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
> index 92310202bdd7..d52b7ec1a678 100644
> --- a/arch/powerpc/platforms/pseries/Makefile
> +++ b/arch/powerpc/platforms/pseries/Makefile
> @@ -27,8 +27,8 @@ obj-$(CONFIG_PAPR_SCM)		+= papr_scm.o
>  obj-$(CONFIG_PPC_SPLPAR)	+= vphn.o
>  obj-$(CONFIG_PPC_SVM)		+= svm.o
>  obj-$(CONFIG_FA_DUMP)		+= rtas-fadump.o
> -obj-$(CONFIG_PSERIES_PLPKS) += plpks.o
> -
> +obj-$(CONFIG_PSERIES_PLPKS)	+= plpks.o
> +obj-$(CONFIG_PPC_SECVAR_SYSFS)	+= plpks-secvar.o
>  obj-$(CONFIG_SUSPEND)		+= suspend.o
>  obj-$(CONFIG_PPC_VAS)		+= vas.o vas-sysfs.o
>  
> diff --git a/arch/powerpc/platforms/pseries/plpks-secvar.c b/arch/powerpc/platforms/pseries/plpks-secvar.c
> new file mode 100644
> index 000000000000..a80d9f9469f9
> --- /dev/null
> +++ b/arch/powerpc/platforms/pseries/plpks-secvar.c
> @@ -0,0 +1,215 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +// Secure variable implementation using the PowerVM LPAR Platform KeyStore (PLPKS)
> +//
> +// Copyright 2022, 2023 IBM Corporation
> +// Authors: Russell Currey
> +//          Andrew Donnellan
> +//          Nayna Jain
> +
> +#define pr_fmt(fmt) "secvar: "fmt
> +
> +#include <linux/printk.h>
> +#include <linux/init.h>
> +#include <linux/types.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/kobject.h>
> +#include <linux/nls.h>
> +#include <asm/machdep.h>
> +#include <asm/secvar.h>
> +#include <asm/plpks.h>
> +
> +// Config attributes for sysfs
> +#define PLPKS_CONFIG_ATTR(name, fmt, func)			\
> +	static ssize_t name##_show(struct kobject *kobj,	\
> +				   struct kobj_attribute *attr,	\
> +				   char *buf)			\
> +	{							\
> +		return sysfs_emit(buf, fmt, func());		\
> +	}							\
> +	static struct kobj_attribute attr_##name = __ATTR_RO(name)
> +
> +PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version);
> +PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize);
> +PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize);
> +PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace);
> +PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicies);
> +PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms);
> +
> +static const struct attribute *config_attrs[] = {
> +	&attr_version.attr,
> +	&attr_max_object_size.attr,
> +	&attr_total_size.attr,
> +	&attr_used_space.attr,
> +	&attr_supported_policies.attr,
> +	&attr_signed_update_algorithms.attr,
> +	NULL,
> +};
> +
> +static u32 get_policy(const char *name)
> +{
> +	if ((strcmp(name, "db") == 0) ||
> +	    (strcmp(name, "dbx") == 0) ||
> +	    (strcmp(name, "grubdb") == 0) ||
> +	    (strcmp(name, "grubdbx") == 0) ||
> +	    (strcmp(name, "sbat") == 0))
> +		return (PLPKS_WORLDREADABLE | PLPKS_SIGNEDUPDATE);
> +	else
> +		return PLPKS_SIGNEDUPDATE;
> +}
> +
> +static const char * const plpks_var_names[] = {
> +	"PK",
> +	"KEK",
> +	"db",
> +	"dbx",
> +	"grubdb",
> +	"grubdbx",
> +	"sbat",
> +	"moduledb",
> +	"trustedcadb",
> +	NULL,
> +};

Var and key are used somewhat interchangeably? These are keys, I think?
And plpks could have other vars but we're only interested in (at least a
subset of) keys here if I understood right.

I guess the terminology is like that throughout secvar so maybe nothing
to be done.

> +
> +static int plpks_get_variable(const char *key, u64 key_len, u8 *data,
> +			      u64 *data_size)
> +{
> +	struct plpks_var var = {0};
> +	int rc = 0;
> +
> +	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
> +	if (!var.name)
> +		return -ENOMEM;
> +	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
> +			     key_len - 1);
> +	if (rc < 0)
> +		goto err;

Okay I can't work out why it's key_len - 1 rather than key_len.

> +	var.namelen = rc * 2;
> +
> +	var.os = PLPKS_VAR_LINUX;
> +	if (data) {
> +		var.data = data;
> +		var.datalen = *data_size;
> +	}
> +	rc = plpks_read_os_var(&var);
> +
> +	if (rc)
> +		goto err;
> +
> +	*data_size = var.datalen;
> +
> +err:
> +	kfree(var.name);
> +	if (rc && rc != -ENOENT) {
> +		pr_err("Failed to read variable '%s': %d\n", key, rc);
> +		// Return -EIO since userspace probably doesn't care about the
> +		// specific error
> +		rc = -EIO;
> +	}
> +	return rc;
> +}
> +
> +static int plpks_set_variable(const char *key, u64 key_len, u8 *data,
> +			      u64 data_size)
> +{
> +	struct plpks_var var = {0};
> +	int rc = 0;
> +	u64 flags;
> +
> +	// Secure variables need to be prefixed with 8 bytes of flags.
> +	// We only want to perform the write if we have at least one byte of data.
> +	if (data_size <= sizeof(flags))

So it's unstructured 8 byte of flags, not a u64 integer? Why not u8
flags[8] then?

> +		return -EINVAL;
> +
> +	var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL);
> +	if (!var.name)
> +		return -ENOMEM;
> +	rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name,
> +			     key_len - 1);
> +	if (rc < 0)
> +		goto err;
> +	var.namelen = rc * 2;
> +
> +	memcpy(&flags, data, sizeof(flags));
> +
> +	var.datalen = data_size - sizeof(flags);
> +	var.data = data + sizeof(flags);
> +	var.os = PLPKS_VAR_LINUX;
> +	var.policy = get_policy(key);
> +
> +	// Unlike in the read case, the plpks error code can be useful to
> +	// userspace on write, so we return it rather than just -EIO
> +	rc = plpks_signed_update_var(&var, flags);
> +
> +err:
> +	kfree(var.name);
> +	return rc;
> +}
> +
> +// PLPKS dynamic secure boot doesn't give us a format string in the same way OPAL does.
> +// Instead, report the format using the SB_VERSION variable in the keystore.
> +static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
> +{
> +	struct plpks_var var = {0};
> +	ssize_t ret;
> +
> +	var.component = NULL;
> +	// Only the signed variables have null bytes in their names, this one doesn't
> +	var.name = "SB_VERSION";
> +	var.namelen = 10;

Could you make that strlen(var.name) for the benefit of those of us with
missing fingers?

> +	var.datalen = 1;
> +	var.data = kzalloc(1, GFP_KERNEL);

This could just point to a u8 on stack I think?


> +	if (!var.data)
> +		return -ENOMEM;
> +
> +	// Unlike the other vars, SB_VERSION is owned by firmware instead of the OS
> +	ret = plpks_read_fw_var(&var);
> +	if (ret) {
> +		if (ret == -ENOENT) {
> +			ret = snprintf(buf, bufsize, "ibm,plpks-sb-unknown");
> +		} else {
> +			pr_err("Error %ld reading SB_VERSION from firmware\n", ret);
> +			ret = -EIO;
> +		}

Is there a meaningful distinction? Does anything good come of
advertising an unknown format like this?

> +		goto err;
> +	}
> +
> +	// This string is made up by us - the hypervisor doesn't provide us
> +	// with a format string in the way that OPAL firmware does. Hypervisor
> +	// defines SB_VERSION as a "1 byte unsigned integer value".

I'd put the comment about SB_VERSION at the top where you use/define it
or mention it in the comment.

> +	ret = snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu", var.data[0]);
> +
> +err:
> +	kfree(var.data);
> +	return ret;
> +}
> +
> +static int plpks_max_size(u64 *max_size)
> +{
> +	// The max object size reported by the hypervisor is accurate for the
> +	// object itself, but we use the first 8 bytes of data on write as the
> +	// signed update flags, so the max size a user can write is larger.
> +	*max_size = (u64)plpks_get_maxobjectsize() + 8;

You have this 8 open coded twice (once as sizeof(u64)). You could make
it a #define at the top with a brief overview of the hcall format so you
don't need so much commentage for it. Although a note here that the
objsize does not include the flags bytes is good to keep.

Thanks,
Nick

> +
> +	return 0;
> +}
> +
> +
> +static const struct secvar_operations plpks_secvar_ops = {
> +	.get = plpks_get_variable,
> +	.set = plpks_set_variable,
> +	.format = plpks_secvar_format,
> +	.max_size = plpks_max_size,
> +	.config_attrs = config_attrs,
> +	.var_names = plpks_var_names,
> +};
> +
> +static int plpks_secvar_init(void)
> +{
> +	if (!plpks_is_available())
> +		return -ENODEV;
> +
> +	return set_secvar_ops(&plpks_secvar_ops);
> +}
> +machine_device_initcall(pseries, plpks_secvar_init);
> -- 
> 2.39.0


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
  2023-01-20  7:43   ` Andrew Donnellan
@ 2023-01-24  5:24     ` Nicholas Piggin
  -1 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  5:24 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
>
> The secvar object format is only in the device tree under powernv.
> We now have an API call to retrieve it in a generic way, so we should
> use that instead of having to handle the DT here.
>
> Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
> The object format is expected to be the same, so there shouldn't be any
> functional differences between objects retrieved from powernv and
> pseries.
>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
>
> ---
>
> v3: New patch
>
> v4: Pass format buffer size (stefanb, npiggin)
> ---
>  .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++-------
>  1 file changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
> index dee51606d5f4..d4ce91bf3fec 100644
> --- a/security/integrity/platform_certs/load_powerpc.c
> +++ b/security/integrity/platform_certs/load_powerpc.c
> @@ -10,7 +10,6 @@
>  #include <linux/cred.h>
>  #include <linux/err.h>
>  #include <linux/slab.h>
> -#include <linux/of.h>
>  #include <asm/secure_boot.h>
>  #include <asm/secvar.h>
>  #include "keyring_handler.h"
> @@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
>  	void *db = NULL, *dbx = NULL;
>  	u64 dbsize = 0, dbxsize = 0;
>  	int rc = 0;
> -	struct device_node *node;
> +	ssize_t len;
> +	char buf[32];
>  
>  	if (!secvar_ops)
>  		return -ENODEV;
>  
> -	/* The following only applies for the edk2-compat backend. */
> -	node = of_find_compatible_node(NULL, NULL, "ibm,edk2-compat-v1");
> -	if (!node)
> +	len = secvar_ops->format(buf, 32);

sizeof(buf)?

Thanks,
Nick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
@ 2023-01-24  5:24     ` Nicholas Piggin
  0 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-24  5:24 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
>
> The secvar object format is only in the device tree under powernv.
> We now have an API call to retrieve it in a generic way, so we should
> use that instead of having to handle the DT here.
>
> Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
> The object format is expected to be the same, so there shouldn't be any
> functional differences between objects retrieved from powernv and
> pseries.
>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
>
> ---
>
> v3: New patch
>
> v4: Pass format buffer size (stefanb, npiggin)
> ---
>  .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++-------
>  1 file changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
> index dee51606d5f4..d4ce91bf3fec 100644
> --- a/security/integrity/platform_certs/load_powerpc.c
> +++ b/security/integrity/platform_certs/load_powerpc.c
> @@ -10,7 +10,6 @@
>  #include <linux/cred.h>
>  #include <linux/err.h>
>  #include <linux/slab.h>
> -#include <linux/of.h>
>  #include <asm/secure_boot.h>
>  #include <asm/secvar.h>
>  #include "keyring_handler.h"
> @@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
>  	void *db = NULL, *dbx = NULL;
>  	u64 dbsize = 0, dbxsize = 0;
>  	int rc = 0;
> -	struct device_node *node;
> +	ssize_t len;
> +	char buf[32];
>  
>  	if (!secvar_ops)
>  		return -ENODEV;
>  
> -	/* The following only applies for the edk2-compat backend. */
> -	node = of_find_compatible_node(NULL, NULL, "ibm,edk2-compat-v1");
> -	if (!node)
> +	len = secvar_ops->format(buf, 32);

sizeof(buf)?

Thanks,
Nick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
  2023-01-20  7:43   ` Andrew Donnellan
@ 2023-01-24 15:14     ` Mimi Zohar
  -1 siblings, 0 replies; 104+ messages in thread
From: Mimi Zohar @ 2023-01-24 15:14 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, mpe, gjoyce,
	sudhakar, bgray, erichte, joel

On Fri, 2023-01-20 at 18:43 +1100, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
> 
> The secvar object format is only in the device tree under powernv.
> We now have an API call to retrieve it in a generic way, so we should
> use that instead of having to handle the DT here.
> 
> Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
> The object format is expected to be the same, so there shouldn't be any
> functional differences between objects retrieved from powernv and
> pseries.
> 
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> 
> ---
> 
> v3: New patch
> 
> v4: Pass format buffer size (stefanb, npiggin)
> ---
>  .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++-------
>  1 file changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
> index dee51606d5f4..d4ce91bf3fec 100644
> --- a/security/integrity/platform_certs/load_powerpc.c
> +++ b/security/integrity/platform_certs/load_powerpc.c
> @@ -10,7 +10,6 @@
>  #include <linux/cred.h>
>  #include <linux/err.h>
>  #include <linux/slab.h>
> -#include <linux/of.h>
>  #include <asm/secure_boot.h>
>  #include <asm/secvar.h>
>  #include "keyring_handler.h"
> @@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
>  	void *db = NULL, *dbx = NULL;
>  	u64 dbsize = 0, dbxsize = 0;
>  	int rc = 0;
> -	struct device_node *node;
> +	ssize_t len;
> +	char buf[32];
>  
>  	if (!secvar_ops)
>  		return -ENODEV;
>  
> -	/* The following only applies for the edk2-compat backend. */
> -	node = of_find_compatible_node(NULL, NULL, "ibm,edk2-compat-v1");
> -	if (!node)
> +	len = secvar_ops->format(buf, 32);

"powerpc/secvar: Handle format string in the consumer"  defines
opal_secvar_format() for the object format "ibm,secvar-backend".  Here
shouldn't it being returning the format for "ibm,edk2-compat-v1"?

Mimi

> +	if (len <= 0)
>  		return -ENODEV;
>  
> +	// Check for known secure boot implementations from OPAL or PLPKS
> +	if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-sb-v1", buf)) {
> +		pr_err("Unsupported secvar implementation \"%s\", not loading certs\n", buf);
> +		return -ENODEV;
> +	}
> +
>  	/*
>  	 * Get db, and dbx. They might not exist, so it isn't an error if we
>  	 * can't get them.
> @@ -103,8 +108,6 @@ static int __init load_powerpc_certs(void)
>  		kfree(dbx);
>  	}
>  
> -	of_node_put(node);
> -
>  	return rc;
>  }
>  late_initcall(load_powerpc_certs);



^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
@ 2023-01-24 15:14     ` Mimi Zohar
  0 siblings, 0 replies; 104+ messages in thread
From: Mimi Zohar @ 2023-01-24 15:14 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, gjoyce,
	ruscur, joel, gcwilson

On Fri, 2023-01-20 at 18:43 +1100, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
> 
> The secvar object format is only in the device tree under powernv.
> We now have an API call to retrieve it in a generic way, so we should
> use that instead of having to handle the DT here.
> 
> Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
> The object format is expected to be the same, so there shouldn't be any
> functional differences between objects retrieved from powernv and
> pseries.
> 
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> 
> ---
> 
> v3: New patch
> 
> v4: Pass format buffer size (stefanb, npiggin)
> ---
>  .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++-------
>  1 file changed, 10 insertions(+), 7 deletions(-)
> 
> diff --git a/security/integrity/platform_certs/load_powerpc.c b/security/integrity/platform_certs/load_powerpc.c
> index dee51606d5f4..d4ce91bf3fec 100644
> --- a/security/integrity/platform_certs/load_powerpc.c
> +++ b/security/integrity/platform_certs/load_powerpc.c
> @@ -10,7 +10,6 @@
>  #include <linux/cred.h>
>  #include <linux/err.h>
>  #include <linux/slab.h>
> -#include <linux/of.h>
>  #include <asm/secure_boot.h>
>  #include <asm/secvar.h>
>  #include "keyring_handler.h"
> @@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
>  	void *db = NULL, *dbx = NULL;
>  	u64 dbsize = 0, dbxsize = 0;
>  	int rc = 0;
> -	struct device_node *node;
> +	ssize_t len;
> +	char buf[32];
>  
>  	if (!secvar_ops)
>  		return -ENODEV;
>  
> -	/* The following only applies for the edk2-compat backend. */
> -	node = of_find_compatible_node(NULL, NULL, "ibm,edk2-compat-v1");
> -	if (!node)
> +	len = secvar_ops->format(buf, 32);

"powerpc/secvar: Handle format string in the consumer"  defines
opal_secvar_format() for the object format "ibm,secvar-backend".  Here
shouldn't it being returning the format for "ibm,edk2-compat-v1"?

Mimi

> +	if (len <= 0)
>  		return -ENODEV;
>  
> +	// Check for known secure boot implementations from OPAL or PLPKS
> +	if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-sb-v1", buf)) {
> +		pr_err("Unsupported secvar implementation \"%s\", not loading certs\n", buf);
> +		return -ENODEV;
> +	}
> +
>  	/*
>  	 * Get db, and dbx. They might not exist, so it isn't an error if we
>  	 * can't get them.
> @@ -103,8 +108,6 @@ static int __init load_powerpc_certs(void)
>  		kfree(dbx);
>  	}
>  
> -	of_node_put(node);
> -
>  	return rc;
>  }
>  late_initcall(load_powerpc_certs);



^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 23/24] integrity/powerpc: Improve error handling & reporting when loading certs
  2023-01-20  7:43   ` Andrew Donnellan
@ 2023-01-24 15:42     ` Mimi Zohar
  -1 siblings, 0 replies; 104+ messages in thread
From: Mimi Zohar @ 2023-01-24 15:42 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, mpe, gjoyce,
	sudhakar, bgray, erichte, joel

On Fri, 2023-01-20 at 18:43 +1100, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
> 
> A few improvements to load_powerpc.c:
> 
>  - include integrity.h for the pr_fmt()
>  - move all error reporting out of get_cert_list()
>  - use ERR_PTR() to better preserve error detail
>  - don't use pr_err() for missing keys
> 
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

Thanks,

Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 23/24] integrity/powerpc: Improve error handling & reporting when loading certs
@ 2023-01-24 15:42     ` Mimi Zohar
  0 siblings, 0 replies; 104+ messages in thread
From: Mimi Zohar @ 2023-01-24 15:42 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, gjoyce,
	ruscur, joel, gcwilson

On Fri, 2023-01-20 at 18:43 +1100, Andrew Donnellan wrote:
> From: Russell Currey <ruscur@russell.cc>
> 
> A few improvements to load_powerpc.c:
> 
>  - include integrity.h for the pr_fmt()
>  - move all error reporting out of get_cert_list()
>  - use ERR_PTR() to better preserve error detail
>  - don't use pr_err() for missing keys
> 
> Signed-off-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>

Thanks,

Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
  2023-01-24 15:14     ` Mimi Zohar
@ 2023-01-25  0:45       ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-25  0:45 UTC (permalink / raw)
  To: Mimi Zohar, linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, mpe, gjoyce,
	sudhakar, bgray, erichte, joel

On Tue, 2023-01-24 at 10:14 -0500, Mimi Zohar wrote:
> > -       /* The following only applies for the edk2-compat backend.
> > */
> > -       node = of_find_compatible_node(NULL, NULL, "ibm,edk2-
> > compat-v1");
> > -       if (!node)
> > +       len = secvar_ops->format(buf, 32);
> 
> "powerpc/secvar: Handle format string in the consumer"  defines
> opal_secvar_format() for the object format "ibm,secvar-backend". 
> Here
> shouldn't it being returning the format for "ibm,edk2-compat-v1"?

opal_secvar_format() doesn't return "ibm,secvar-backend", it searches
for the device tree node named "ibm,secvar-backend", then reads and
returns the contents of the property "format" under that node.

The expected content of the format property is "ibm,edk2-compat-v1".

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
@ 2023-01-25  0:45       ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-25  0:45 UTC (permalink / raw)
  To: Mimi Zohar, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, gjoyce,
	ruscur, joel, gcwilson

On Tue, 2023-01-24 at 10:14 -0500, Mimi Zohar wrote:
> > -       /* The following only applies for the edk2-compat backend.
> > */
> > -       node = of_find_compatible_node(NULL, NULL, "ibm,edk2-
> > compat-v1");
> > -       if (!node)
> > +       len = secvar_ops->format(buf, 32);
> 
> "powerpc/secvar: Handle format string in the consumer"  defines
> opal_secvar_format() for the object format "ibm,secvar-backend". 
> Here
> shouldn't it being returning the format for "ibm,edk2-compat-v1"?

opal_secvar_format() doesn't return "ibm,secvar-backend", it searches
for the device tree node named "ibm,secvar-backend", then reads and
returns the contents of the property "format" under that node.

The expected content of the format property is "ibm,edk2-compat-v1".

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
  2023-01-24 15:14     ` Mimi Zohar
@ 2023-01-25  2:23       ` Russell Currey
  -1 siblings, 0 replies; 104+ messages in thread
From: Russell Currey @ 2023-01-25  2:23 UTC (permalink / raw)
  To: Mimi Zohar, Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, mpe, gjoyce, sudhakar,
	bgray, erichte, joel

On Tue, 2023-01-24 at 10:14 -0500, Mimi Zohar wrote:
> On Fri, 2023-01-20 at 18:43 +1100, Andrew Donnellan wrote:
> > From: Russell Currey <ruscur@russell.cc>
> > 
> > The secvar object format is only in the device tree under powernv.
> > We now have an API call to retrieve it in a generic way, so we
> > should
> > use that instead of having to handle the DT here.
> > 
> > Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
> > The object format is expected to be the same, so there shouldn't be
> > any
> > functional differences between objects retrieved from powernv and
> > pseries.
> > 
> > Signed-off-by: Russell Currey <ruscur@russell.cc>
> > Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> > 
> > ---
> > 
> > v3: New patch
> > 
> > v4: Pass format buffer size (stefanb, npiggin)
> > ---
> >  .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++---
> > ----
> >  1 file changed, 10 insertions(+), 7 deletions(-)
> > 
> > diff --git a/security/integrity/platform_certs/load_powerpc.c
> > b/security/integrity/platform_certs/load_powerpc.c
> > index dee51606d5f4..d4ce91bf3fec 100644
> > --- a/security/integrity/platform_certs/load_powerpc.c
> > +++ b/security/integrity/platform_certs/load_powerpc.c
> > @@ -10,7 +10,6 @@
> >  #include <linux/cred.h>
> >  #include <linux/err.h>
> >  #include <linux/slab.h>
> > -#include <linux/of.h>
> >  #include <asm/secure_boot.h>
> >  #include <asm/secvar.h>
> >  #include "keyring_handler.h"
> > @@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
> >         void *db = NULL, *dbx = NULL;
> >         u64 dbsize = 0, dbxsize = 0;
> >         int rc = 0;
> > -       struct device_node *node;
> > +       ssize_t len;
> > +       char buf[32];
> >  
> >         if (!secvar_ops)
> >                 return -ENODEV;
> >  
> > -       /* The following only applies for the edk2-compat backend.
> > */
> > -       node = of_find_compatible_node(NULL, NULL, "ibm,edk2-
> > compat-v1");
> > -       if (!node)
> > +       len = secvar_ops->format(buf, 32);
> 
> "powerpc/secvar: Handle format string in the consumer"  defines
> opal_secvar_format() for the object format "ibm,secvar-backend". 
> Here
> shouldn't it being returning the format for "ibm,edk2-compat-v1"?
> 

They end up with the same value.  The DT structure on powernv looks
like this:

/proc/device-tree/ibm,opal/secvar:
name             "secvar"
compatible       "ibm,secvar-backend"
		 "ibm,edk2-compat-v1"
format           "ibm,edk2-compat-v1"
max-var-key-len  00000000 00000400
phandle          0000805a (32858)
max-var-size     00000000 00002000

The existing code is checking for a node compatible with "ibm,edk2-
compat-v1", which would match the node above.  opal_secvar_format()
checks for a node compatible with "ibm,secvar-backend" (again, matching
above) and then returns the contents of the "format" string, which is
"ibm,edk2-compat-v1".

Ultimately it's two different ways of doing the same thing, but this
way load_powerpc_certs() doesn't have to interact with the device tree.

- Russell


> Mimi
> 
> > +       if (len <= 0)
> >                 return -ENODEV;
> >  
> > +       // Check for known secure boot implementations from OPAL or
> > PLPKS
> > +       if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-
> > sb-v1", buf)) {
> > +               pr_err("Unsupported secvar implementation \"%s\",
> > not loading certs\n", buf);
> > +               return -ENODEV;
> > +       }
> > +
> >         /*
> >          * Get db, and dbx. They might not exist, so it isn't an
> > error if we
> >          * can't get them.
> > @@ -103,8 +108,6 @@ static int __init load_powerpc_certs(void)
> >                 kfree(dbx);
> >         }
> >  
> > -       of_node_put(node);
> > -
> >         return rc;
> >  }
> >  late_initcall(load_powerpc_certs);
> 
> 


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
@ 2023-01-25  2:23       ` Russell Currey
  0 siblings, 0 replies; 104+ messages in thread
From: Russell Currey @ 2023-01-25  2:23 UTC (permalink / raw)
  To: Mimi Zohar, Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, gjoyce,
	joel, gcwilson

On Tue, 2023-01-24 at 10:14 -0500, Mimi Zohar wrote:
> On Fri, 2023-01-20 at 18:43 +1100, Andrew Donnellan wrote:
> > From: Russell Currey <ruscur@russell.cc>
> > 
> > The secvar object format is only in the device tree under powernv.
> > We now have an API call to retrieve it in a generic way, so we
> > should
> > use that instead of having to handle the DT here.
> > 
> > Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
> > The object format is expected to be the same, so there shouldn't be
> > any
> > functional differences between objects retrieved from powernv and
> > pseries.
> > 
> > Signed-off-by: Russell Currey <ruscur@russell.cc>
> > Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> > 
> > ---
> > 
> > v3: New patch
> > 
> > v4: Pass format buffer size (stefanb, npiggin)
> > ---
> >  .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++---
> > ----
> >  1 file changed, 10 insertions(+), 7 deletions(-)
> > 
> > diff --git a/security/integrity/platform_certs/load_powerpc.c
> > b/security/integrity/platform_certs/load_powerpc.c
> > index dee51606d5f4..d4ce91bf3fec 100644
> > --- a/security/integrity/platform_certs/load_powerpc.c
> > +++ b/security/integrity/platform_certs/load_powerpc.c
> > @@ -10,7 +10,6 @@
> >  #include <linux/cred.h>
> >  #include <linux/err.h>
> >  #include <linux/slab.h>
> > -#include <linux/of.h>
> >  #include <asm/secure_boot.h>
> >  #include <asm/secvar.h>
> >  #include "keyring_handler.h"
> > @@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
> >         void *db = NULL, *dbx = NULL;
> >         u64 dbsize = 0, dbxsize = 0;
> >         int rc = 0;
> > -       struct device_node *node;
> > +       ssize_t len;
> > +       char buf[32];
> >  
> >         if (!secvar_ops)
> >                 return -ENODEV;
> >  
> > -       /* The following only applies for the edk2-compat backend.
> > */
> > -       node = of_find_compatible_node(NULL, NULL, "ibm,edk2-
> > compat-v1");
> > -       if (!node)
> > +       len = secvar_ops->format(buf, 32);
> 
> "powerpc/secvar: Handle format string in the consumer"  defines
> opal_secvar_format() for the object format "ibm,secvar-backend". 
> Here
> shouldn't it being returning the format for "ibm,edk2-compat-v1"?
> 

They end up with the same value.  The DT structure on powernv looks
like this:

/proc/device-tree/ibm,opal/secvar:
name             "secvar"
compatible       "ibm,secvar-backend"
		 "ibm,edk2-compat-v1"
format           "ibm,edk2-compat-v1"
max-var-key-len  00000000 00000400
phandle          0000805a (32858)
max-var-size     00000000 00002000

The existing code is checking for a node compatible with "ibm,edk2-
compat-v1", which would match the node above.  opal_secvar_format()
checks for a node compatible with "ibm,secvar-backend" (again, matching
above) and then returns the contents of the "format" string, which is
"ibm,edk2-compat-v1".

Ultimately it's two different ways of doing the same thing, but this
way load_powerpc_certs() doesn't have to interact with the device tree.

- Russell


> Mimi
> 
> > +       if (len <= 0)
> >                 return -ENODEV;
> >  
> > +       // Check for known secure boot implementations from OPAL or
> > PLPKS
> > +       if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-
> > sb-v1", buf)) {
> > +               pr_err("Unsupported secvar implementation \"%s\",
> > not loading certs\n", buf);
> > +               return -ENODEV;
> > +       }
> > +
> >         /*
> >          * Get db, and dbx. They might not exist, so it isn't an
> > error if we
> >          * can't get them.
> > @@ -103,8 +108,6 @@ static int __init load_powerpc_certs(void)
> >                 kfree(dbx);
> >         }
> >  
> > -       of_node_put(node);
> > -
> >         return rc;
> >  }
> >  late_initcall(load_powerpc_certs);
> 
> 


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
  2023-01-25  2:23       ` Russell Currey
@ 2023-01-25  2:47         ` Mimi Zohar
  -1 siblings, 0 replies; 104+ messages in thread
From: Mimi Zohar @ 2023-01-25  2:47 UTC (permalink / raw)
  To: Russell Currey, Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, mpe, gjoyce, sudhakar,
	bgray, erichte, joel

On Wed, 2023-01-25 at 13:23 +1100, Russell Currey wrote:
> On Tue, 2023-01-24 at 10:14 -0500, Mimi Zohar wrote:
> > On Fri, 2023-01-20 at 18:43 +1100, Andrew Donnellan wrote:
> > > From: Russell Currey <ruscur@russell.cc>
> > > 
> > > The secvar object format is only in the device tree under powernv.
> > > We now have an API call to retrieve it in a generic way, so we
> > > should
> > > use that instead of having to handle the DT here.
> > > 
> > > Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
> > > The object format is expected to be the same, so there shouldn't be
> > > any
> > > functional differences between objects retrieved from powernv and
> > > pseries.
> > > 
> > > Signed-off-by: Russell Currey <ruscur@russell.cc>
> > > Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> > > 
> > > ---
> > > 
> > > v3: New patch
> > > 
> > > v4: Pass format buffer size (stefanb, npiggin)
> > > ---
> > >  .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++---
> > > ----
> > >  1 file changed, 10 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/security/integrity/platform_certs/load_powerpc.c
> > > b/security/integrity/platform_certs/load_powerpc.c
> > > index dee51606d5f4..d4ce91bf3fec 100644
> > > --- a/security/integrity/platform_certs/load_powerpc.c
> > > +++ b/security/integrity/platform_certs/load_powerpc.c
> > > @@ -10,7 +10,6 @@
> > >  #include <linux/cred.h>
> > >  #include <linux/err.h>
> > >  #include <linux/slab.h>
> > > -#include <linux/of.h>
> > >  #include <asm/secure_boot.h>
> > >  #include <asm/secvar.h>
> > >  #include "keyring_handler.h"
> > > @@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
> > >         void *db = NULL, *dbx = NULL;
> > >         u64 dbsize = 0, dbxsize = 0;
> > >         int rc = 0;
> > > -       struct device_node *node;
> > > +       ssize_t len;
> > > +       char buf[32];
> > >  
> > >         if (!secvar_ops)
> > >                 return -ENODEV;
> > >  
> > > -       /* The following only applies for the edk2-compat backend.
> > > */
> > > -       node = of_find_compatible_node(NULL, NULL, "ibm,edk2-
> > > compat-v1");
> > > -       if (!node)
> > > +       len = secvar_ops->format(buf, 32);
> > 
> > "powerpc/secvar: Handle format string in the consumer"  defines
> > opal_secvar_format() for the object format "ibm,secvar-backend". 
> > Here
> > shouldn't it being returning the format for "ibm,edk2-compat-v1"?
> > 
> 
> They end up with the same value.  The DT structure on powernv looks
> like this:
> 
> /proc/device-tree/ibm,opal/secvar:
> name             "secvar"
> compatible       "ibm,secvar-backend"
> 		 "ibm,edk2-compat-v1"
> format           "ibm,edk2-compat-v1"
> max-var-key-len  00000000 00000400
> phandle          0000805a (32858)
> max-var-size     00000000 00002000
> 
> The existing code is checking for a node compatible with "ibm,edk2-
> compat-v1", which would match the node above.  opal_secvar_format()
> checks for a node compatible with "ibm,secvar-backend" (again, matching
> above) and then returns the contents of the "format" string, which is
> "ibm,edk2-compat-v1".
> 
> Ultimately it's two different ways of doing the same thing, but this
> way load_powerpc_certs() doesn't have to interact with the device tree.

Agreed.  Thank you for the explanation.  To simplify review, I suggest
either adding this explanation in the patch description or stage the
change by replacing the existing "ibm,edk2-compat-v1" usage first.

thanks,

Mimi

> 
> 
> > Mimi
> > 
> > > +       if (len <= 0)
> > >                 return -ENODEV;
> > >  
> > > +       // Check for known secure boot implementations from OPAL or
> > > PLPKS
> > > +       if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-
> > > sb-v1", buf)) {
> > > +               pr_err("Unsupported secvar implementation \"%s\",
> > > not loading certs\n", buf);
> > > +               return -ENODEV;
> > > +       }
> > > +
> > >         /*
> > >          * Get db, and dbx. They might not exist, so it isn't an
> > > error if we
> > >          * can't get them.
> > > @@ -103,8 +108,6 @@ static int __init load_powerpc_certs(void)
> > >                 kfree(dbx);
> > >         }
> > >  
> > > -       of_node_put(node);
> > > -
> > >         return rc;
> > >  }
> > >  late_initcall(load_powerpc_certs);
> > 
> > 
> 



^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
@ 2023-01-25  2:47         ` Mimi Zohar
  0 siblings, 0 replies; 104+ messages in thread
From: Mimi Zohar @ 2023-01-25  2:47 UTC (permalink / raw)
  To: Russell Currey, Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, gjoyce,
	joel, gcwilson

On Wed, 2023-01-25 at 13:23 +1100, Russell Currey wrote:
> On Tue, 2023-01-24 at 10:14 -0500, Mimi Zohar wrote:
> > On Fri, 2023-01-20 at 18:43 +1100, Andrew Donnellan wrote:
> > > From: Russell Currey <ruscur@russell.cc>
> > > 
> > > The secvar object format is only in the device tree under powernv.
> > > We now have an API call to retrieve it in a generic way, so we
> > > should
> > > use that instead of having to handle the DT here.
> > > 
> > > Add support for pseries secvar, with the "ibm,plpks-sb-v1" format.
> > > The object format is expected to be the same, so there shouldn't be
> > > any
> > > functional differences between objects retrieved from powernv and
> > > pseries.
> > > 
> > > Signed-off-by: Russell Currey <ruscur@russell.cc>
> > > Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> > > 
> > > ---
> > > 
> > > v3: New patch
> > > 
> > > v4: Pass format buffer size (stefanb, npiggin)
> > > ---
> > >  .../integrity/platform_certs/load_powerpc.c     | 17 ++++++++++---
> > > ----
> > >  1 file changed, 10 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/security/integrity/platform_certs/load_powerpc.c
> > > b/security/integrity/platform_certs/load_powerpc.c
> > > index dee51606d5f4..d4ce91bf3fec 100644
> > > --- a/security/integrity/platform_certs/load_powerpc.c
> > > +++ b/security/integrity/platform_certs/load_powerpc.c
> > > @@ -10,7 +10,6 @@
> > >  #include <linux/cred.h>
> > >  #include <linux/err.h>
> > >  #include <linux/slab.h>
> > > -#include <linux/of.h>
> > >  #include <asm/secure_boot.h>
> > >  #include <asm/secvar.h>
> > >  #include "keyring_handler.h"
> > > @@ -59,16 +58,22 @@ static int __init load_powerpc_certs(void)
> > >         void *db = NULL, *dbx = NULL;
> > >         u64 dbsize = 0, dbxsize = 0;
> > >         int rc = 0;
> > > -       struct device_node *node;
> > > +       ssize_t len;
> > > +       char buf[32];
> > >  
> > >         if (!secvar_ops)
> > >                 return -ENODEV;
> > >  
> > > -       /* The following only applies for the edk2-compat backend.
> > > */
> > > -       node = of_find_compatible_node(NULL, NULL, "ibm,edk2-
> > > compat-v1");
> > > -       if (!node)
> > > +       len = secvar_ops->format(buf, 32);
> > 
> > "powerpc/secvar: Handle format string in the consumer"  defines
> > opal_secvar_format() for the object format "ibm,secvar-backend". 
> > Here
> > shouldn't it being returning the format for "ibm,edk2-compat-v1"?
> > 
> 
> They end up with the same value.  The DT structure on powernv looks
> like this:
> 
> /proc/device-tree/ibm,opal/secvar:
> name             "secvar"
> compatible       "ibm,secvar-backend"
> 		 "ibm,edk2-compat-v1"
> format           "ibm,edk2-compat-v1"
> max-var-key-len  00000000 00000400
> phandle          0000805a (32858)
> max-var-size     00000000 00002000
> 
> The existing code is checking for a node compatible with "ibm,edk2-
> compat-v1", which would match the node above.  opal_secvar_format()
> checks for a node compatible with "ibm,secvar-backend" (again, matching
> above) and then returns the contents of the "format" string, which is
> "ibm,edk2-compat-v1".
> 
> Ultimately it's two different ways of doing the same thing, but this
> way load_powerpc_certs() doesn't have to interact with the device tree.

Agreed.  Thank you for the explanation.  To simplify review, I suggest
either adding this explanation in the patch description or stage the
change by replacing the existing "ibm,edk2-compat-v1" usage first.

thanks,

Mimi

> 
> 
> > Mimi
> > 
> > > +       if (len <= 0)
> > >                 return -ENODEV;
> > >  
> > > +       // Check for known secure boot implementations from OPAL or
> > > PLPKS
> > > +       if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-
> > > sb-v1", buf)) {
> > > +               pr_err("Unsupported secvar implementation \"%s\",
> > > not loading certs\n", buf);
> > > +               return -ENODEV;
> > > +       }
> > > +
> > >         /*
> > >          * Get db, and dbx. They might not exist, so it isn't an
> > > error if we
> > >          * can't get them.
> > > @@ -103,8 +108,6 @@ static int __init load_powerpc_certs(void)
> > >                 kfree(dbx);
> > >         }
> > >  
> > > -       of_node_put(node);
> > > -
> > >         return rc;
> > >  }
> > >  late_initcall(load_powerpc_certs);
> > 
> > 
> 



^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
  2023-01-24  4:40       ` Andrew Donnellan
@ 2023-01-25  3:59         ` Michael Ellerman
  -1 siblings, 0 replies; 104+ messages in thread
From: Michael Ellerman @ 2023-01-25  3:59 UTC (permalink / raw)
  To: Andrew Donnellan, Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

Andrew Donnellan <ajd@linux.ibm.com> writes:
> On Tue, 2023-01-24 at 14:36 +1000, Nicholas Piggin wrote:
>> 
>> > +       prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
>> > +       if (prop) {
>> > +               ospasswordlength = (u16)len;
>> > +               ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
>> > +               if (!ospassword) {
>> > +                       of_remove_property(of_chosen, prop);
>> > +                       return -ENOMEM;
>> > +               }
>> > +               memcpy(ospassword, prop->value, len);
>> > +               return of_remove_property(of_chosen, prop);
>> 
>> Why do you remove the property afterward?
>
> Because otherwise the password will be sitting around in /proc/device-
> tree for the world to go and read.

The above removes it from the unflattened tree, but it will still exist
in the flattened tree, which is readable by root in /sys/firmware/fdt.

I'm not sure if that's a major security problem, but it does seem risky.

To scrub it from the flat tree you'd need to have an early_init_dt style
routine that finds the password early, saves the value somewhere for the
plpks driver, and then zeroes out the value in the flat tree. See the
example of rng-seed in early_init_dt_scan_chosen().

cheers

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
@ 2023-01-25  3:59         ` Michael Ellerman
  0 siblings, 0 replies; 104+ messages in thread
From: Michael Ellerman @ 2023-01-25  3:59 UTC (permalink / raw)
  To: Andrew Donnellan, Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

Andrew Donnellan <ajd@linux.ibm.com> writes:
> On Tue, 2023-01-24 at 14:36 +1000, Nicholas Piggin wrote:
>> 
>> > +       prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
>> > +       if (prop) {
>> > +               ospasswordlength = (u16)len;
>> > +               ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
>> > +               if (!ospassword) {
>> > +                       of_remove_property(of_chosen, prop);
>> > +                       return -ENOMEM;
>> > +               }
>> > +               memcpy(ospassword, prop->value, len);
>> > +               return of_remove_property(of_chosen, prop);
>> 
>> Why do you remove the property afterward?
>
> Because otherwise the password will be sitting around in /proc/device-
> tree for the world to go and read.

The above removes it from the unflattened tree, but it will still exist
in the flattened tree, which is readable by root in /sys/firmware/fdt.

I'm not sure if that's a major security problem, but it does seem risky.

To scrub it from the flat tree you'd need to have an early_init_dt style
routine that finds the password early, saves the value somewhere for the
plpks driver, and then zeroes out the value in the flat tree. See the
example of rng-seed in early_init_dt_scan_chosen().

cheers

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
  2023-01-20  7:42   ` Andrew Donnellan
@ 2023-01-25 13:09     ` Michael Ellerman
  -1 siblings, 0 replies; 104+ messages in thread
From: Michael Ellerman @ 2023-01-25 13:09 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, ruscur, zohar, gjoyce,
	sudhakar, bgray, erichte, joel

Andrew Donnellan <ajd@linux.ibm.com> writes:
> A number of structures and buffers passed to PKS hcalls have alignment
> requirements, which could on occasion cause problems:
>
> - Authorisation structures must be 16-byte aligned and must not cross a
>   page boundary
>
> - Label structures must not cross page boundaries
>
> - Password output buffers must not cross page boundaries
>
> Round up the allocations of these structures/buffers to the next power of
> 2 to make sure this happens.

It's not the *next* power of 2, it's the *nearest* power of 2, including
the initial value if it's already a power of 2.

That in conjunction with slab's guarantee that power of 2 sized objects
are naturally aligned, and that the relevant structs are smaller than a
page, is what makes this actually work.

So I think the patch is fine, but the change log and comments probably
need to be a bit clearer.

cheers

> Reported-by: Benjamin Gray <bgray@linux.ibm.com>
> Fixes: 2454a7af0f2a ("powerpc/pseries: define driver for Platform KeyStore")
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> Reviewed-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
>
> ---
>
> v3: Merge plpks fixes and signed update series with secvar series
>
> v4: Fix typo in commit message
>
>     Move up in series (npiggin)
> ---
>  arch/powerpc/platforms/pseries/plpks.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
> index 9e85b6d85b0b..a01cf2ff140a 100644
> --- a/arch/powerpc/platforms/pseries/plpks.c
> +++ b/arch/powerpc/platforms/pseries/plpks.c
> @@ -126,7 +126,8 @@ static int plpks_gen_password(void)
>  	u8 *password, consumer = PKS_OS_OWNER;
>  	int rc;
>  
> -	password = kzalloc(maxpwsize, GFP_KERNEL);
> +	// The password must not cross a page boundary, so we align to the next power of 2
> +	password = kzalloc(roundup_pow_of_two(maxpwsize), GFP_KERNEL);
>  	if (!password)
>  		return -ENOMEM;
>  
> @@ -162,7 +163,9 @@ static struct plpks_auth *construct_auth(u8 consumer)
>  	if (consumer > PKS_OS_OWNER)
>  		return ERR_PTR(-EINVAL);
>  
> -	auth = kzalloc(struct_size(auth, password, maxpwsize), GFP_KERNEL);
> +	// The auth structure must not cross a page boundary and must be
> +	// 16 byte aligned. We align to the next largest power of 2
> +	auth = kzalloc(roundup_pow_of_two(struct_size(auth, password, maxpwsize)), GFP_KERNEL);
>  	if (!auth)
>  		return ERR_PTR(-ENOMEM);
>  
> @@ -196,7 +199,8 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
>  	if (component && slen > sizeof(label->attr.prefix))
>  		return ERR_PTR(-EINVAL);
>  
> -	label = kzalloc(sizeof(*label), GFP_KERNEL);
> +	// The label structure must not cross a page boundary, so we align to the next power of 2
> +	label = kzalloc(roundup_pow_of_two(sizeof(*label)), GFP_KERNEL);
>  	if (!label)
>  		return ERR_PTR(-ENOMEM);
>  
> -- 
> 2.39.0

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
@ 2023-01-25 13:09     ` Michael Ellerman
  0 siblings, 0 replies; 104+ messages in thread
From: Michael Ellerman @ 2023-01-25 13:09 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, joel, ruscur, gcwilson

Andrew Donnellan <ajd@linux.ibm.com> writes:
> A number of structures and buffers passed to PKS hcalls have alignment
> requirements, which could on occasion cause problems:
>
> - Authorisation structures must be 16-byte aligned and must not cross a
>   page boundary
>
> - Label structures must not cross page boundaries
>
> - Password output buffers must not cross page boundaries
>
> Round up the allocations of these structures/buffers to the next power of
> 2 to make sure this happens.

It's not the *next* power of 2, it's the *nearest* power of 2, including
the initial value if it's already a power of 2.

That in conjunction with slab's guarantee that power of 2 sized objects
are naturally aligned, and that the relevant structs are smaller than a
page, is what makes this actually work.

So I think the patch is fine, but the change log and comments probably
need to be a bit clearer.

cheers

> Reported-by: Benjamin Gray <bgray@linux.ibm.com>
> Fixes: 2454a7af0f2a ("powerpc/pseries: define driver for Platform KeyStore")
> Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> Reviewed-by: Russell Currey <ruscur@russell.cc>
> Signed-off-by: Russell Currey <ruscur@russell.cc>
>
> ---
>
> v3: Merge plpks fixes and signed update series with secvar series
>
> v4: Fix typo in commit message
>
>     Move up in series (npiggin)
> ---
>  arch/powerpc/platforms/pseries/plpks.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/platforms/pseries/plpks.c b/arch/powerpc/platforms/pseries/plpks.c
> index 9e85b6d85b0b..a01cf2ff140a 100644
> --- a/arch/powerpc/platforms/pseries/plpks.c
> +++ b/arch/powerpc/platforms/pseries/plpks.c
> @@ -126,7 +126,8 @@ static int plpks_gen_password(void)
>  	u8 *password, consumer = PKS_OS_OWNER;
>  	int rc;
>  
> -	password = kzalloc(maxpwsize, GFP_KERNEL);
> +	// The password must not cross a page boundary, so we align to the next power of 2
> +	password = kzalloc(roundup_pow_of_two(maxpwsize), GFP_KERNEL);
>  	if (!password)
>  		return -ENOMEM;
>  
> @@ -162,7 +163,9 @@ static struct plpks_auth *construct_auth(u8 consumer)
>  	if (consumer > PKS_OS_OWNER)
>  		return ERR_PTR(-EINVAL);
>  
> -	auth = kzalloc(struct_size(auth, password, maxpwsize), GFP_KERNEL);
> +	// The auth structure must not cross a page boundary and must be
> +	// 16 byte aligned. We align to the next largest power of 2
> +	auth = kzalloc(roundup_pow_of_two(struct_size(auth, password, maxpwsize)), GFP_KERNEL);
>  	if (!auth)
>  		return ERR_PTR(-ENOMEM);
>  
> @@ -196,7 +199,8 @@ static struct label *construct_label(char *component, u8 varos, u8 *name,
>  	if (component && slen > sizeof(label->attr.prefix))
>  		return ERR_PTR(-EINVAL);
>  
> -	label = kzalloc(sizeof(*label), GFP_KERNEL);
> +	// The label structure must not cross a page boundary, so we align to the next power of 2
> +	label = kzalloc(roundup_pow_of_two(sizeof(*label)), GFP_KERNEL);
>  	if (!label)
>  		return ERR_PTR(-ENOMEM);
>  
> -- 
> 2.39.0

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
  2023-01-25 13:09     ` Michael Ellerman
@ 2023-01-26 17:19       ` Segher Boessenkool
  -1 siblings, 0 replies; 104+ messages in thread
From: Segher Boessenkool @ 2023-01-26 17:19 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: Andrew Donnellan, linuxppc-dev, linux-integrity, sudhakar, bgray,
	erichte, gregkh, nayna, linux-kernel, zohar, gjoyce, joel,
	ruscur, gcwilson

On Thu, Jan 26, 2023 at 12:09:53AM +1100, Michael Ellerman wrote:
> Andrew Donnellan <ajd@linux.ibm.com> writes:
> > A number of structures and buffers passed to PKS hcalls have alignment
> > requirements, which could on occasion cause problems:
> >
> > - Authorisation structures must be 16-byte aligned and must not cross a
> >   page boundary
> >
> > - Label structures must not cross page boundaries
> >
> > - Password output buffers must not cross page boundaries
> >
> > Round up the allocations of these structures/buffers to the next power of
> > 2 to make sure this happens.
> 
> It's not the *next* power of 2, it's the *nearest* power of 2, including
> the initial value if it's already a power of 2.

It's not the nearest either, the nearest power of two to 65 is 64.  You
could say "but, round up" to which I would say "round?"  :-P

"Adjust the allocation size to be the smallest power of two greater than
or equal to the given size."

"Pad to a power of two" in shorthand.  "Padded to a power of two if
necessary" if you want to emphasise it can be a no-op.


Segher

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
@ 2023-01-26 17:19       ` Segher Boessenkool
  0 siblings, 0 replies; 104+ messages in thread
From: Segher Boessenkool @ 2023-01-26 17:19 UTC (permalink / raw)
  To: Michael Ellerman
  Cc: gjoyce, Andrew Donnellan, erichte, gregkh, nayna, linux-kernel,
	zohar, sudhakar, ruscur, joel, bgray, linux-integrity, gcwilson,
	linuxppc-dev

On Thu, Jan 26, 2023 at 12:09:53AM +1100, Michael Ellerman wrote:
> Andrew Donnellan <ajd@linux.ibm.com> writes:
> > A number of structures and buffers passed to PKS hcalls have alignment
> > requirements, which could on occasion cause problems:
> >
> > - Authorisation structures must be 16-byte aligned and must not cross a
> >   page boundary
> >
> > - Label structures must not cross page boundaries
> >
> > - Password output buffers must not cross page boundaries
> >
> > Round up the allocations of these structures/buffers to the next power of
> > 2 to make sure this happens.
> 
> It's not the *next* power of 2, it's the *nearest* power of 2, including
> the initial value if it's already a power of 2.

It's not the nearest either, the nearest power of two to 65 is 64.  You
could say "but, round up" to which I would say "round?"  :-P

"Adjust the allocation size to be the smallest power of two greater than
or equal to the given size."

"Pad to a power of two" in shorthand.  "Padded to a power of two if
necessary" if you want to emphasise it can be a no-op.


Segher

^ permalink raw reply	[flat|nested] 104+ messages in thread

* RE: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
  2023-01-26 17:19       ` Segher Boessenkool
@ 2023-01-26 17:31         ` David Laight
  -1 siblings, 0 replies; 104+ messages in thread
From: David Laight @ 2023-01-26 17:31 UTC (permalink / raw)
  To: 'Segher Boessenkool', Michael Ellerman
  Cc: gjoyce, Andrew Donnellan, erichte, gregkh, nayna, linux-kernel,
	zohar, sudhakar, ruscur, joel, bgray, linux-integrity, gcwilson,
	linuxppc-dev

From: Segher Boessenkool
> Sent: 26 January 2023 17:19
> 
> On Thu, Jan 26, 2023 at 12:09:53AM +1100, Michael Ellerman wrote:
> > Andrew Donnellan <ajd@linux.ibm.com> writes:
> > > A number of structures and buffers passed to PKS hcalls have alignment
> > > requirements, which could on occasion cause problems:
> > >
> > > - Authorisation structures must be 16-byte aligned and must not cross a
> > >   page boundary
> > >
> > > - Label structures must not cross page boundaries
> > >
> > > - Password output buffers must not cross page boundaries
> > >
> > > Round up the allocations of these structures/buffers to the next power of
> > > 2 to make sure this happens.
> >
> > It's not the *next* power of 2, it's the *nearest* power of 2, including
> > the initial value if it's already a power of 2.
> 
> It's not the nearest either, the nearest power of two to 65 is 64.  You
> could say "but, round up" to which I would say "round?"  :-P
> 
> "Adjust the allocation size to be the smallest power of two greater than
> or equal to the given size."
> 
> "Pad to a power of two" in shorthand.  "Padded to a power of two if
> necessary" if you want to emphasise it can be a no-op.

Changing the size to kzalloc() doesn't help.
The alignment depends on the allocator and is only required to have
a relatively small alignment (ARCH_MINALIGN?) regardless of the size.

IIRC one of the allocators adds a small header to every item.
It won't return 16 byte aligned items at all.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)


^ permalink raw reply	[flat|nested] 104+ messages in thread

* RE: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
@ 2023-01-26 17:31         ` David Laight
  0 siblings, 0 replies; 104+ messages in thread
From: David Laight @ 2023-01-26 17:31 UTC (permalink / raw)
  To: 'Segher Boessenkool', Michael Ellerman
  Cc: sudhakar, bgray, Andrew Donnellan, erichte, gregkh, nayna,
	linux-kernel, zohar, gjoyce, joel, ruscur, linux-integrity,
	gcwilson, linuxppc-dev

From: Segher Boessenkool
> Sent: 26 January 2023 17:19
> 
> On Thu, Jan 26, 2023 at 12:09:53AM +1100, Michael Ellerman wrote:
> > Andrew Donnellan <ajd@linux.ibm.com> writes:
> > > A number of structures and buffers passed to PKS hcalls have alignment
> > > requirements, which could on occasion cause problems:
> > >
> > > - Authorisation structures must be 16-byte aligned and must not cross a
> > >   page boundary
> > >
> > > - Label structures must not cross page boundaries
> > >
> > > - Password output buffers must not cross page boundaries
> > >
> > > Round up the allocations of these structures/buffers to the next power of
> > > 2 to make sure this happens.
> >
> > It's not the *next* power of 2, it's the *nearest* power of 2, including
> > the initial value if it's already a power of 2.
> 
> It's not the nearest either, the nearest power of two to 65 is 64.  You
> could say "but, round up" to which I would say "round?"  :-P
> 
> "Adjust the allocation size to be the smallest power of two greater than
> or equal to the given size."
> 
> "Pad to a power of two" in shorthand.  "Padded to a power of two if
> necessary" if you want to emphasise it can be a no-op.

Changing the size to kzalloc() doesn't help.
The alignment depends on the allocator and is only required to have
a relatively small alignment (ARCH_MINALIGN?) regardless of the size.

IIRC one of the allocators adds a small header to every item.
It won't return 16 byte aligned items at all.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
  2023-01-26 17:31         ` David Laight
@ 2023-01-27  3:20           ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-27  3:20 UTC (permalink / raw)
  To: David Laight, 'Segher Boessenkool', Michael Ellerman
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, linux-integrity, gcwilson, linuxppc-dev

On Thu, 2023-01-26 at 17:31 +0000, David Laight wrote:
> Changing the size to kzalloc() doesn't help.
> The alignment depends on the allocator and is only required to have
> a relatively small alignment (ARCH_MINALIGN?) regardless of the size.
> 
> IIRC one of the allocators adds a small header to every item.
> It won't return 16 byte aligned items at all.

I'm relying on the behaviour described in Documentation/core-
api/memory-allocation.rst:

    The address of a chunk allocated with kmalloc is aligned to at
    least ARCH_KMALLOC_MINALIGN bytes. For sizes which are a power of
    two, the alignment is also guaranteed to be at least the respective
    size.

Is this wrong?


Andrew

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
@ 2023-01-27  3:20           ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-27  3:20 UTC (permalink / raw)
  To: David Laight, 'Segher Boessenkool', Michael Ellerman
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, joel, ruscur, linux-integrity, gcwilson, linuxppc-dev

On Thu, 2023-01-26 at 17:31 +0000, David Laight wrote:
> Changing the size to kzalloc() doesn't help.
> The alignment depends on the allocator and is only required to have
> a relatively small alignment (ARCH_MINALIGN?) regardless of the size.
> 
> IIRC one of the allocators adds a small header to every item.
> It won't return 16 byte aligned items at all.

I'm relying on the behaviour described in Documentation/core-
api/memory-allocation.rst:

    The address of a chunk allocated with kmalloc is aligned to at
    least ARCH_KMALLOC_MINALIGN bytes. For sizes which are a power of
    two, the alignment is also guaranteed to be at least the respective
    size.

Is this wrong?


Andrew

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* RE: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
  2023-01-27  3:20           ` Andrew Donnellan
@ 2023-01-27  9:05             ` David Laight
  -1 siblings, 0 replies; 104+ messages in thread
From: David Laight @ 2023-01-27  9:05 UTC (permalink / raw)
  To: 'Andrew Donnellan', 'Segher Boessenkool',
	Michael Ellerman
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, linux-integrity, gcwilson, linuxppc-dev

From: Andrew Donnellan
> Sent: 27 January 2023 03:21
> 
> On Thu, 2023-01-26 at 17:31 +0000, David Laight wrote:
> > Changing the size to kzalloc() doesn't help.
> > The alignment depends on the allocator and is only required to have
> > a relatively small alignment (ARCH_MINALIGN?) regardless of the size.
> >
> > IIRC one of the allocators adds a small header to every item.
> > It won't return 16 byte aligned items at all.
> 
> I'm relying on the behaviour described in Documentation/core-
> api/memory-allocation.rst:
> 
>     The address of a chunk allocated with kmalloc is aligned to at
>     least ARCH_KMALLOC_MINALIGN bytes. For sizes which are a power of
>     two, the alignment is also guaranteed to be at least the respective
>     size.
> 
> Is this wrong?

The alignment for power of two doesn't match what I've inferred
from reading comments on other patches.

It is true for dma_malloc_coherent() - that does guarantee that a
16k allocate will be aligned on a 16k physical address boundary.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 104+ messages in thread

* RE: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
@ 2023-01-27  9:05             ` David Laight
  0 siblings, 0 replies; 104+ messages in thread
From: David Laight @ 2023-01-27  9:05 UTC (permalink / raw)
  To: 'Andrew Donnellan', 'Segher Boessenkool',
	Michael Ellerman
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, joel, ruscur, linux-integrity, gcwilson, linuxppc-dev

From: Andrew Donnellan
> Sent: 27 January 2023 03:21
> 
> On Thu, 2023-01-26 at 17:31 +0000, David Laight wrote:
> > Changing the size to kzalloc() doesn't help.
> > The alignment depends on the allocator and is only required to have
> > a relatively small alignment (ARCH_MINALIGN?) regardless of the size.
> >
> > IIRC one of the allocators adds a small header to every item.
> > It won't return 16 byte aligned items at all.
> 
> I'm relying on the behaviour described in Documentation/core-
> api/memory-allocation.rst:
> 
>     The address of a chunk allocated with kmalloc is aligned to at
>     least ARCH_KMALLOC_MINALIGN bytes. For sizes which are a power of
>     two, the alignment is also guaranteed to be at least the respective
>     size.
> 
> Is this wrong?

The alignment for power of two doesn't match what I've inferred
from reading comments on other patches.

It is true for dma_malloc_coherent() - that does guarantee that a
16k allocate will be aligned on a 16k physical address boundary.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
  2023-01-26 17:19       ` Segher Boessenkool
@ 2023-01-27 10:52         ` Michael Ellerman
  -1 siblings, 0 replies; 104+ messages in thread
From: Michael Ellerman @ 2023-01-27 10:52 UTC (permalink / raw)
  To: Segher Boessenkool
  Cc: Andrew Donnellan, linuxppc-dev, linux-integrity, sudhakar, bgray,
	erichte, gregkh, nayna, linux-kernel, zohar, gjoyce, joel,
	ruscur, gcwilson

Segher Boessenkool <segher@kernel.crashing.org> writes:
> On Thu, Jan 26, 2023 at 12:09:53AM +1100, Michael Ellerman wrote:
>> Andrew Donnellan <ajd@linux.ibm.com> writes:
>> > A number of structures and buffers passed to PKS hcalls have alignment
>> > requirements, which could on occasion cause problems:
>> >
>> > - Authorisation structures must be 16-byte aligned and must not cross a
>> >   page boundary
>> >
>> > - Label structures must not cross page boundaries
>> >
>> > - Password output buffers must not cross page boundaries
>> >
>> > Round up the allocations of these structures/buffers to the next power of
>> > 2 to make sure this happens.
>> 
>> It's not the *next* power of 2, it's the *nearest* power of 2, including
>> the initial value if it's already a power of 2.
>
> It's not the nearest either, the nearest power of two to 65 is 64.  You
> could say "but, round up" to which I would say "round?"  :-P

OK you got me there :)

The function name makes it pretty clear that it will round *up* to the
nearest power of 2 but you're right the comment should also make that
clear.

> "Adjust the allocation size to be the smallest power of two greater than
> or equal to the given size."
>
> "Pad to a power of two" in shorthand.  "Padded to a power of two if
> necessary" if you want to emphasise it can be a no-op.

The initial wording implied that it would always over-allocate so yes I
think it's important to make it clear that it doesn't round up if it
doesn't need to.

cheers

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
@ 2023-01-27 10:52         ` Michael Ellerman
  0 siblings, 0 replies; 104+ messages in thread
From: Michael Ellerman @ 2023-01-27 10:52 UTC (permalink / raw)
  To: Segher Boessenkool
  Cc: gjoyce, Andrew Donnellan, erichte, gregkh, nayna, linux-kernel,
	zohar, sudhakar, ruscur, joel, bgray, linux-integrity, gcwilson,
	linuxppc-dev

Segher Boessenkool <segher@kernel.crashing.org> writes:
> On Thu, Jan 26, 2023 at 12:09:53AM +1100, Michael Ellerman wrote:
>> Andrew Donnellan <ajd@linux.ibm.com> writes:
>> > A number of structures and buffers passed to PKS hcalls have alignment
>> > requirements, which could on occasion cause problems:
>> >
>> > - Authorisation structures must be 16-byte aligned and must not cross a
>> >   page boundary
>> >
>> > - Label structures must not cross page boundaries
>> >
>> > - Password output buffers must not cross page boundaries
>> >
>> > Round up the allocations of these structures/buffers to the next power of
>> > 2 to make sure this happens.
>> 
>> It's not the *next* power of 2, it's the *nearest* power of 2, including
>> the initial value if it's already a power of 2.
>
> It's not the nearest either, the nearest power of two to 65 is 64.  You
> could say "but, round up" to which I would say "round?"  :-P

OK you got me there :)

The function name makes it pretty clear that it will round *up* to the
nearest power of 2 but you're right the comment should also make that
clear.

> "Adjust the allocation size to be the smallest power of two greater than
> or equal to the given size."
>
> "Pad to a power of two" in shorthand.  "Padded to a power of two if
> necessary" if you want to emphasise it can be a no-op.

The initial wording implied that it would always over-allocate so yes I
think it's important to make it clear that it doesn't round up if it
doesn't need to.

cheers

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
  2023-01-27  3:20           ` Andrew Donnellan
@ 2023-01-27 11:08             ` Michael Ellerman
  -1 siblings, 0 replies; 104+ messages in thread
From: Michael Ellerman @ 2023-01-27 11:08 UTC (permalink / raw)
  To: Andrew Donnellan, David Laight, 'Segher Boessenkool'
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, linux-integrity, gcwilson, linuxppc-dev

Andrew Donnellan <ajd@linux.ibm.com> writes:
> On Thu, 2023-01-26 at 17:31 +0000, David Laight wrote:
>> Changing the size to kzalloc() doesn't help.
>> The alignment depends on the allocator and is only required to have
>> a relatively small alignment (ARCH_MINALIGN?) regardless of the size.
>> 
>> IIRC one of the allocators adds a small header to every item.
>> It won't return 16 byte aligned items at all.
>
> I'm relying on the behaviour described in Documentation/core-
> api/memory-allocation.rst:
>
>     The address of a chunk allocated with kmalloc is aligned to at
>     least ARCH_KMALLOC_MINALIGN bytes. For sizes which are a power of
>     two, the alignment is also guaranteed to be at least the respective
>     size.
>
> Is this wrong?

I believe it's correct.

For SLAB and SLUB it boils down to:
  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/slab_common.c?commit=830b3c68c1fb1e9176028d02ef86f3cf76aa2476#n640

That's where the kmalloc slabs are created (see create_kmalloc_cache())
just below.

If you create your own slab (with kmem_cache_create()) then the
alignment is up to you, so that's why there's no power-of-2 logic in
calculate_alignment().

And SLOB (which we don't use) does something similar:
  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/slob.c?commit=830b3c68c1fb1e9176028d02ef86f3cf76aa2476#n493

cheers

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers
@ 2023-01-27 11:08             ` Michael Ellerman
  0 siblings, 0 replies; 104+ messages in thread
From: Michael Ellerman @ 2023-01-27 11:08 UTC (permalink / raw)
  To: Andrew Donnellan, David Laight, 'Segher Boessenkool'
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, joel, ruscur, linux-integrity, gcwilson, linuxppc-dev

Andrew Donnellan <ajd@linux.ibm.com> writes:
> On Thu, 2023-01-26 at 17:31 +0000, David Laight wrote:
>> Changing the size to kzalloc() doesn't help.
>> The alignment depends on the allocator and is only required to have
>> a relatively small alignment (ARCH_MINALIGN?) regardless of the size.
>> 
>> IIRC one of the allocators adds a small header to every item.
>> It won't return 16 byte aligned items at all.
>
> I'm relying on the behaviour described in Documentation/core-
> api/memory-allocation.rst:
>
>     The address of a chunk allocated with kmalloc is aligned to at
>     least ARCH_KMALLOC_MINALIGN bytes. For sizes which are a power of
>     two, the alignment is also guaranteed to be at least the respective
>     size.
>
> Is this wrong?

I believe it's correct.

For SLAB and SLUB it boils down to:
  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/slab_common.c?commit=830b3c68c1fb1e9176028d02ef86f3cf76aa2476#n640

That's where the kmalloc slabs are created (see create_kmalloc_cache())
just below.

If you create your own slab (with kmem_cache_create()) then the
alignment is up to you, so that's why there's no power-of-2 logic in
calculate_alignment().

And SLOB (which we don't use) does something similar:
  https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/slob.c?commit=830b3c68c1fb1e9176028d02ef86f3cf76aa2476#n493

cheers

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 16/24] powerpc/pseries: Implement signed update for PLPKS objects
  2023-01-24  4:16     ` Nicholas Piggin
@ 2023-01-30  4:43       ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-30  4:43 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Tue, 2023-01-24 at 14:16 +1000, Nicholas Piggin wrote:
> > diff --git a/arch/powerpc/platforms/pseries/plpks.c
> > b/arch/powerpc/platforms/pseries/plpks.c
> > index 1189246b03dc..796ed5544ee5 100644
> > --- a/arch/powerpc/platforms/pseries/plpks.c
> > +++ b/arch/powerpc/platforms/pseries/plpks.c
> > @@ -81,6 +81,12 @@ static int pseries_status_to_err(int rc)
> >                 err = -ENOENT;
> >                 break;
> >         case H_BUSY:
> > +       case H_LONG_BUSY_ORDER_1_MSEC:
> > +       case H_LONG_BUSY_ORDER_10_MSEC:
> > +       case H_LONG_BUSY_ORDER_100_MSEC:
> > +       case H_LONG_BUSY_ORDER_1_SEC:
> > +       case H_LONG_BUSY_ORDER_10_SEC:
> > +       case H_LONG_BUSY_ORDER_100_SEC:
> >                 err = -EBUSY;
> >                 break;
> >         case H_AUTHORITY:
> 
> This is a bit sad to maintain here. It's duplicating bits with
> hvcs_convert, and a bunch of open coded places. Probably not the
> series to do anything about. Would be nice if we could standardise
> it though.

Agreed - though we're not going to touch it in this series.

> 
> > @@ -184,14 +190,17 @@ static struct label *construct_label(char
> > *component, u8 varos, u8 *name,
> >                                      u16 namelen)
> >  {
> >         struct label *label;
> > -       size_t slen;
> > +       size_t slen = 0;
> >  
> >         if (!name || namelen > PLPKS_MAX_NAME_SIZE)
> >                 return ERR_PTR(-EINVAL);
> >  
> > -       slen = strlen(component);
> > -       if (component && slen > sizeof(label->attr.prefix))
> > -               return ERR_PTR(-EINVAL);
> > +       // Support NULL component for signed updates
> > +       if (component) {
> > +               slen = strlen(component);
> > +               if (slen > sizeof(label->attr.prefix))
> > +                       return ERR_PTR(-EINVAL);
> > +       }
> 
> Is this already a bug? Code checks for component != NULL but
> previously
> calls strlen which would oops on NULL component AFAIKS. Granted
> nothing
> is actually using any of this these days.

True, it should have been checking for NULL first, but as you say no-
one is using it.

> 
> It already seems like it's supposed to be allowed to rad NULL
> component
> with read_var though? Why the differences, why not always allow NULL
> component? (I assume there is some reason, I just don't know anything
> about secvar or secure boot).

I think the comment confuses more than it clarifies, I'll remove it.

As you say, read_var() should work fine with component == NULL, though
write_var() checks it. The only rule I can find in the spec is that
signed update calls *must* set the component to NULL. I'm seeking
clarification on that.

> > +EXPORT_SYMBOL(plpks_signed_update_var);
> 
> Sorry I missed it before -- can this be a _GPL export?

Indeed it should be - actually, I should check if I can get rid of the
export completely...

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 16/24] powerpc/pseries: Implement signed update for PLPKS objects
@ 2023-01-30  4:43       ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-30  4:43 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Tue, 2023-01-24 at 14:16 +1000, Nicholas Piggin wrote:
> > diff --git a/arch/powerpc/platforms/pseries/plpks.c
> > b/arch/powerpc/platforms/pseries/plpks.c
> > index 1189246b03dc..796ed5544ee5 100644
> > --- a/arch/powerpc/platforms/pseries/plpks.c
> > +++ b/arch/powerpc/platforms/pseries/plpks.c
> > @@ -81,6 +81,12 @@ static int pseries_status_to_err(int rc)
> >                 err = -ENOENT;
> >                 break;
> >         case H_BUSY:
> > +       case H_LONG_BUSY_ORDER_1_MSEC:
> > +       case H_LONG_BUSY_ORDER_10_MSEC:
> > +       case H_LONG_BUSY_ORDER_100_MSEC:
> > +       case H_LONG_BUSY_ORDER_1_SEC:
> > +       case H_LONG_BUSY_ORDER_10_SEC:
> > +       case H_LONG_BUSY_ORDER_100_SEC:
> >                 err = -EBUSY;
> >                 break;
> >         case H_AUTHORITY:
> 
> This is a bit sad to maintain here. It's duplicating bits with
> hvcs_convert, and a bunch of open coded places. Probably not the
> series to do anything about. Would be nice if we could standardise
> it though.

Agreed - though we're not going to touch it in this series.

> 
> > @@ -184,14 +190,17 @@ static struct label *construct_label(char
> > *component, u8 varos, u8 *name,
> >                                      u16 namelen)
> >  {
> >         struct label *label;
> > -       size_t slen;
> > +       size_t slen = 0;
> >  
> >         if (!name || namelen > PLPKS_MAX_NAME_SIZE)
> >                 return ERR_PTR(-EINVAL);
> >  
> > -       slen = strlen(component);
> > -       if (component && slen > sizeof(label->attr.prefix))
> > -               return ERR_PTR(-EINVAL);
> > +       // Support NULL component for signed updates
> > +       if (component) {
> > +               slen = strlen(component);
> > +               if (slen > sizeof(label->attr.prefix))
> > +                       return ERR_PTR(-EINVAL);
> > +       }
> 
> Is this already a bug? Code checks for component != NULL but
> previously
> calls strlen which would oops on NULL component AFAIKS. Granted
> nothing
> is actually using any of this these days.

True, it should have been checking for NULL first, but as you say no-
one is using it.

> 
> It already seems like it's supposed to be allowed to rad NULL
> component
> with read_var though? Why the differences, why not always allow NULL
> component? (I assume there is some reason, I just don't know anything
> about secvar or secure boot).

I think the comment confuses more than it clarifies, I'll remove it.

As you say, read_var() should work fine with component == NULL, though
write_var() checks it. The only rule I can find in the spec is that
signed update calls *must* set the component to NULL. I'm seeking
clarification on that.

> > +EXPORT_SYMBOL(plpks_signed_update_var);
> 
> Sorry I missed it before -- can this be a _GPL export?

Indeed it should be - actually, I should check if I can get rid of the
export completely...

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
  2023-01-25  2:47         ` Mimi Zohar
@ 2023-01-31  1:03           ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-31  1:03 UTC (permalink / raw)
  To: Mimi Zohar, Russell Currey, linuxppc-dev, linux-integrity
  Cc: gregkh, gcwilson, linux-kernel, nayna, mpe, gjoyce, sudhakar,
	bgray, erichte, joel

On Tue, 2023-01-24 at 21:47 -0500, Mimi Zohar wrote:
> Agreed.  Thank you for the explanation.  To simplify review, I
> suggest
> either adding this explanation in the patch description or stage the
> change by replacing the existing "ibm,edk2-compat-v1" usage first.

Will clarify in the commit message of the next revision.

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar
@ 2023-01-31  1:03           ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-31  1:03 UTC (permalink / raw)
  To: Mimi Zohar, Russell Currey, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, gjoyce,
	joel, gcwilson

On Tue, 2023-01-24 at 21:47 -0500, Mimi Zohar wrote:
> Agreed.  Thank you for the explanation.  To simplify review, I
> suggest
> either adding this explanation in the patch description or stage the
> change by replacing the existing "ibm,edk2-compat-v1" usage first.

Will clarify in the commit message of the next revision.

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
  2023-01-24  4:36     ` Nicholas Piggin
@ 2023-01-31  2:43       ` Russell Currey
  -1 siblings, 0 replies; 104+ messages in thread
From: Russell Currey @ 2023-01-31  2:43 UTC (permalink / raw)
  To: Nicholas Piggin, Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, gcwilson, joel

On Tue, 2023-01-24 at 14:36 +1000, Nicholas Piggin wrote:
> On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> > From: Russell Currey <ruscur@russell.cc>
> > 
> > Before interacting with the PLPKS, we ask the hypervisor to
> > generate a
> > password for the current boot, which is then required for most
> > further
> > PLPKS operations.
> > 
> > If we kexec into a new kernel, the new kernel will try and fail to
> > generate a new password, as the password has already been set.
> > 
> > Pass the password through to the new kernel via the device tree, in
> > /chosen/plpks-pw. Check for the presence of this property before
> > trying
> 
> In /chosen/ibm,plpks-pw

Good catch, thanks

> 
> > to generate a new password - if it exists, use the existing
> > password and
> > remove it from the device tree.
> > 
> > Signed-off-by: Russell Currey <ruscur@russell.cc>
> > Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> > 
> > ---
> > 
> > v3: New patch
> > 
> > v4: Fix compile when CONFIG_PSERIES_PLPKS=n (snowpatch)
> > 
> >     Fix error handling on fdt_path_offset() call (ruscur)
> > ---
> >  arch/powerpc/kexec/file_load_64.c      | 18 ++++++++++++++++++
> >  arch/powerpc/platforms/pseries/plpks.c | 18 +++++++++++++++++-
> >  2 files changed, 35 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/powerpc/kexec/file_load_64.c
> > b/arch/powerpc/kexec/file_load_64.c
> > index af8854f9eae3..0c9130af60cc 100644
> > --- a/arch/powerpc/kexec/file_load_64.c
> > +++ b/arch/powerpc/kexec/file_load_64.c
> > @@ -27,6 +27,7 @@
> >  #include <asm/kexec_ranges.h>
> >  #include <asm/crashdump-ppc64.h>
> >  #include <asm/prom.h>
> > +#include <asm/plpks.h>
> >  
> >  struct umem_info {
> >         u64 *buf;               /* data buffer for usable-memory
> > property */
> > @@ -1156,6 +1157,9 @@ int setup_new_fdt_ppc64(const struct kimage
> > *image, void *fdt,
> >  {
> >         struct crash_mem *umem = NULL, *rmem = NULL;
> >         int i, nr_ranges, ret;
> > +#ifdef CONFIG_PSERIES_PLPKS
> > +       int chosen_offset;
> > +#endif
> 
> Could put this in plpks_is_available and avoid an ifdef.

Yep, moving this out, though not into plpks_is_available().

> 
> >  
> >         /*
> >          * Restrict memory usage for kdump kernel by setting up
> > @@ -1230,6 +1234,20 @@ int setup_new_fdt_ppc64(const struct kimage
> > *image, void *fdt,
> >                 }
> >         }
> >  
> > +#ifdef CONFIG_PSERIES_PLPKS
> > +       // If we have PLPKS active, we need to provide the password
> > +       if (plpks_is_available()) {
> > +               chosen_offset = fdt_path_offset(fdt, "/chosen");
> > +               if (chosen_offset < 0) {
> > +                       pr_err("Can't find chosen node: %s\n",
> > +                              fdt_strerror(chosen_offset));
> > +                       goto out;
> > +               }
> > +               ret = fdt_setprop(fdt, chosen_offset, "ibm,plpks-
> > pw",
> > +                                 plpks_get_password(),
> > plpks_get_passwordlen());
> > +       }
> > +#endif // CONFIG_PSERIES_PLPKS
> 
> I think if you define plpks_get_password and plpks_get_passwordlen as
> BUILD_BUG_ON when PLPKS is not configured and plpks_is_available as
> false, you could remove the ifdef entirely.

I'm moving this into a helper in plpks.c since now there's FDT handling
in early boot in there.  We can drop plpks_get_password() entirely.

> 
> > +
> >  out:
> >         kfree(rmem);
> >         kfree(umem);
> > diff --git a/arch/powerpc/platforms/pseries/plpks.c
> > b/arch/powerpc/platforms/pseries/plpks.c
> > index b3c7410a4f13..0350f10e1755 100644
> > --- a/arch/powerpc/platforms/pseries/plpks.c
> > +++ b/arch/powerpc/platforms/pseries/plpks.c
> > @@ -16,6 +16,7 @@
> >  #include <linux/slab.h>
> >  #include <linux/string.h>
> >  #include <linux/types.h>
> > +#include <linux/of.h>
> >  #include <asm/hvcall.h>
> >  #include <asm/machdep.h>
> >  #include <asm/plpks.h>
> > @@ -126,7 +127,22 @@ static int plpks_gen_password(void)
> >  {
> >         unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
> >         u8 *password, consumer = PLPKS_OS_OWNER;
> > -       int rc;
> > +       struct property *prop;
> > +       int rc, len;
> > +
> > +       // Before we generate the password, we may have been booted
> > by kexec and
> > +       // provided with a previous password.  Check for that
> > first.
> 
> So not really generating the password then. Should it be in a
> different
> function the caller makes first?

Yes this should have been separate, and now has to be anyway since
we're retrieving the password from the FDT in early boot.

> 
> > +       prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
> > +       if (prop) {
> > +               ospasswordlength = (u16)len;
> > +               ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
> > +               if (!ospassword) {
> > +                       of_remove_property(of_chosen, prop);
> > +                       return -ENOMEM;
> > +               }
> > +               memcpy(ospassword, prop->value, len);
> > +               return of_remove_property(of_chosen, prop);
> 
> Why do you remove the property afterward?

As Andrew mentioned, so we don't have a password lingering in the
device tree, though it's not especially useful.  We're going to get it
and clear it from the FDT in early boot instead.

> 
> Thanks,
> Nick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec
@ 2023-01-31  2:43       ` Russell Currey
  0 siblings, 0 replies; 104+ messages in thread
From: Russell Currey @ 2023-01-31  2:43 UTC (permalink / raw)
  To: Nicholas Piggin, Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	joel, bgray, gcwilson

On Tue, 2023-01-24 at 14:36 +1000, Nicholas Piggin wrote:
> On Fri Jan 20, 2023 at 5:43 PM AEST, Andrew Donnellan wrote:
> > From: Russell Currey <ruscur@russell.cc>
> > 
> > Before interacting with the PLPKS, we ask the hypervisor to
> > generate a
> > password for the current boot, which is then required for most
> > further
> > PLPKS operations.
> > 
> > If we kexec into a new kernel, the new kernel will try and fail to
> > generate a new password, as the password has already been set.
> > 
> > Pass the password through to the new kernel via the device tree, in
> > /chosen/plpks-pw. Check for the presence of this property before
> > trying
> 
> In /chosen/ibm,plpks-pw

Good catch, thanks

> 
> > to generate a new password - if it exists, use the existing
> > password and
> > remove it from the device tree.
> > 
> > Signed-off-by: Russell Currey <ruscur@russell.cc>
> > Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com>
> > 
> > ---
> > 
> > v3: New patch
> > 
> > v4: Fix compile when CONFIG_PSERIES_PLPKS=n (snowpatch)
> > 
> >     Fix error handling on fdt_path_offset() call (ruscur)
> > ---
> >  arch/powerpc/kexec/file_load_64.c      | 18 ++++++++++++++++++
> >  arch/powerpc/platforms/pseries/plpks.c | 18 +++++++++++++++++-
> >  2 files changed, 35 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/powerpc/kexec/file_load_64.c
> > b/arch/powerpc/kexec/file_load_64.c
> > index af8854f9eae3..0c9130af60cc 100644
> > --- a/arch/powerpc/kexec/file_load_64.c
> > +++ b/arch/powerpc/kexec/file_load_64.c
> > @@ -27,6 +27,7 @@
> >  #include <asm/kexec_ranges.h>
> >  #include <asm/crashdump-ppc64.h>
> >  #include <asm/prom.h>
> > +#include <asm/plpks.h>
> >  
> >  struct umem_info {
> >         u64 *buf;               /* data buffer for usable-memory
> > property */
> > @@ -1156,6 +1157,9 @@ int setup_new_fdt_ppc64(const struct kimage
> > *image, void *fdt,
> >  {
> >         struct crash_mem *umem = NULL, *rmem = NULL;
> >         int i, nr_ranges, ret;
> > +#ifdef CONFIG_PSERIES_PLPKS
> > +       int chosen_offset;
> > +#endif
> 
> Could put this in plpks_is_available and avoid an ifdef.

Yep, moving this out, though not into plpks_is_available().

> 
> >  
> >         /*
> >          * Restrict memory usage for kdump kernel by setting up
> > @@ -1230,6 +1234,20 @@ int setup_new_fdt_ppc64(const struct kimage
> > *image, void *fdt,
> >                 }
> >         }
> >  
> > +#ifdef CONFIG_PSERIES_PLPKS
> > +       // If we have PLPKS active, we need to provide the password
> > +       if (plpks_is_available()) {
> > +               chosen_offset = fdt_path_offset(fdt, "/chosen");
> > +               if (chosen_offset < 0) {
> > +                       pr_err("Can't find chosen node: %s\n",
> > +                              fdt_strerror(chosen_offset));
> > +                       goto out;
> > +               }
> > +               ret = fdt_setprop(fdt, chosen_offset, "ibm,plpks-
> > pw",
> > +                                 plpks_get_password(),
> > plpks_get_passwordlen());
> > +       }
> > +#endif // CONFIG_PSERIES_PLPKS
> 
> I think if you define plpks_get_password and plpks_get_passwordlen as
> BUILD_BUG_ON when PLPKS is not configured and plpks_is_available as
> false, you could remove the ifdef entirely.

I'm moving this into a helper in plpks.c since now there's FDT handling
in early boot in there.  We can drop plpks_get_password() entirely.

> 
> > +
> >  out:
> >         kfree(rmem);
> >         kfree(umem);
> > diff --git a/arch/powerpc/platforms/pseries/plpks.c
> > b/arch/powerpc/platforms/pseries/plpks.c
> > index b3c7410a4f13..0350f10e1755 100644
> > --- a/arch/powerpc/platforms/pseries/plpks.c
> > +++ b/arch/powerpc/platforms/pseries/plpks.c
> > @@ -16,6 +16,7 @@
> >  #include <linux/slab.h>
> >  #include <linux/string.h>
> >  #include <linux/types.h>
> > +#include <linux/of.h>
> >  #include <asm/hvcall.h>
> >  #include <asm/machdep.h>
> >  #include <asm/plpks.h>
> > @@ -126,7 +127,22 @@ static int plpks_gen_password(void)
> >  {
> >         unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 };
> >         u8 *password, consumer = PLPKS_OS_OWNER;
> > -       int rc;
> > +       struct property *prop;
> > +       int rc, len;
> > +
> > +       // Before we generate the password, we may have been booted
> > by kexec and
> > +       // provided with a previous password.  Check for that
> > first.
> 
> So not really generating the password then. Should it be in a
> different
> function the caller makes first?

Yes this should have been separate, and now has to be anyway since
we're retrieving the password from the FDT in early boot.

> 
> > +       prop = of_find_property(of_chosen, "ibm,plpks-pw", &len);
> > +       if (prop) {
> > +               ospasswordlength = (u16)len;
> > +               ospassword = kzalloc(ospasswordlength, GFP_KERNEL);
> > +               if (!ospassword) {
> > +                       of_remove_property(of_chosen, prop);
> > +                       return -ENOMEM;
> > +               }
> > +               memcpy(ospassword, prop->value, len);
> > +               return of_remove_property(of_chosen, prop);
> 
> Why do you remove the property afterward?

As Andrew mentioned, so we don't have a password lingering in the
device tree, though it's not especially useful.  We're going to get it
and clear it from the FDT in early boot instead.

> 
> Thanks,
> Nick


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
  2023-01-24  5:17     ` Nicholas Piggin
@ 2023-01-31  2:54       ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-31  2:54 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Tue, 2023-01-24 at 15:17 +1000, Nicholas Piggin wrote:
> > +static const char * const plpks_var_names[] = {
> > +       "PK",
> > +       "KEK",
> > +       "db",
> > +       "dbx",
> > +       "grubdb",
> > +       "grubdbx",
> > +       "sbat",
> > +       "moduledb",
> > +       "trustedcadb",
> > +       NULL,
> > +};
> 
> Var and key are used somewhat interchangeably? These are keys, I
> think?
> And plpks could have other vars but we're only interested in (at
> least a
> subset of) keys here if I understood right.
> 
> I guess the terminology is like that throughout secvar so maybe
> nothing
> to be done.

The "key" terminology seems to come from OPAL, while on the PLPKS side
it's a bit of a mess but "var" follows the usage in existing code (the
spec refers more to "objects").

> 
> > +
> > +static int plpks_get_variable(const char *key, u64 key_len, u8
> > *data,
> > +                             u64 *data_size)
> > +{
> > +       struct plpks_var var = {0};
> > +       int rc = 0;
> > +
> > +       var.name = kcalloc(key_len - 1, sizeof(wchar_t),
> > GFP_KERNEL);
> > +       if (!var.name)
> > +               return -ENOMEM;
> > +       rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN,
> > (wchar_t *)var.name,
> > +                            key_len - 1);
> > +       if (rc < 0)
> > +               goto err;
> 
> Okay I can't work out why it's key_len - 1 rather than key_len.

The existing code in secvar-sysfs.c calls secvar_ops->get() with
key_len = strlen(name) + 1, to include the null byte, which is what
OPAL expects. For PLPKS, the variable name explicitly does not include
a trailing null byte.

I'll add a comment indicating as such, perhaps at some later point it
can be reworked.

> 
> > +       var.namelen = rc * 2;
> > +
> > +       var.os = PLPKS_VAR_LINUX;
> > +       if (data) {
> > +               var.data = data;
> > +               var.datalen = *data_size;
> > +       }
> > +       rc = plpks_read_os_var(&var);
> > +
> > +       if (rc)
> > +               goto err;
> > +
> > +       *data_size = var.datalen;
> > +
> > +err:
> > +       kfree(var.name);
> > +       if (rc && rc != -ENOENT) {
> > +               pr_err("Failed to read variable '%s': %d\n", key,
> > rc);
> > +               // Return -EIO since userspace probably doesn't
> > care about the
> > +               // specific error
> > +               rc = -EIO;
> > +       }
> > +       return rc;
> > +}
> > +
> > +static int plpks_set_variable(const char *key, u64 key_len, u8
> > *data,
> > +                             u64 data_size)
> > +{
> > +       struct plpks_var var = {0};
> > +       int rc = 0;
> > +       u64 flags;
> > +
> > +       // Secure variables need to be prefixed with 8 bytes of
> > flags.
> > +       // We only want to perform the write if we have at least
> > one byte of data.
> > +       if (data_size <= sizeof(flags))
> 
> So it's unstructured 8 byte of flags, not a u64 integer? Why not u8
> flags[8] then?

No, it's a u64 and it's passed in the hcall as a single u64.

> 
> > +               return -EINVAL;
> > +
> > +       var.name = kcalloc(key_len - 1, sizeof(wchar_t),
> > GFP_KERNEL);
> > +       if (!var.name)
> > +               return -ENOMEM;
> > +       rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN,
> > (wchar_t *)var.name,
> > +                            key_len - 1);
> > +       if (rc < 0)
> > +               goto err;
> > +       var.namelen = rc * 2;
> > +
> > +       memcpy(&flags, data, sizeof(flags));
> > +
> > +       var.datalen = data_size - sizeof(flags);
> > +       var.data = data + sizeof(flags);
> > +       var.os = PLPKS_VAR_LINUX;
> > +       var.policy = get_policy(key);
> > +
> > +       // Unlike in the read case, the plpks error code can be
> > useful to
> > +       // userspace on write, so we return it rather than just -
> > EIO
> > +       rc = plpks_signed_update_var(&var, flags);
> > +
> > +err:
> > +       kfree(var.name);
> > +       return rc;
> > +}
> > +
> > +// PLPKS dynamic secure boot doesn't give us a format string in
> > the same way OPAL does.
> > +// Instead, report the format using the SB_VERSION variable in the
> > keystore.
> > +static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
> > +{
> > +       struct plpks_var var = {0};
> > +       ssize_t ret;
> > +
> > +       var.component = NULL;
> > +       // Only the signed variables have null bytes in their
> > names, this one doesn't
> > +       var.name = "SB_VERSION";
> > +       var.namelen = 10;
> 
> Could you make that strlen(var.name) for the benefit of those of us
> with
> missing fingers?

Will do.

> 
> > +       var.datalen = 1;
> > +       var.data = kzalloc(1, GFP_KERNEL);
> 
> This could just point to a u8 on stack I think?

Until we get VMAP_STACK and we'll have to switch back.

> 
> 
> > +       if (!var.data)
> > +               return -ENOMEM;
> > +
> > +       // Unlike the other vars, SB_VERSION is owned by firmware
> > instead of the OS
> > +       ret = plpks_read_fw_var(&var);
> > +       if (ret) {
> > +               if (ret == -ENOENT) {
> > +                       ret = snprintf(buf, bufsize, "ibm,plpks-sb-
> > unknown");
> > +               } else {
> > +                       pr_err("Error %ld reading SB_VERSION from
> > firmware\n", ret);
> > +                       ret = -EIO;
> > +               }
> 
> Is there a meaningful distinction? Does anything good come of
> advertising an unknown format like this?

Our thinking was simply to distinguish between cases where the API is
otherwise working happily but for some reason simply not advertising a
version number (you might still want to try to interact with the key
store regardless) vs the case where the hypervisor is returning a real
error.

I plan to keep this as is for the next revision, but I'm happy to
change it if there's a strong objection, it could go either way.

> 
> > +               goto err;
> > +       }
> > +
> > +       // This string is made up by us - the hypervisor doesn't
> > provide us
> > +       // with a format string in the way that OPAL firmware does.
> > Hypervisor
> > +       // defines SB_VERSION as a "1 byte unsigned integer value".
> 
> I'd put the comment about SB_VERSION at the top where you use/define
> it
> or mention it in the comment.

Will fix.

> 
> > +       ret = snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu",
> > var.data[0]);
> > +
> > +err:
> > +       kfree(var.data);
> > +       return ret;
> > +}
> > +
> > +static int plpks_max_size(u64 *max_size)
> > +{
> > +       // The max object size reported by the hypervisor is
> > accurate for the
> > +       // object itself, but we use the first 8 bytes of data on
> > write as the
> > +       // signed update flags, so the max size a user can write is
> > larger.
> > +       *max_size = (u64)plpks_get_maxobjectsize() + 8;
> 
> You have this 8 open coded twice (once as sizeof(u64)). You could
> make
> it a #define at the top with a brief overview of the hcall format so
> you
> don't need so much commentage for it. Although a note here that the
> objsize does not include the flags bytes is good to keep.

Will do.

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
@ 2023-01-31  2:54       ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-31  2:54 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Tue, 2023-01-24 at 15:17 +1000, Nicholas Piggin wrote:
> > +static const char * const plpks_var_names[] = {
> > +       "PK",
> > +       "KEK",
> > +       "db",
> > +       "dbx",
> > +       "grubdb",
> > +       "grubdbx",
> > +       "sbat",
> > +       "moduledb",
> > +       "trustedcadb",
> > +       NULL,
> > +};
> 
> Var and key are used somewhat interchangeably? These are keys, I
> think?
> And plpks could have other vars but we're only interested in (at
> least a
> subset of) keys here if I understood right.
> 
> I guess the terminology is like that throughout secvar so maybe
> nothing
> to be done.

The "key" terminology seems to come from OPAL, while on the PLPKS side
it's a bit of a mess but "var" follows the usage in existing code (the
spec refers more to "objects").

> 
> > +
> > +static int plpks_get_variable(const char *key, u64 key_len, u8
> > *data,
> > +                             u64 *data_size)
> > +{
> > +       struct plpks_var var = {0};
> > +       int rc = 0;
> > +
> > +       var.name = kcalloc(key_len - 1, sizeof(wchar_t),
> > GFP_KERNEL);
> > +       if (!var.name)
> > +               return -ENOMEM;
> > +       rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN,
> > (wchar_t *)var.name,
> > +                            key_len - 1);
> > +       if (rc < 0)
> > +               goto err;
> 
> Okay I can't work out why it's key_len - 1 rather than key_len.

The existing code in secvar-sysfs.c calls secvar_ops->get() with
key_len = strlen(name) + 1, to include the null byte, which is what
OPAL expects. For PLPKS, the variable name explicitly does not include
a trailing null byte.

I'll add a comment indicating as such, perhaps at some later point it
can be reworked.

> 
> > +       var.namelen = rc * 2;
> > +
> > +       var.os = PLPKS_VAR_LINUX;
> > +       if (data) {
> > +               var.data = data;
> > +               var.datalen = *data_size;
> > +       }
> > +       rc = plpks_read_os_var(&var);
> > +
> > +       if (rc)
> > +               goto err;
> > +
> > +       *data_size = var.datalen;
> > +
> > +err:
> > +       kfree(var.name);
> > +       if (rc && rc != -ENOENT) {
> > +               pr_err("Failed to read variable '%s': %d\n", key,
> > rc);
> > +               // Return -EIO since userspace probably doesn't
> > care about the
> > +               // specific error
> > +               rc = -EIO;
> > +       }
> > +       return rc;
> > +}
> > +
> > +static int plpks_set_variable(const char *key, u64 key_len, u8
> > *data,
> > +                             u64 data_size)
> > +{
> > +       struct plpks_var var = {0};
> > +       int rc = 0;
> > +       u64 flags;
> > +
> > +       // Secure variables need to be prefixed with 8 bytes of
> > flags.
> > +       // We only want to perform the write if we have at least
> > one byte of data.
> > +       if (data_size <= sizeof(flags))
> 
> So it's unstructured 8 byte of flags, not a u64 integer? Why not u8
> flags[8] then?

No, it's a u64 and it's passed in the hcall as a single u64.

> 
> > +               return -EINVAL;
> > +
> > +       var.name = kcalloc(key_len - 1, sizeof(wchar_t),
> > GFP_KERNEL);
> > +       if (!var.name)
> > +               return -ENOMEM;
> > +       rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN,
> > (wchar_t *)var.name,
> > +                            key_len - 1);
> > +       if (rc < 0)
> > +               goto err;
> > +       var.namelen = rc * 2;
> > +
> > +       memcpy(&flags, data, sizeof(flags));
> > +
> > +       var.datalen = data_size - sizeof(flags);
> > +       var.data = data + sizeof(flags);
> > +       var.os = PLPKS_VAR_LINUX;
> > +       var.policy = get_policy(key);
> > +
> > +       // Unlike in the read case, the plpks error code can be
> > useful to
> > +       // userspace on write, so we return it rather than just -
> > EIO
> > +       rc = plpks_signed_update_var(&var, flags);
> > +
> > +err:
> > +       kfree(var.name);
> > +       return rc;
> > +}
> > +
> > +// PLPKS dynamic secure boot doesn't give us a format string in
> > the same way OPAL does.
> > +// Instead, report the format using the SB_VERSION variable in the
> > keystore.
> > +static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
> > +{
> > +       struct plpks_var var = {0};
> > +       ssize_t ret;
> > +
> > +       var.component = NULL;
> > +       // Only the signed variables have null bytes in their
> > names, this one doesn't
> > +       var.name = "SB_VERSION";
> > +       var.namelen = 10;
> 
> Could you make that strlen(var.name) for the benefit of those of us
> with
> missing fingers?

Will do.

> 
> > +       var.datalen = 1;
> > +       var.data = kzalloc(1, GFP_KERNEL);
> 
> This could just point to a u8 on stack I think?

Until we get VMAP_STACK and we'll have to switch back.

> 
> 
> > +       if (!var.data)
> > +               return -ENOMEM;
> > +
> > +       // Unlike the other vars, SB_VERSION is owned by firmware
> > instead of the OS
> > +       ret = plpks_read_fw_var(&var);
> > +       if (ret) {
> > +               if (ret == -ENOENT) {
> > +                       ret = snprintf(buf, bufsize, "ibm,plpks-sb-
> > unknown");
> > +               } else {
> > +                       pr_err("Error %ld reading SB_VERSION from
> > firmware\n", ret);
> > +                       ret = -EIO;
> > +               }
> 
> Is there a meaningful distinction? Does anything good come of
> advertising an unknown format like this?

Our thinking was simply to distinguish between cases where the API is
otherwise working happily but for some reason simply not advertising a
version number (you might still want to try to interact with the key
store regardless) vs the case where the hypervisor is returning a real
error.

I plan to keep this as is for the next revision, but I'm happy to
change it if there's a strong objection, it could go either way.

> 
> > +               goto err;
> > +       }
> > +
> > +       // This string is made up by us - the hypervisor doesn't
> > provide us
> > +       // with a format string in the way that OPAL firmware does.
> > Hypervisor
> > +       // defines SB_VERSION as a "1 byte unsigned integer value".
> 
> I'd put the comment about SB_VERSION at the top where you use/define
> it
> or mention it in the comment.

Will fix.

> 
> > +       ret = snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu",
> > var.data[0]);
> > +
> > +err:
> > +       kfree(var.data);
> > +       return ret;
> > +}
> > +
> > +static int plpks_max_size(u64 *max_size)
> > +{
> > +       // The max object size reported by the hypervisor is
> > accurate for the
> > +       // object itself, but we use the first 8 bytes of data on
> > write as the
> > +       // signed update flags, so the max size a user can write is
> > larger.
> > +       *max_size = (u64)plpks_get_maxobjectsize() + 8;
> 
> You have this 8 open coded twice (once as sizeof(u64)). You could
> make
> it a #define at the top with a brief overview of the hcall format so
> you
> don't need so much commentage for it. Although a note here that the
> objsize does not include the flags bytes is good to keep.

Will do.

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 16/24] powerpc/pseries: Implement signed update for PLPKS objects
  2023-01-30  4:43       ` Andrew Donnellan
@ 2023-01-31  4:23         ` Russell Currey
  -1 siblings, 0 replies; 104+ messages in thread
From: Russell Currey @ 2023-01-31  4:23 UTC (permalink / raw)
  To: Andrew Donnellan, Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, gcwilson, joel

On Mon, 2023-01-30 at 15:43 +1100, Andrew Donnellan wrote:
> On Tue, 2023-01-24 at 14:16 +1000, Nicholas Piggin wrote:
> > > diff --git a/arch/powerpc/platforms/pseries/plpks.c
> > > b/arch/powerpc/platforms/pseries/plpks.c
> > > index 1189246b03dc..796ed5544ee5 100644
> > > --- a/arch/powerpc/platforms/pseries/plpks.c
> > > +++ b/arch/powerpc/platforms/pseries/plpks.c
> > > @@ -81,6 +81,12 @@ static int pseries_status_to_err(int rc)
> > >                 err = -ENOENT;
> > >                 break;
> > >         case H_BUSY:
> > > +       case H_LONG_BUSY_ORDER_1_MSEC:
> > > +       case H_LONG_BUSY_ORDER_10_MSEC:
> > > +       case H_LONG_BUSY_ORDER_100_MSEC:
> > > +       case H_LONG_BUSY_ORDER_1_SEC:
> > > +       case H_LONG_BUSY_ORDER_10_SEC:
> > > +       case H_LONG_BUSY_ORDER_100_SEC:
> > >                 err = -EBUSY;
> > >                 break;
> > >         case H_AUTHORITY:
> > 
> > This is a bit sad to maintain here. It's duplicating bits with
> > hvcs_convert, and a bunch of open coded places. Probably not the
> > series to do anything about. Would be nice if we could standardise
> > it though.
> 
> Agreed - though we're not going to touch it in this series.
> 
> > 
> > > @@ -184,14 +190,17 @@ static struct label *construct_label(char
> > > *component, u8 varos, u8 *name,
> > >                                      u16 namelen)
> > >  {
> > >         struct label *label;
> > > -       size_t slen;
> > > +       size_t slen = 0;
> > >  
> > >         if (!name || namelen > PLPKS_MAX_NAME_SIZE)
> > >                 return ERR_PTR(-EINVAL);
> > >  
> > > -       slen = strlen(component);
> > > -       if (component && slen > sizeof(label->attr.prefix))
> > > -               return ERR_PTR(-EINVAL);
> > > +       // Support NULL component for signed updates
> > > +       if (component) {
> > > +               slen = strlen(component);
> > > +               if (slen > sizeof(label->attr.prefix))
> > > +                       return ERR_PTR(-EINVAL);
> > > +       }
> > 
> > Is this already a bug? Code checks for component != NULL but
> > previously
> > calls strlen which would oops on NULL component AFAIKS. Granted
> > nothing
> > is actually using any of this these days.
> 
> True, it should have been checking for NULL first, but as you say no-
> one is using it.
> 
> > 
> > It already seems like it's supposed to be allowed to rad NULL
> > component
> > with read_var though? Why the differences, why not always allow
> > NULL
> > component? (I assume there is some reason, I just don't know
> > anything
> > about secvar or secure boot).
> 
> I think the comment confuses more than it clarifies, I'll remove it.
> 
> As you say, read_var() should work fine with component == NULL,
> though
> write_var() checks it. The only rule I can find in the spec is that
> signed update calls *must* set the component to NULL. I'm seeking
> clarification on that.

Signed update calls *must* set the component to NULL.

We could just call construct_label() with NULL as the component
directly but I think it's better to explicitly check var->component and
return so the caller knows what they're trying to do is wrong.

> 
> > > +EXPORT_SYMBOL(plpks_signed_update_var);
> > 
> > Sorry I missed it before -- can this be a _GPL export?
> 
> Indeed it should be - actually, I should check if I can get rid of
> the
> export completely...
> 


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 16/24] powerpc/pseries: Implement signed update for PLPKS objects
@ 2023-01-31  4:23         ` Russell Currey
  0 siblings, 0 replies; 104+ messages in thread
From: Russell Currey @ 2023-01-31  4:23 UTC (permalink / raw)
  To: Andrew Donnellan, Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	joel, bgray, gcwilson

On Mon, 2023-01-30 at 15:43 +1100, Andrew Donnellan wrote:
> On Tue, 2023-01-24 at 14:16 +1000, Nicholas Piggin wrote:
> > > diff --git a/arch/powerpc/platforms/pseries/plpks.c
> > > b/arch/powerpc/platforms/pseries/plpks.c
> > > index 1189246b03dc..796ed5544ee5 100644
> > > --- a/arch/powerpc/platforms/pseries/plpks.c
> > > +++ b/arch/powerpc/platforms/pseries/plpks.c
> > > @@ -81,6 +81,12 @@ static int pseries_status_to_err(int rc)
> > >                 err = -ENOENT;
> > >                 break;
> > >         case H_BUSY:
> > > +       case H_LONG_BUSY_ORDER_1_MSEC:
> > > +       case H_LONG_BUSY_ORDER_10_MSEC:
> > > +       case H_LONG_BUSY_ORDER_100_MSEC:
> > > +       case H_LONG_BUSY_ORDER_1_SEC:
> > > +       case H_LONG_BUSY_ORDER_10_SEC:
> > > +       case H_LONG_BUSY_ORDER_100_SEC:
> > >                 err = -EBUSY;
> > >                 break;
> > >         case H_AUTHORITY:
> > 
> > This is a bit sad to maintain here. It's duplicating bits with
> > hvcs_convert, and a bunch of open coded places. Probably not the
> > series to do anything about. Would be nice if we could standardise
> > it though.
> 
> Agreed - though we're not going to touch it in this series.
> 
> > 
> > > @@ -184,14 +190,17 @@ static struct label *construct_label(char
> > > *component, u8 varos, u8 *name,
> > >                                      u16 namelen)
> > >  {
> > >         struct label *label;
> > > -       size_t slen;
> > > +       size_t slen = 0;
> > >  
> > >         if (!name || namelen > PLPKS_MAX_NAME_SIZE)
> > >                 return ERR_PTR(-EINVAL);
> > >  
> > > -       slen = strlen(component);
> > > -       if (component && slen > sizeof(label->attr.prefix))
> > > -               return ERR_PTR(-EINVAL);
> > > +       // Support NULL component for signed updates
> > > +       if (component) {
> > > +               slen = strlen(component);
> > > +               if (slen > sizeof(label->attr.prefix))
> > > +                       return ERR_PTR(-EINVAL);
> > > +       }
> > 
> > Is this already a bug? Code checks for component != NULL but
> > previously
> > calls strlen which would oops on NULL component AFAIKS. Granted
> > nothing
> > is actually using any of this these days.
> 
> True, it should have been checking for NULL first, but as you say no-
> one is using it.
> 
> > 
> > It already seems like it's supposed to be allowed to rad NULL
> > component
> > with read_var though? Why the differences, why not always allow
> > NULL
> > component? (I assume there is some reason, I just don't know
> > anything
> > about secvar or secure boot).
> 
> I think the comment confuses more than it clarifies, I'll remove it.
> 
> As you say, read_var() should work fine with component == NULL,
> though
> write_var() checks it. The only rule I can find in the spec is that
> signed update calls *must* set the component to NULL. I'm seeking
> clarification on that.

Signed update calls *must* set the component to NULL.

We could just call construct_label() with NULL as the component
directly but I think it's better to explicitly check var->component and
return so the caller knows what they're trying to do is wrong.

> 
> > > +EXPORT_SYMBOL(plpks_signed_update_var);
> > 
> > Sorry I missed it before -- can this be a _GPL export?
> 
> Indeed it should be - actually, I should check if I can get rid of
> the
> export completely...
> 


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
  2023-01-31  2:54       ` Andrew Donnellan
@ 2023-01-31  4:25         ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-31  4:25 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Tue, 2023-01-31 at 13:54 +1100, Andrew Donnellan wrote:
> > > +{
> > > +       // The max object size reported by the hypervisor is
> > > accurate for the
> > > +       // object itself, but we use the first 8 bytes of data on
> > > write as the
> > > +       // signed update flags, so the max size a user can write
> > > is
> > > larger.
> > > +       *max_size = (u64)plpks_get_maxobjectsize() + 8;
> > 
> > You have this 8 open coded twice (once as sizeof(u64)). You could
> > make
> > it a #define at the top with a brief overview of the hcall format
> > so
> > you
> > don't need so much commentage for it. Although a note here that the
> > objsize does not include the flags bytes is good to keep.
> 
> Will do.

Thinking about this further, I'm going to change the 8 to sizeof(u64)
to make it clearer that it's linked with the type of the flags
variable, but I am going to keep the other cases as is (they're
sizeof(flags), not sizeof(u64), so it's already obvious how they work,
and I don't want to define a macro for one user).


-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
@ 2023-01-31  4:25         ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-01-31  4:25 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Tue, 2023-01-31 at 13:54 +1100, Andrew Donnellan wrote:
> > > +{
> > > +       // The max object size reported by the hypervisor is
> > > accurate for the
> > > +       // object itself, but we use the first 8 bytes of data on
> > > write as the
> > > +       // signed update flags, so the max size a user can write
> > > is
> > > larger.
> > > +       *max_size = (u64)plpks_get_maxobjectsize() + 8;
> > 
> > You have this 8 open coded twice (once as sizeof(u64)). You could
> > make
> > it a #define at the top with a brief overview of the hcall format
> > so
> > you
> > don't need so much commentage for it. Although a note here that the
> > objsize does not include the flags bytes is good to keep.
> 
> Will do.

Thinking about this further, I'm going to change the 8 to sizeof(u64)
to make it clearer that it's linked with the type of the flags
variable, but I am going to keep the other cases as is (they're
sizeof(flags), not sizeof(u64), so it's already obvious how they work,
and I don't want to define a macro for one user).


-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
  2023-01-31  2:54       ` Andrew Donnellan
@ 2023-01-31  8:55         ` Nicholas Piggin
  -1 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-31  8:55 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Tue Jan 31, 2023 at 12:54 PM AEST, Andrew Donnellan wrote:
> On Tue, 2023-01-24 at 15:17 +1000, Nicholas Piggin wrote:
> > > +static const char * const plpks_var_names[] = {
> > > +       "PK",
> > > +       "KEK",
> > > +       "db",
> > > +       "dbx",
> > > +       "grubdb",
> > > +       "grubdbx",
> > > +       "sbat",
> > > +       "moduledb",
> > > +       "trustedcadb",
> > > +       NULL,
> > > +};
> > 
> > Var and key are used somewhat interchangeably? These are keys, I
> > think?
> > And plpks could have other vars but we're only interested in (at
> > least a
> > subset of) keys here if I understood right.
> > 
> > I guess the terminology is like that throughout secvar so maybe
> > nothing
> > to be done.
>
> The "key" terminology seems to come from OPAL, while on the PLPKS side
> it's a bit of a mess but "var" follows the usage in existing code (the
> spec refers more to "objects").
>
> > 
> > > +
> > > +static int plpks_get_variable(const char *key, u64 key_len, u8
> > > *data,
> > > +                             u64 *data_size)
> > > +{
> > > +       struct plpks_var var = {0};
> > > +       int rc = 0;
> > > +
> > > +       var.name = kcalloc(key_len - 1, sizeof(wchar_t),
> > > GFP_KERNEL);
> > > +       if (!var.name)
> > > +               return -ENOMEM;
> > > +       rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN,
> > > (wchar_t *)var.name,
> > > +                            key_len - 1);
> > > +       if (rc < 0)
> > > +               goto err;
> > 
> > Okay I can't work out why it's key_len - 1 rather than key_len.
>
> The existing code in secvar-sysfs.c calls secvar_ops->get() with
> key_len = strlen(name) + 1, to include the null byte, which is what
> OPAL expects. For PLPKS, the variable name explicitly does not include
> a trailing null byte.
>
> I'll add a comment indicating as such, perhaps at some later point it
> can be reworked.
>
> > 
> > > +       var.namelen = rc * 2;
> > > +
> > > +       var.os = PLPKS_VAR_LINUX;
> > > +       if (data) {
> > > +               var.data = data;
> > > +               var.datalen = *data_size;
> > > +       }
> > > +       rc = plpks_read_os_var(&var);
> > > +
> > > +       if (rc)
> > > +               goto err;
> > > +
> > > +       *data_size = var.datalen;
> > > +
> > > +err:
> > > +       kfree(var.name);
> > > +       if (rc && rc != -ENOENT) {
> > > +               pr_err("Failed to read variable '%s': %d\n", key,
> > > rc);
> > > +               // Return -EIO since userspace probably doesn't
> > > care about the
> > > +               // specific error
> > > +               rc = -EIO;
> > > +       }
> > > +       return rc;
> > > +}
> > > +
> > > +static int plpks_set_variable(const char *key, u64 key_len, u8
> > > *data,
> > > +                             u64 data_size)
> > > +{
> > > +       struct plpks_var var = {0};
> > > +       int rc = 0;
> > > +       u64 flags;
> > > +
> > > +       // Secure variables need to be prefixed with 8 bytes of
> > > flags.
> > > +       // We only want to perform the write if we have at least
> > > one byte of data.
> > > +       if (data_size <= sizeof(flags))
> > 
> > So it's unstructured 8 byte of flags, not a u64 integer? Why not u8
> > flags[8] then?
>
> No, it's a u64 and it's passed in the hcall as a single u64.

In host endian? This is done so userspace can acces it with the existing
secvar API, right? I suppose that's okay...

> > > +static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
> > > +{
> > > +       struct plpks_var var = {0};
> > > +       ssize_t ret;
> > > +
> > > +       var.component = NULL;
> > > +       // Only the signed variables have null bytes in their
> > > names, this one doesn't
> > > +       var.name = "SB_VERSION";
> > > +       var.namelen = 10;
> > 
> > Could you make that strlen(var.name) for the benefit of those of us
> > with
> > missing fingers?
>
> Will do.
>
> > 
> > > +       var.datalen = 1;
> > > +       var.data = kzalloc(1, GFP_KERNEL);
> > 
> > This could just point to a u8 on stack I think?
>
> Until we get VMAP_STACK and we'll have to switch back.

AFAIKS plpks_read_var does not require linear map, so should not be
required. IMO that's the right way to go for an external API, so
actually plpks_write_var is the outlier there and should be changed
to follow read and remove in not requiring special pointers.

Thanks,
Nick

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
@ 2023-01-31  8:55         ` Nicholas Piggin
  0 siblings, 0 replies; 104+ messages in thread
From: Nicholas Piggin @ 2023-01-31  8:55 UTC (permalink / raw)
  To: Andrew Donnellan, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Tue Jan 31, 2023 at 12:54 PM AEST, Andrew Donnellan wrote:
> On Tue, 2023-01-24 at 15:17 +1000, Nicholas Piggin wrote:
> > > +static const char * const plpks_var_names[] = {
> > > +       "PK",
> > > +       "KEK",
> > > +       "db",
> > > +       "dbx",
> > > +       "grubdb",
> > > +       "grubdbx",
> > > +       "sbat",
> > > +       "moduledb",
> > > +       "trustedcadb",
> > > +       NULL,
> > > +};
> > 
> > Var and key are used somewhat interchangeably? These are keys, I
> > think?
> > And plpks could have other vars but we're only interested in (at
> > least a
> > subset of) keys here if I understood right.
> > 
> > I guess the terminology is like that throughout secvar so maybe
> > nothing
> > to be done.
>
> The "key" terminology seems to come from OPAL, while on the PLPKS side
> it's a bit of a mess but "var" follows the usage in existing code (the
> spec refers more to "objects").
>
> > 
> > > +
> > > +static int plpks_get_variable(const char *key, u64 key_len, u8
> > > *data,
> > > +                             u64 *data_size)
> > > +{
> > > +       struct plpks_var var = {0};
> > > +       int rc = 0;
> > > +
> > > +       var.name = kcalloc(key_len - 1, sizeof(wchar_t),
> > > GFP_KERNEL);
> > > +       if (!var.name)
> > > +               return -ENOMEM;
> > > +       rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN,
> > > (wchar_t *)var.name,
> > > +                            key_len - 1);
> > > +       if (rc < 0)
> > > +               goto err;
> > 
> > Okay I can't work out why it's key_len - 1 rather than key_len.
>
> The existing code in secvar-sysfs.c calls secvar_ops->get() with
> key_len = strlen(name) + 1, to include the null byte, which is what
> OPAL expects. For PLPKS, the variable name explicitly does not include
> a trailing null byte.
>
> I'll add a comment indicating as such, perhaps at some later point it
> can be reworked.
>
> > 
> > > +       var.namelen = rc * 2;
> > > +
> > > +       var.os = PLPKS_VAR_LINUX;
> > > +       if (data) {
> > > +               var.data = data;
> > > +               var.datalen = *data_size;
> > > +       }
> > > +       rc = plpks_read_os_var(&var);
> > > +
> > > +       if (rc)
> > > +               goto err;
> > > +
> > > +       *data_size = var.datalen;
> > > +
> > > +err:
> > > +       kfree(var.name);
> > > +       if (rc && rc != -ENOENT) {
> > > +               pr_err("Failed to read variable '%s': %d\n", key,
> > > rc);
> > > +               // Return -EIO since userspace probably doesn't
> > > care about the
> > > +               // specific error
> > > +               rc = -EIO;
> > > +       }
> > > +       return rc;
> > > +}
> > > +
> > > +static int plpks_set_variable(const char *key, u64 key_len, u8
> > > *data,
> > > +                             u64 data_size)
> > > +{
> > > +       struct plpks_var var = {0};
> > > +       int rc = 0;
> > > +       u64 flags;
> > > +
> > > +       // Secure variables need to be prefixed with 8 bytes of
> > > flags.
> > > +       // We only want to perform the write if we have at least
> > > one byte of data.
> > > +       if (data_size <= sizeof(flags))
> > 
> > So it's unstructured 8 byte of flags, not a u64 integer? Why not u8
> > flags[8] then?
>
> No, it's a u64 and it's passed in the hcall as a single u64.

In host endian? This is done so userspace can acces it with the existing
secvar API, right? I suppose that's okay...

> > > +static ssize_t plpks_secvar_format(char *buf, size_t bufsize)
> > > +{
> > > +       struct plpks_var var = {0};
> > > +       ssize_t ret;
> > > +
> > > +       var.component = NULL;
> > > +       // Only the signed variables have null bytes in their
> > > names, this one doesn't
> > > +       var.name = "SB_VERSION";
> > > +       var.namelen = 10;
> > 
> > Could you make that strlen(var.name) for the benefit of those of us
> > with
> > missing fingers?
>
> Will do.
>
> > 
> > > +       var.datalen = 1;
> > > +       var.data = kzalloc(1, GFP_KERNEL);
> > 
> > This could just point to a u8 on stack I think?
>
> Until we get VMAP_STACK and we'll have to switch back.

AFAIKS plpks_read_var does not require linear map, so should not be
required. IMO that's the right way to go for an external API, so
actually plpks_write_var is the outlier there and should be changed
to follow read and remove in not requiring special pointers.

Thanks,
Nick

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
  2023-01-31  8:55         ` Nicholas Piggin
@ 2023-02-01  2:15           ` Andrew Donnellan
  -1 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-02-01  2:15 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: sudhakar, bgray, erichte, gregkh, nayna, linux-kernel, zohar,
	gjoyce, ruscur, gcwilson, joel

On Tue, 2023-01-31 at 18:55 +1000, Nicholas Piggin wrote:
> > > > +       var.datalen = 1;
> > > > +       var.data = kzalloc(1, GFP_KERNEL);
> > > 
> > > This could just point to a u8 on stack I think?
> > 
> > Until we get VMAP_STACK and we'll have to switch back.
> 
> AFAIKS plpks_read_var does not require linear map, so should not be
> required. IMO that's the right way to go for an external API, so
> actually plpks_write_var is the outlier there and should be changed
> to follow read and remove in not requiring special pointers.

Indeed, I was confused - in the read case, the buffer doesn't get
directly passed to the hcall.

I'll wait a little bit longer for more feedback on v5 of this series
and maybe fix this in v6 if mpe thinks I should respin it again.

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot
@ 2023-02-01  2:15           ` Andrew Donnellan
  0 siblings, 0 replies; 104+ messages in thread
From: Andrew Donnellan @ 2023-02-01  2:15 UTC (permalink / raw)
  To: Nicholas Piggin, linuxppc-dev, linux-integrity
  Cc: gjoyce, erichte, gregkh, nayna, linux-kernel, zohar, sudhakar,
	ruscur, joel, bgray, gcwilson

On Tue, 2023-01-31 at 18:55 +1000, Nicholas Piggin wrote:
> > > > +       var.datalen = 1;
> > > > +       var.data = kzalloc(1, GFP_KERNEL);
> > > 
> > > This could just point to a u8 on stack I think?
> > 
> > Until we get VMAP_STACK and we'll have to switch back.
> 
> AFAIKS plpks_read_var does not require linear map, so should not be
> required. IMO that's the right way to go for an external API, so
> actually plpks_write_var is the outlier there and should be changed
> to follow read and remove in not requiring special pointers.

Indeed, I was confused - in the read case, the buffer doesn't get
directly passed to the hcall.

I'll wait a little bit longer for more feedback on v5 of this series
and maybe fix this in v6 if mpe thinks I should respin it again.

-- 
Andrew Donnellan    OzLabs, ADL Canberra
ajd@linux.ibm.com   IBM Australia Limited

^ permalink raw reply	[flat|nested] 104+ messages in thread

end of thread, other threads:[~2023-02-01  2:16 UTC | newest]

Thread overview: 104+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-20  7:42 [PATCH v4 00/24] pSeries dynamic secure boot secvar interface + platform keyring loading Andrew Donnellan
2023-01-20  7:42 ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 01/24] powerpc/pseries: Fix handling of PLPKS object flushing timeout Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 02/24] powerpc/pseries: Fix alignment of PLPKS structures and buffers Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-25 13:09   ` Michael Ellerman
2023-01-25 13:09     ` Michael Ellerman
2023-01-26 17:19     ` Segher Boessenkool
2023-01-26 17:19       ` Segher Boessenkool
2023-01-26 17:31       ` David Laight
2023-01-26 17:31         ` David Laight
2023-01-27  3:20         ` Andrew Donnellan
2023-01-27  3:20           ` Andrew Donnellan
2023-01-27  9:05           ` David Laight
2023-01-27  9:05             ` David Laight
2023-01-27 11:08           ` Michael Ellerman
2023-01-27 11:08             ` Michael Ellerman
2023-01-27 10:52       ` Michael Ellerman
2023-01-27 10:52         ` Michael Ellerman
2023-01-20  7:42 ` [PATCH v4 03/24] powerpc/secvar: Use u64 in secvar_operations Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 04/24] powerpc/secvar: Warn and error if multiple secvar ops are set Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 05/24] powerpc/secvar: Use sysfs_emit() instead of sprintf() Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 06/24] powerpc/secvar: Handle format string in the consumer Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 07/24] powerpc/secvar: Handle max object size " Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 08/24] powerpc/secvar: Clean up init error messages Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 09/24] powerpc/secvar: Extend sysfs to include config vars Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 10/24] powerpc/secvar: Allow backend to populate static list of variable names Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 11/24] powerpc/secvar: Warn when PAGE_SIZE is smaller than max object size Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 12/24] powerpc/secvar: Don't print error on ENOENT when reading variables Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 13/24] powerpc/pseries: Move plpks.h to include directory Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 14/24] powerpc/pseries: Move PLPKS constants to header file Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 15/24] powerpc/pseries: Expose PLPKS config values, support additional fields Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:42 ` [PATCH v4 16/24] powerpc/pseries: Implement signed update for PLPKS objects Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-24  4:16   ` Nicholas Piggin
2023-01-24  4:16     ` Nicholas Piggin
2023-01-30  4:43     ` Andrew Donnellan
2023-01-30  4:43       ` Andrew Donnellan
2023-01-31  4:23       ` Russell Currey
2023-01-31  4:23         ` Russell Currey
2023-01-20  7:42 ` [PATCH v4 17/24] powerpc/pseries: Log hcall return codes for PLPKS debug Andrew Donnellan
2023-01-20  7:42   ` Andrew Donnellan
2023-01-20  7:43 ` [PATCH v4 18/24] powerpc/pseries: Make caller pass buffer to plpks_read_var() Andrew Donnellan
2023-01-20  7:43   ` Andrew Donnellan
2023-01-20  7:43 ` [PATCH v4 19/24] powerpc/pseries: Turn PSERIES_PLPKS into a hidden option Andrew Donnellan
2023-01-20  7:43   ` Andrew Donnellan
2023-01-24  4:26   ` Nicholas Piggin
2023-01-24  4:26     ` Nicholas Piggin
2023-01-20  7:43 ` [PATCH v4 20/24] powerpc/pseries: Add helpers to get PLPKS password Andrew Donnellan
2023-01-20  7:43   ` Andrew Donnellan
2023-01-20  7:43 ` [PATCH v4 21/24] powerpc/pseries: Pass PLPKS password on kexec Andrew Donnellan
2023-01-20  7:43   ` Andrew Donnellan
2023-01-24  4:36   ` Nicholas Piggin
2023-01-24  4:36     ` Nicholas Piggin
2023-01-24  4:40     ` Andrew Donnellan
2023-01-24  4:40       ` Andrew Donnellan
2023-01-25  3:59       ` Michael Ellerman
2023-01-25  3:59         ` Michael Ellerman
2023-01-31  2:43     ` Russell Currey
2023-01-31  2:43       ` Russell Currey
2023-01-20  7:43 ` [PATCH v4 22/24] powerpc/pseries: Implement secvars for dynamic secure boot Andrew Donnellan
2023-01-20  7:43   ` Andrew Donnellan
2023-01-24  5:17   ` Nicholas Piggin
2023-01-24  5:17     ` Nicholas Piggin
2023-01-31  2:54     ` Andrew Donnellan
2023-01-31  2:54       ` Andrew Donnellan
2023-01-31  4:25       ` Andrew Donnellan
2023-01-31  4:25         ` Andrew Donnellan
2023-01-31  8:55       ` Nicholas Piggin
2023-01-31  8:55         ` Nicholas Piggin
2023-02-01  2:15         ` Andrew Donnellan
2023-02-01  2:15           ` Andrew Donnellan
2023-01-20  7:43 ` [PATCH v4 23/24] integrity/powerpc: Improve error handling & reporting when loading certs Andrew Donnellan
2023-01-20  7:43   ` Andrew Donnellan
2023-01-24 15:42   ` Mimi Zohar
2023-01-24 15:42     ` Mimi Zohar
2023-01-20  7:43 ` [PATCH v4 24/24] integrity/powerpc: Support loading keys from pseries secvar Andrew Donnellan
2023-01-20  7:43   ` Andrew Donnellan
2023-01-24  5:24   ` Nicholas Piggin
2023-01-24  5:24     ` Nicholas Piggin
2023-01-24 15:14   ` Mimi Zohar
2023-01-24 15:14     ` Mimi Zohar
2023-01-25  0:45     ` Andrew Donnellan
2023-01-25  0:45       ` Andrew Donnellan
2023-01-25  2:23     ` Russell Currey
2023-01-25  2:23       ` Russell Currey
2023-01-25  2:47       ` Mimi Zohar
2023-01-25  2:47         ` Mimi Zohar
2023-01-31  1:03         ` Andrew Donnellan
2023-01-31  1:03           ` Andrew Donnellan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.