1 // SPDX-License-Identifier: GPL-2.0-only 2 3 // Secure variable implementation using the PowerVM LPAR Platform KeyStore (PLPKS) 4 // 5 // Copyright 2022, 2023 IBM Corporation 6 // Authors: Russell Currey 7 // Andrew Donnellan 8 // Nayna Jain 9 10 #define pr_fmt(fmt) "secvar: "fmt 11 12 #include <linux/printk.h> 13 #include <linux/init.h> 14 #include <linux/types.h> 15 #include <linux/slab.h> 16 #include <linux/string.h> 17 #include <linux/kobject.h> 18 #include <linux/nls.h> 19 #include <asm/machdep.h> 20 #include <asm/secvar.h> 21 #include <asm/plpks.h> 22 23 // Config attributes for sysfs 24 #define PLPKS_CONFIG_ATTR(name, fmt, func) \ 25 static ssize_t name##_show(struct kobject *kobj, \ 26 struct kobj_attribute *attr, \ 27 char *buf) \ 28 { \ 29 return sysfs_emit(buf, fmt, func()); \ 30 } \ 31 static struct kobj_attribute attr_##name = __ATTR_RO(name) 32 33 PLPKS_CONFIG_ATTR(version, "%u\n", plpks_get_version); 34 PLPKS_CONFIG_ATTR(max_object_size, "%u\n", plpks_get_maxobjectsize); 35 PLPKS_CONFIG_ATTR(total_size, "%u\n", plpks_get_totalsize); 36 PLPKS_CONFIG_ATTR(used_space, "%u\n", plpks_get_usedspace); 37 PLPKS_CONFIG_ATTR(supported_policies, "%08x\n", plpks_get_supportedpolicies); 38 PLPKS_CONFIG_ATTR(signed_update_algorithms, "%016llx\n", plpks_get_signedupdatealgorithms); 39 40 static const struct attribute *config_attrs[] = { 41 &attr_version.attr, 42 &attr_max_object_size.attr, 43 &attr_total_size.attr, 44 &attr_used_space.attr, 45 &attr_supported_policies.attr, 46 &attr_signed_update_algorithms.attr, 47 NULL, 48 }; 49 50 static u32 get_policy(const char *name) 51 { 52 if ((strcmp(name, "db") == 0) || 53 (strcmp(name, "dbx") == 0) || 54 (strcmp(name, "grubdb") == 0) || 55 (strcmp(name, "grubdbx") == 0) || 56 (strcmp(name, "sbat") == 0)) 57 return (PLPKS_WORLDREADABLE | PLPKS_SIGNEDUPDATE); 58 else 59 return PLPKS_SIGNEDUPDATE; 60 } 61 62 static const char * const plpks_var_names_static[] = { 63 "PK", 64 "moduledb", 65 "trustedcadb", 66 NULL, 67 }; 68 69 static const char * const plpks_var_names_dynamic[] = { 70 "PK", 71 "KEK", 72 "db", 73 "dbx", 74 "grubdb", 75 "grubdbx", 76 "sbat", 77 "moduledb", 78 "trustedcadb", 79 NULL, 80 }; 81 82 static int plpks_get_variable(const char *key, u64 key_len, u8 *data, 83 u64 *data_size) 84 { 85 struct plpks_var var = {0}; 86 int rc = 0; 87 88 // We subtract 1 from key_len because we don't need to include the 89 // null terminator at the end of the string 90 var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL); 91 if (!var.name) 92 return -ENOMEM; 93 rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name, 94 key_len - 1); 95 if (rc < 0) 96 goto err; 97 var.namelen = rc * 2; 98 99 var.os = PLPKS_VAR_LINUX; 100 if (data) { 101 var.data = data; 102 var.datalen = *data_size; 103 } 104 rc = plpks_read_os_var(&var); 105 106 if (rc) 107 goto err; 108 109 *data_size = var.datalen; 110 111 err: 112 kfree(var.name); 113 if (rc && rc != -ENOENT) { 114 pr_err("Failed to read variable '%s': %d\n", key, rc); 115 // Return -EIO since userspace probably doesn't care about the 116 // specific error 117 rc = -EIO; 118 } 119 return rc; 120 } 121 122 static int plpks_set_variable(const char *key, u64 key_len, u8 *data, 123 u64 data_size) 124 { 125 struct plpks_var var = {0}; 126 int rc = 0; 127 u64 flags; 128 129 // Secure variables need to be prefixed with 8 bytes of flags. 130 // We only want to perform the write if we have at least one byte of data. 131 if (data_size <= sizeof(flags)) 132 return -EINVAL; 133 134 // We subtract 1 from key_len because we don't need to include the 135 // null terminator at the end of the string 136 var.name = kcalloc(key_len - 1, sizeof(wchar_t), GFP_KERNEL); 137 if (!var.name) 138 return -ENOMEM; 139 rc = utf8s_to_utf16s(key, key_len - 1, UTF16_LITTLE_ENDIAN, (wchar_t *)var.name, 140 key_len - 1); 141 if (rc < 0) 142 goto err; 143 var.namelen = rc * 2; 144 145 // Flags are contained in the first 8 bytes of the buffer, and are always big-endian 146 flags = be64_to_cpup((__be64 *)data); 147 148 var.datalen = data_size - sizeof(flags); 149 var.data = data + sizeof(flags); 150 var.os = PLPKS_VAR_LINUX; 151 var.policy = get_policy(key); 152 153 // Unlike in the read case, the plpks error code can be useful to 154 // userspace on write, so we return it rather than just -EIO 155 rc = plpks_signed_update_var(&var, flags); 156 157 err: 158 kfree(var.name); 159 return rc; 160 } 161 162 /* 163 * Return the key management mode. 164 * 165 * SB_VERSION is defined as a "1 byte unsigned integer value", taking values 166 * starting from 1. It is owned by the Partition Firmware and its presence 167 * indicates that the key management mode is dynamic. Any failure in 168 * reading SB_VERSION defaults the key management mode to static. The error 169 * codes -ENOENT or -EPERM are expected in static key management mode. An 170 * unexpected error code will have to be investigated. Only signed variables 171 * have null bytes in their names, SB_VERSION does not. 172 * 173 * Return 0 to indicate that the key management mode is static. Otherwise 174 * return the SB_VERSION value to indicate that the key management mode is 175 * dynamic. 176 */ 177 static u8 plpks_get_sb_keymgmt_mode(void) 178 { 179 u8 mode; 180 ssize_t rc; 181 struct plpks_var var = { 182 .component = NULL, 183 .name = "SB_VERSION", 184 .namelen = 10, 185 .datalen = 1, 186 .data = &mode, 187 }; 188 189 rc = plpks_read_fw_var(&var); 190 if (rc) { 191 if (rc != -ENOENT && rc != -EPERM) 192 pr_info("Error %ld reading SB_VERSION from firmware\n", rc); 193 mode = 0; 194 } 195 return mode; 196 } 197 198 /* 199 * PLPKS dynamic secure boot doesn't give us a format string in the same way 200 * OPAL does. Instead, report the format using the SB_VERSION variable in the 201 * keystore. The string, made up by us, takes the form of either 202 * "ibm,plpks-sb-v<n>" or "ibm,plpks-sb-v0", based on the key management mode, 203 * and return the length of the secvar format property. 204 */ 205 static ssize_t plpks_secvar_format(char *buf, size_t bufsize) 206 { 207 u8 mode; 208 209 mode = plpks_get_sb_keymgmt_mode(); 210 return snprintf(buf, bufsize, "ibm,plpks-sb-v%hhu", mode); 211 } 212 213 static int plpks_max_size(u64 *max_size) 214 { 215 // The max object size reported by the hypervisor is accurate for the 216 // object itself, but we use the first 8 bytes of data on write as the 217 // signed update flags, so the max size a user can write is larger. 218 *max_size = (u64)plpks_get_maxobjectsize() + sizeof(u64); 219 220 return 0; 221 } 222 223 static const struct secvar_operations plpks_secvar_ops_static = { 224 .get = plpks_get_variable, 225 .set = plpks_set_variable, 226 .format = plpks_secvar_format, 227 .max_size = plpks_max_size, 228 .config_attrs = config_attrs, 229 .var_names = plpks_var_names_static, 230 }; 231 232 static const struct secvar_operations plpks_secvar_ops_dynamic = { 233 .get = plpks_get_variable, 234 .set = plpks_set_variable, 235 .format = plpks_secvar_format, 236 .max_size = plpks_max_size, 237 .config_attrs = config_attrs, 238 .var_names = plpks_var_names_dynamic, 239 }; 240 241 static int plpks_secvar_init(void) 242 { 243 u8 mode; 244 245 if (!plpks_is_available()) 246 return -ENODEV; 247 248 mode = plpks_get_sb_keymgmt_mode(); 249 if (mode) 250 return set_secvar_ops(&plpks_secvar_ops_dynamic); 251 return set_secvar_ops(&plpks_secvar_ops_static); 252 } 253 machine_device_initcall(pseries, plpks_secvar_init); 254