[PATCH 3/4] powerpc/pseries: Expose PLPKS config values, support additional fields

Russell Currey ruscur at russell.cc
Wed Jan 4 14:57:39 AEDT 2023


On Tue, 2022-12-20 at 18:16 +1100, Andrew Donnellan wrote:
> From: Nayna Jain <nayna at 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.
> 
> 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 at linux.ibm.com>
> [ajd: split patch, extend to support additional v3 API fields, minor
> fixes]
> Co-developed-by: Andrew Donnellan <ajd at linux.ibm.com>
> Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
> ---
>  arch/powerpc/platforms/pseries/plpks.c | 118 ++++++++++++++++++++++-
> --
>  arch/powerpc/platforms/pseries/plpks.h |  58 ++++++++++++
>  2 files changed, 164 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/powerpc/platforms/pseries/plpks.c
> b/arch/powerpc/platforms/pseries/plpks.c
> index 8ccc91143370..c5ae00a8a968 100644
> --- a/arch/powerpc/platforms/pseries/plpks.c
> +++ b/arch/powerpc/platforms/pseries/plpks.c
> @@ -38,8 +38,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;
> @@ -220,32 +228,118 @@ 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;
> +       }
>  
> -       size = sizeof(config);
> +       rc = plpar_hcall(H_PKS_GET_CONFIG, retbuf,
> virt_to_phys(config), size);
>  
> -       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;
> +       }
>  
> -       if (rc != H_SUCCESS)
> -               return pseries_status_to_err(rc);
> +       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) -
> +                         MAX_LABEL_ATTR_SIZE;
> +       maxobjlabelsize = maxobjlabelsize < 0 ? 0 : maxobjlabelsize;

Isn't a bit of precision lost here?  There has to be a better way to
handle this.  We get a be16 from the hypervisor, turn it into a u16,
and assign that to an s16 in order to handle underflow.  Can we just
check if the size we're given is large enough?  The hypervisor
documentation also says this value must be at least 255, if we sanity
check that we don't have to worry about underflow.

> +       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);
> +
> +err:
> +       kfree(config);
> +       return rc;
> +}
>  
> -       maxpwsize = be16_to_cpu(config.maxpwsize);
> -       maxobjsize = be16_to_cpu(config.maxobjsize);
> +u8 plpks_get_version(void)
> +{
> +       return version;
> +}
> +
> +u16 plpks_get_objoverhead(void)
> +{
> +       return objoverhead;
> +}
> +
> +u16 plpks_get_maxpwsize(void)
> +{
> +       return maxpwsize;
> +}
> +
> +u16 plpks_get_maxobjectsize(void)
> +{
> +       return maxobjsize;
> +}
> +
> +u16 plpks_get_maxobjectlabelsize(void)

and it's returned as a u16 here.

> +{
> +       return maxobjlabelsize;
> +}
> +
> +u32 plpks_get_totalsize(void)
> +{
> +       return totalsize;
> +}
> +
> +u32 plpks_get_usedspace(void)
> +{
> +       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,
> diff --git a/arch/powerpc/platforms/pseries/plpks.h
> b/arch/powerpc/platforms/pseries/plpks.h
> index 275ccd86bfb5..c89740796660 100644
> --- a/arch/powerpc/platforms/pseries/plpks.h
> +++ b/arch/powerpc/platforms/pseries/plpks.h
> @@ -68,4 +68,62 @@ 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



More information about the Linuxppc-dev mailing list