[PATCH 1/2] powerpc/pseries: define driver for Platform KeyStore

Gregory Joyce gjoyce at ibm.com
Tue Jul 19 08:30:13 AEST 2022


Comments inline.
Reviewed-by: Greg Joyce <gjoyce at linux.vnet.ibm.com>

________________________________
From: Nayna Jain <nayna at linux.ibm.com>
Sent: Tuesday, July 12, 2022 7:59 PM
To: linuxppc-dev at lists.ozlabs.org <linuxppc-dev at lists.ozlabs.org>
Cc: Michael Ellerman <mpe at ellerman.id.au>; Benjamin Herrenschmidt <benh at kernel.crashing.org>; Paul Mackerras <paulus at samba.org>; George Wilson <gcwilson at linux.ibm.com>; Gregory Joyce <gjoyce at ibm.com>; Nayna Jain <nayna at linux.ibm.com>
Subject: [PATCH 1/2] powerpc/pseries: define driver for Platform KeyStore

PowerVM provides an isolated Platform Keystore(PKS) storage allocation
for each LPAR with individually managed access controls to store
sensitive information securely. It provides a new set of hypervisor
calls for Linux kernel to access PKS storage.

Define PLPKS driver using H_CALL interface to access PKS storage.

Signed-off-by: Nayna Jain <nayna at linux.ibm.com>
---


+
+static int construct_auth(u8 consumer, struct plpks_auth **auth)
+{
+       pr_debug("max password size is %u\n", config->maxpwsize);

Are the pr_debugs in this function still needed?

+
+       if (!auth || consumer > 3)
+               return -EINVAL;
+
+       *auth = kmalloc(struct_size(*auth, password, config->maxpwsize),
+                       GFP_KERNEL);
+       if (!*auth)
+               return -ENOMEM;
+
+       (*auth)->version = 1;
+       (*auth)->consumer = consumer;
+       (*auth)->rsvd0 = 0;
+       (*auth)->rsvd1 = 0;
+       if (consumer == PKS_FW_OWNER || consumer == PKS_BOOTLOADER_OWNER) {
+               pr_debug("consumer is bootloader or firmware\n");
+               (*auth)->passwordlength = 0;
+               return 0;
+       }
+
+       (*auth)->passwordlength = (__force __be16)ospasswordlength;
+
+       memcpy((*auth)->password, ospassword,
+              flex_array_size(*auth, password,
+              (__force u16)((*auth)->passwordlength)));
+       (*auth)->passwordlength = cpu_to_be16((__force u16)((*auth)->passwordlength));
+
+       return 0;
+}
+
+/**
+ * Label is combination of label attributes + name.
+ * Label attributes are used internally by kernel and not exposed to the user.
+ */
+static int construct_label(char *component, u8 varos, u8 *name, u16 namelen, u8 **label)
+{
+       int varlen;
+       int len = 0;
+       int llen = 0;
+       int i;
+       int rc = 0;
+       u8 labellength = MAX_LABEL_ATTR_SIZE;
+
+       if (!label)
+               return -EINVAL;
+
+       varlen = namelen + sizeof(struct label_attr);
+       *label = kzalloc(varlen, GFP_KERNEL);
+
+       if (!*label)
+               return -ENOMEM;
+
+       if (component) {
+               len = strlen(component);
+               memcpy(*label, component, len);
+       }
+       llen = len;
+

I guess the 8, 1, and 5 are field lengths. Could they be a define or sizeof?

+       if (component)
+               len = 8 - strlen(component);
+       else
+               len = 8;
+
+       memset(*label + llen, 0, len);
+       llen = llen + len;
+
+       ((*label)[llen]) = 0;
+       llen = llen + 1;
+
+       memcpy(*label + llen, &varos, 1);
+       llen = llen + 1;
+
+       memcpy(*label + llen, &labellength, 1);
+       llen = llen + 1;
+
+       memset(*label + llen, 0, 5);
+       llen = llen + 5;
+
+       memcpy(*label + llen, name, namelen);
+       llen = llen + namelen;
+
+       for (i = 0; i < llen; i++)
+               pr_debug("%c", (*label)[i]);
+
+       rc = llen;
+       return rc;
+}
+
+static int _plpks_get_config(void)
+{
+       unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = {0};
+       int rc;
+       size_t size = sizeof(struct plpks_config);
+
+       config = kzalloc(size, GFP_KERNEL);
+       if (!config)
+               return -ENOMEM;
+
+       rc = plpar_hcall(H_PKS_GET_CONFIG,
+                        retbuf,
+                        virt_to_phys(config),
+                        size);
+
+       if (rc != H_SUCCESS)

Free config before returning the error.

+               return pseries_status_to_err(rc);
+
+       config->rsvd0 = be32_to_cpu((__force __be32)config->rsvd0);
+       config->maxpwsize = be16_to_cpu((__force __be16)config->maxpwsize);
+       config->maxobjlabelsize = be16_to_cpu((__force __be16)config->maxobjlabelsize);
+       config->maxobjsize = be16_to_cpu((__force __be16)config->maxobjsize);
+       config->totalsize = be32_to_cpu((__force __be32)config->totalsize);
+       config->usedspace = be32_to_cpu((__force __be32)config->usedspace);
+       config->supportedpolicies = be32_to_cpu((__force __be32)config->supportedpolicies);
+       config->rsvd1 = be64_to_cpu((__force __be64)config->rsvd1);
+
+       configset = true;
+
+       return 0;
+}
+
+static int plpks_confirm_object_flushed(u8 *label, u16 labellen)
+{
+       unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = {0};
+       int rc;
+       u64 timeout = 0;
+       struct plpks_auth *auth;
+       u8 status;
+       int i;
+

Deleted pr_debugs? I guess this is a general question for all pr_debugs in this file.

+       rc = construct_auth(PKS_OS_OWNER, &auth);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < labellen; i++)
+               pr_debug("%02x ", label[i]);
+
+       do {
+               rc = plpar_hcall(H_PKS_CONFIRM_OBJECT_FLUSHED,
+                                retbuf,
+                                virt_to_phys(auth),
+                                virt_to_phys(label),
+                                labellen);
+
+               status = retbuf[0];
+               if (rc) {
+                       pr_info("rc is %d, status is %d\n", rc, status);
+                       if (rc == H_NOT_FOUND && status == 1)
+                               rc = 0;
+                       break;
+               }
+
+               pr_debug("rc is %d, status is %d\n", rc, status);
+
+               if (!rc && status == 1)
+                       break;
+
+               usleep_range(PKS_FLUSH_SLEEP, PKS_FLUSH_SLEEP + PKS_FLUSH_SLEEP_RANGE);
+               timeout = timeout + PKS_FLUSH_SLEEP;
+               pr_debug("timeout is %llu\n", timeout);
+
+       } while (timeout < PKS_FLUSH_MAX_TIMEOUT);
+
+       rc = pseries_status_to_err(rc);
+
+       kfree(auth);
+
+       return rc;
+}
+

+EXPORT_SYMBOL(plpks_remove_var);
XPORT_SYMBOL(plpks_get_config);
+
+static __init int pseries_plpks_init(void)
+{
+       int rc = 0;
+
+       rc = _plpks_get_config();
+
+       if (rc) {

I think this pr_err would be better if provided more info like the pr_info below.

+               pr_err("Error initializing plpks\n");
+               return rc;
+       }
+
+       rc = plpks_gen_password();
+       if (rc) {
+               if (rc == H_IN_USE) {
+                       rc = 0;
+               } else {

I think this pr_err would be better if provided more info like the pr_info below.

+                       pr_err("Failed setting password %d\n", rc);
+                       rc = pseries_status_to_err(rc);
+                       return rc;
+               }
+       }
+
+       pr_info("POWER LPAR Platform Keystore initialized successfully\n");
+
+       return rc;
+}
+arch_initcall(pseries_plpks_init);
--
2.27.0

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/linuxppc-dev/attachments/20220718/d5f5aaf8/attachment-0001.htm>


More information about the Linuxppc-dev mailing list