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@xxxxxxxxxxxxx IBM Australia Limited