1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * POWER LPAR Platform KeyStore(PLPKS) 4 * Copyright (C) 2022 IBM Corporation 5 * Author: Nayna Jain <nayna@linux.ibm.com> 6 * 7 * Provides access to variables stored in Power LPAR Platform KeyStore(PLPKS). 8 */ 9 10 #define pr_fmt(fmt) "plpks: " fmt 11 12 #include <linux/delay.h> 13 #include <linux/errno.h> 14 #include <linux/io.h> 15 #include <linux/printk.h> 16 #include <linux/slab.h> 17 #include <linux/string.h> 18 #include <linux/types.h> 19 #include <asm/hvcall.h> 20 #include <asm/machdep.h> 21 22 #include "plpks.h" 23 24 #define PKS_FW_OWNER 0x1 25 #define PKS_BOOTLOADER_OWNER 0x2 26 #define PKS_OS_OWNER 0x3 27 28 #define LABEL_VERSION 0 29 #define MAX_LABEL_ATTR_SIZE 16 30 #define MAX_NAME_SIZE 239 31 #define MAX_DATA_SIZE 4000 32 33 #define PKS_FLUSH_MAX_TIMEOUT 5000 //msec 34 #define PKS_FLUSH_SLEEP 10 //msec 35 #define PKS_FLUSH_SLEEP_RANGE 400 36 37 static u8 *ospassword; 38 static u16 ospasswordlength; 39 40 // Retrieved with H_PKS_GET_CONFIG 41 static u16 maxpwsize; 42 static u16 maxobjsize; 43 44 struct plpks_auth { 45 u8 version; 46 u8 consumer; 47 __be64 rsvd0; 48 __be32 rsvd1; 49 __be16 passwordlength; 50 u8 password[]; 51 } __packed __aligned(16); 52 53 struct label_attr { 54 u8 prefix[8]; 55 u8 version; 56 u8 os; 57 u8 length; 58 u8 reserved[5]; 59 }; 60 61 struct label { 62 struct label_attr attr; 63 u8 name[MAX_NAME_SIZE]; 64 size_t size; 65 }; 66 67 static int pseries_status_to_err(int rc) 68 { 69 int err; 70 71 switch (rc) { 72 case H_SUCCESS: 73 err = 0; 74 break; 75 case H_FUNCTION: 76 err = -ENXIO; 77 break; 78 case H_P1: 79 case H_P2: 80 case H_P3: 81 case H_P4: 82 case H_P5: 83 case H_P6: 84 err = -EINVAL; 85 break; 86 case H_NOT_FOUND: 87 err = -ENOENT; 88 break; 89 case H_BUSY: 90 err = -EBUSY; 91 break; 92 case H_AUTHORITY: 93 err = -EPERM; 94 break; 95 case H_NO_MEM: 96 err = -ENOMEM; 97 break; 98 case H_RESOURCE: 99 err = -EEXIST; 100 break; 101 case H_TOO_BIG: 102 err = -EFBIG; 103 break; 104 case H_STATE: 105 err = -EIO; 106 break; 107 case H_R_STATE: 108 err = -EIO; 109 break; 110 case H_IN_USE: 111 err = -EEXIST; 112 break; 113 case H_ABORTED: 114 err = -EINTR; 115 break; 116 default: 117 err = -EINVAL; 118 } 119 120 return err; 121 } 122 123 static int plpks_gen_password(void) 124 { 125 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 }; 126 u8 *password, consumer = PKS_OS_OWNER; 127 int rc; 128 129 password = kzalloc(maxpwsize, GFP_KERNEL); 130 if (!password) 131 return -ENOMEM; 132 133 rc = plpar_hcall(H_PKS_GEN_PASSWORD, retbuf, consumer, 0, 134 virt_to_phys(password), maxpwsize); 135 136 if (!rc) { 137 ospasswordlength = maxpwsize; 138 ospassword = kzalloc(maxpwsize, GFP_KERNEL); 139 if (!ospassword) { 140 kfree(password); 141 return -ENOMEM; 142 } 143 memcpy(ospassword, password, ospasswordlength); 144 } else { 145 if (rc == H_IN_USE) { 146 pr_warn("Password is already set for POWER LPAR Platform KeyStore\n"); 147 rc = 0; 148 } else { 149 goto out; 150 } 151 } 152 out: 153 kfree(password); 154 155 return pseries_status_to_err(rc); 156 } 157 158 static struct plpks_auth *construct_auth(u8 consumer) 159 { 160 struct plpks_auth *auth; 161 162 if (consumer > PKS_OS_OWNER) 163 return ERR_PTR(-EINVAL); 164 165 auth = kmalloc(struct_size(auth, password, maxpwsize), GFP_KERNEL); 166 if (!auth) 167 return ERR_PTR(-ENOMEM); 168 169 auth->version = 1; 170 auth->consumer = consumer; 171 auth->rsvd0 = 0; 172 auth->rsvd1 = 0; 173 174 if (consumer == PKS_FW_OWNER || consumer == PKS_BOOTLOADER_OWNER) { 175 auth->passwordlength = 0; 176 return auth; 177 } 178 179 memcpy(auth->password, ospassword, ospasswordlength); 180 181 auth->passwordlength = cpu_to_be16(ospasswordlength); 182 183 return auth; 184 } 185 186 /** 187 * Label is combination of label attributes + name. 188 * Label attributes are used internally by kernel and not exposed to the user. 189 */ 190 static struct label *construct_label(char *component, u8 varos, u8 *name, 191 u16 namelen) 192 { 193 struct label *label; 194 size_t slen; 195 196 if (!name || namelen > MAX_NAME_SIZE) 197 return ERR_PTR(-EINVAL); 198 199 slen = strlen(component); 200 if (component && slen > sizeof(label->attr.prefix)) 201 return ERR_PTR(-EINVAL); 202 203 label = kzalloc(sizeof(*label), GFP_KERNEL); 204 if (!label) 205 return ERR_PTR(-ENOMEM); 206 207 if (component) 208 memcpy(&label->attr.prefix, component, slen); 209 210 label->attr.version = LABEL_VERSION; 211 label->attr.os = varos; 212 label->attr.length = MAX_LABEL_ATTR_SIZE; 213 memcpy(&label->name, name, namelen); 214 215 label->size = sizeof(struct label_attr) + namelen; 216 217 return label; 218 } 219 220 static int _plpks_get_config(void) 221 { 222 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 }; 223 struct { 224 u8 version; 225 u8 flags; 226 __be32 rsvd0; 227 __be16 maxpwsize; 228 __be16 maxobjlabelsize; 229 __be16 maxobjsize; 230 __be32 totalsize; 231 __be32 usedspace; 232 __be32 supportedpolicies; 233 __be64 rsvd1; 234 } __packed config; 235 size_t size; 236 int rc; 237 238 size = sizeof(config); 239 240 rc = plpar_hcall(H_PKS_GET_CONFIG, retbuf, virt_to_phys(&config), size); 241 242 if (rc != H_SUCCESS) 243 return pseries_status_to_err(rc); 244 245 maxpwsize = be16_to_cpu(config.maxpwsize); 246 maxobjsize = be16_to_cpu(config.maxobjsize); 247 248 return 0; 249 } 250 251 static int plpks_confirm_object_flushed(struct label *label, 252 struct plpks_auth *auth) 253 { 254 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 }; 255 u64 timeout = 0; 256 u8 status; 257 int rc; 258 259 do { 260 rc = plpar_hcall(H_PKS_CONFIRM_OBJECT_FLUSHED, retbuf, 261 virt_to_phys(auth), virt_to_phys(label), 262 label->size); 263 264 status = retbuf[0]; 265 if (rc) { 266 if (rc == H_NOT_FOUND && status == 1) 267 rc = 0; 268 break; 269 } 270 271 if (!rc && status == 1) 272 break; 273 274 usleep_range(PKS_FLUSH_SLEEP, 275 PKS_FLUSH_SLEEP + PKS_FLUSH_SLEEP_RANGE); 276 timeout = timeout + PKS_FLUSH_SLEEP; 277 } while (timeout < PKS_FLUSH_MAX_TIMEOUT); 278 279 rc = pseries_status_to_err(rc); 280 281 return rc; 282 } 283 284 int plpks_write_var(struct plpks_var var) 285 { 286 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 }; 287 struct plpks_auth *auth; 288 struct label *label; 289 int rc; 290 291 if (!var.component || !var.data || var.datalen <= 0 || 292 var.namelen > MAX_NAME_SIZE || var.datalen > MAX_DATA_SIZE) 293 return -EINVAL; 294 295 if (var.policy & SIGNEDUPDATE) 296 return -EINVAL; 297 298 auth = construct_auth(PKS_OS_OWNER); 299 if (IS_ERR(auth)) 300 return PTR_ERR(auth); 301 302 label = construct_label(var.component, var.os, var.name, var.namelen); 303 if (IS_ERR(label)) { 304 rc = PTR_ERR(label); 305 goto out; 306 } 307 308 rc = plpar_hcall(H_PKS_WRITE_OBJECT, retbuf, virt_to_phys(auth), 309 virt_to_phys(label), label->size, var.policy, 310 virt_to_phys(var.data), var.datalen); 311 312 if (!rc) 313 rc = plpks_confirm_object_flushed(label, auth); 314 315 if (rc) 316 pr_err("Failed to write variable %s for component %s with error %d\n", 317 var.name, var.component, rc); 318 319 rc = pseries_status_to_err(rc); 320 kfree(label); 321 out: 322 kfree(auth); 323 324 return rc; 325 } 326 327 int plpks_remove_var(char *component, u8 varos, struct plpks_var_name vname) 328 { 329 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 }; 330 struct plpks_auth *auth; 331 struct label *label; 332 int rc; 333 334 if (!component || vname.namelen > MAX_NAME_SIZE) 335 return -EINVAL; 336 337 auth = construct_auth(PKS_OS_OWNER); 338 if (IS_ERR(auth)) 339 return PTR_ERR(auth); 340 341 label = construct_label(component, varos, vname.name, vname.namelen); 342 if (IS_ERR(label)) { 343 rc = PTR_ERR(label); 344 goto out; 345 } 346 347 rc = plpar_hcall(H_PKS_REMOVE_OBJECT, retbuf, virt_to_phys(auth), 348 virt_to_phys(label), label->size); 349 350 if (!rc) 351 rc = plpks_confirm_object_flushed(label, auth); 352 353 if (rc) 354 pr_err("Failed to remove variable %s for component %s with error %d\n", 355 vname.name, component, rc); 356 357 rc = pseries_status_to_err(rc); 358 kfree(label); 359 out: 360 kfree(auth); 361 362 return rc; 363 } 364 365 static int plpks_read_var(u8 consumer, struct plpks_var *var) 366 { 367 unsigned long retbuf[PLPAR_HCALL_BUFSIZE] = { 0 }; 368 struct plpks_auth *auth; 369 struct label *label; 370 u8 *output; 371 int rc; 372 373 if (var->namelen > MAX_NAME_SIZE) 374 return -EINVAL; 375 376 auth = construct_auth(PKS_OS_OWNER); 377 if (IS_ERR(auth)) 378 return PTR_ERR(auth); 379 380 label = construct_label(var->component, var->os, var->name, 381 var->namelen); 382 if (IS_ERR(label)) { 383 rc = PTR_ERR(label); 384 goto out_free_auth; 385 } 386 387 output = kzalloc(maxobjsize, GFP_KERNEL); 388 if (!output) { 389 rc = -ENOMEM; 390 goto out_free_label; 391 } 392 393 rc = plpar_hcall(H_PKS_READ_OBJECT, retbuf, virt_to_phys(auth), 394 virt_to_phys(label), label->size, virt_to_phys(output), 395 maxobjsize); 396 397 if (rc != H_SUCCESS) { 398 pr_err("Failed to read variable %s for component %s with error %d\n", 399 var->name, var->component, rc); 400 rc = pseries_status_to_err(rc); 401 goto out_free_output; 402 } 403 404 if (var->datalen == 0 || var->datalen > retbuf[0]) 405 var->datalen = retbuf[0]; 406 407 var->data = kzalloc(var->datalen, GFP_KERNEL); 408 if (!var->data) { 409 rc = -ENOMEM; 410 goto out_free_output; 411 } 412 var->policy = retbuf[1]; 413 414 memcpy(var->data, output, var->datalen); 415 rc = 0; 416 417 out_free_output: 418 kfree(output); 419 out_free_label: 420 kfree(label); 421 out_free_auth: 422 kfree(auth); 423 424 return rc; 425 } 426 427 int plpks_read_os_var(struct plpks_var *var) 428 { 429 return plpks_read_var(PKS_OS_OWNER, var); 430 } 431 432 int plpks_read_fw_var(struct plpks_var *var) 433 { 434 return plpks_read_var(PKS_FW_OWNER, var); 435 } 436 437 int plpks_read_bootloader_var(struct plpks_var *var) 438 { 439 return plpks_read_var(PKS_BOOTLOADER_OWNER, var); 440 } 441 442 static __init int pseries_plpks_init(void) 443 { 444 int rc; 445 446 rc = _plpks_get_config(); 447 448 if (rc) { 449 pr_err("POWER LPAR Platform KeyStore is not supported or enabled\n"); 450 return rc; 451 } 452 453 rc = plpks_gen_password(); 454 if (rc) 455 pr_err("Failed setting POWER LPAR Platform KeyStore Password\n"); 456 else 457 pr_info("POWER LPAR Platform KeyStore initialized successfully\n"); 458 459 return rc; 460 } 461 machine_arch_initcall(pseries, pseries_plpks_init); 462