162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright IBM Corp. 2022 462306a36Sopenharmony_ci * Author(s): Steffen Eiden <seiden@linux.ibm.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This file provides a Linux misc device to give userspace access to some 762306a36Sopenharmony_ci * Ultravisor (UV) functions. The device only accepts IOCTLs and will only 862306a36Sopenharmony_ci * be present if the Ultravisor facility (158) is present. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * When userspace sends a valid IOCTL uvdevice will copy the input data to 1162306a36Sopenharmony_ci * kernel space, do some basic validity checks to avoid kernel/system 1262306a36Sopenharmony_ci * corruption. Any other check that the Ultravisor does will not be done by 1362306a36Sopenharmony_ci * the uvdevice to keep changes minimal when adding new functionalities 1462306a36Sopenharmony_ci * to existing UV-calls. 1562306a36Sopenharmony_ci * After the checks uvdevice builds a corresponding 1662306a36Sopenharmony_ci * Ultravisor Call Control Block, and sends the request to the Ultravisor. 1762306a36Sopenharmony_ci * Then, it copies the response, including the return codes, back to userspace. 1862306a36Sopenharmony_ci * It is the responsibility of the userspace to check for any error issued 1962306a36Sopenharmony_ci * by UV and to interpret the UV response. The uvdevice acts as a communication 2062306a36Sopenharmony_ci * channel for userspace to the Ultravisor. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci#include <linux/kernel.h> 2562306a36Sopenharmony_ci#include <linux/miscdevice.h> 2662306a36Sopenharmony_ci#include <linux/types.h> 2762306a36Sopenharmony_ci#include <linux/stddef.h> 2862306a36Sopenharmony_ci#include <linux/vmalloc.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/cpufeature.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <asm/uvdevice.h> 3362306a36Sopenharmony_ci#include <asm/uv.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define BIT_UVIO_INTERNAL U32_MAX 3662306a36Sopenharmony_ci/* Mapping from IOCTL-nr to UVC-bit */ 3762306a36Sopenharmony_cistatic const u32 ioctl_nr_to_uvc_bit[] __initconst = { 3862306a36Sopenharmony_ci [UVIO_IOCTL_UVDEV_INFO_NR] = BIT_UVIO_INTERNAL, 3962306a36Sopenharmony_ci [UVIO_IOCTL_ATT_NR] = BIT_UVC_CMD_RETR_ATTEST, 4062306a36Sopenharmony_ci [UVIO_IOCTL_ADD_SECRET_NR] = BIT_UVC_CMD_ADD_SECRET, 4162306a36Sopenharmony_ci [UVIO_IOCTL_LIST_SECRETS_NR] = BIT_UVC_CMD_LIST_SECRETS, 4262306a36Sopenharmony_ci [UVIO_IOCTL_LOCK_SECRETS_NR] = BIT_UVC_CMD_LOCK_SECRETS, 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic_assert(ARRAY_SIZE(ioctl_nr_to_uvc_bit) == UVIO_IOCTL_NUM_IOCTLS); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic struct uvio_uvdev_info uvdev_info = { 4862306a36Sopenharmony_ci .supp_uvio_cmds = GENMASK_ULL(UVIO_IOCTL_NUM_IOCTLS - 1, 0), 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void __init set_supp_uv_cmds(unsigned long *supp_uv_cmds) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci int i; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci for (i = 0; i < UVIO_IOCTL_NUM_IOCTLS; i++) { 5662306a36Sopenharmony_ci if (ioctl_nr_to_uvc_bit[i] == BIT_UVIO_INTERNAL) 5762306a36Sopenharmony_ci continue; 5862306a36Sopenharmony_ci if (!test_bit_inv(ioctl_nr_to_uvc_bit[i], uv_info.inst_calls_list)) 5962306a36Sopenharmony_ci continue; 6062306a36Sopenharmony_ci __set_bit(i, supp_uv_cmds); 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/** 6562306a36Sopenharmony_ci * uvio_uvdev_info() - get information about the uvdevice 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * @uv_ioctl: ioctl control block 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * Lists all IOCTLs that are supported by this uvdevice 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_cistatic int uvio_uvdev_info(struct uvio_ioctl_cb *uv_ioctl) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (uv_ioctl->argument_len < sizeof(uvdev_info)) 7662306a36Sopenharmony_ci return -EINVAL; 7762306a36Sopenharmony_ci if (copy_to_user(user_buf_arg, &uvdev_info, sizeof(uvdev_info))) 7862306a36Sopenharmony_ci return -EFAULT; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci uv_ioctl->uv_rc = UVC_RC_EXECUTED; 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int uvio_build_uvcb_attest(struct uv_cb_attest *uvcb_attest, u8 *arcb, 8562306a36Sopenharmony_ci u8 *meas, u8 *add_data, struct uvio_attest *uvio_attest) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci void __user *user_buf_arcb = (void __user *)uvio_attest->arcb_addr; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (copy_from_user(arcb, user_buf_arcb, uvio_attest->arcb_len)) 9062306a36Sopenharmony_ci return -EFAULT; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci uvcb_attest->header.len = sizeof(*uvcb_attest); 9362306a36Sopenharmony_ci uvcb_attest->header.cmd = UVC_CMD_RETR_ATTEST; 9462306a36Sopenharmony_ci uvcb_attest->arcb_addr = (u64)arcb; 9562306a36Sopenharmony_ci uvcb_attest->cont_token = 0; 9662306a36Sopenharmony_ci uvcb_attest->user_data_len = uvio_attest->user_data_len; 9762306a36Sopenharmony_ci memcpy(uvcb_attest->user_data, uvio_attest->user_data, sizeof(uvcb_attest->user_data)); 9862306a36Sopenharmony_ci uvcb_attest->meas_len = uvio_attest->meas_len; 9962306a36Sopenharmony_ci uvcb_attest->meas_addr = (u64)meas; 10062306a36Sopenharmony_ci uvcb_attest->add_data_len = uvio_attest->add_data_len; 10162306a36Sopenharmony_ci uvcb_attest->add_data_addr = (u64)add_data; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int uvio_copy_attest_result_to_user(struct uv_cb_attest *uvcb_attest, 10762306a36Sopenharmony_ci struct uvio_ioctl_cb *uv_ioctl, 10862306a36Sopenharmony_ci u8 *measurement, u8 *add_data, 10962306a36Sopenharmony_ci struct uvio_attest *uvio_attest) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct uvio_attest __user *user_uvio_attest = (void __user *)uv_ioctl->argument_addr; 11262306a36Sopenharmony_ci void __user *user_buf_add = (void __user *)uvio_attest->add_data_addr; 11362306a36Sopenharmony_ci void __user *user_buf_meas = (void __user *)uvio_attest->meas_addr; 11462306a36Sopenharmony_ci void __user *user_buf_uid = &user_uvio_attest->config_uid; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (copy_to_user(user_buf_meas, measurement, uvio_attest->meas_len)) 11762306a36Sopenharmony_ci return -EFAULT; 11862306a36Sopenharmony_ci if (add_data && copy_to_user(user_buf_add, add_data, uvio_attest->add_data_len)) 11962306a36Sopenharmony_ci return -EFAULT; 12062306a36Sopenharmony_ci if (copy_to_user(user_buf_uid, uvcb_attest->config_uid, sizeof(uvcb_attest->config_uid))) 12162306a36Sopenharmony_ci return -EFAULT; 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int get_uvio_attest(struct uvio_ioctl_cb *uv_ioctl, struct uvio_attest *uvio_attest) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci u8 __user *user_arg_buf = (u8 __user *)uv_ioctl->argument_addr; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (copy_from_user(uvio_attest, user_arg_buf, sizeof(*uvio_attest))) 13062306a36Sopenharmony_ci return -EFAULT; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (uvio_attest->arcb_len > UVIO_ATT_ARCB_MAX_LEN) 13362306a36Sopenharmony_ci return -EINVAL; 13462306a36Sopenharmony_ci if (uvio_attest->arcb_len == 0) 13562306a36Sopenharmony_ci return -EINVAL; 13662306a36Sopenharmony_ci if (uvio_attest->meas_len > UVIO_ATT_MEASUREMENT_MAX_LEN) 13762306a36Sopenharmony_ci return -EINVAL; 13862306a36Sopenharmony_ci if (uvio_attest->meas_len == 0) 13962306a36Sopenharmony_ci return -EINVAL; 14062306a36Sopenharmony_ci if (uvio_attest->add_data_len > UVIO_ATT_ADDITIONAL_MAX_LEN) 14162306a36Sopenharmony_ci return -EINVAL; 14262306a36Sopenharmony_ci if (uvio_attest->reserved136) 14362306a36Sopenharmony_ci return -EINVAL; 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/** 14862306a36Sopenharmony_ci * uvio_attestation() - Perform a Retrieve Attestation Measurement UVC. 14962306a36Sopenharmony_ci * 15062306a36Sopenharmony_ci * @uv_ioctl: ioctl control block 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * uvio_attestation() does a Retrieve Attestation Measurement Ultravisor Call. 15362306a36Sopenharmony_ci * It verifies that the given userspace addresses are valid and request sizes 15462306a36Sopenharmony_ci * are sane. Every other check is made by the Ultravisor (UV) and won't result 15562306a36Sopenharmony_ci * in a negative return value. It copies the input to kernelspace, builds the 15662306a36Sopenharmony_ci * request, sends the UV-call, and copies the result to userspace. 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * The Attestation Request has two input and two outputs. 15962306a36Sopenharmony_ci * ARCB and User Data are inputs for the UV generated by userspace. 16062306a36Sopenharmony_ci * Measurement and Additional Data are outputs for userspace generated by UV. 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * The Attestation Request Control Block (ARCB) is a cryptographically verified 16362306a36Sopenharmony_ci * and secured request to UV and User Data is some plaintext data which is 16462306a36Sopenharmony_ci * going to be included in the Attestation Measurement calculation. 16562306a36Sopenharmony_ci * 16662306a36Sopenharmony_ci * Measurement is a cryptographic measurement of the callers properties, 16762306a36Sopenharmony_ci * optional data configured by the ARCB and the user data. If specified by the 16862306a36Sopenharmony_ci * ARCB, UV will add some Additional Data to the measurement calculation. 16962306a36Sopenharmony_ci * This Additional Data is then returned as well. 17062306a36Sopenharmony_ci * 17162306a36Sopenharmony_ci * If the Retrieve Attestation Measurement UV facility is not present, 17262306a36Sopenharmony_ci * UV will return invalid command rc. This won't be fenced in the driver 17362306a36Sopenharmony_ci * and does not result in a negative return value. 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci * Context: might sleep 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * Return: 0 on success or a negative error code on error. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistatic int uvio_attestation(struct uvio_ioctl_cb *uv_ioctl) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct uv_cb_attest *uvcb_attest = NULL; 18262306a36Sopenharmony_ci struct uvio_attest *uvio_attest = NULL; 18362306a36Sopenharmony_ci u8 *measurement = NULL; 18462306a36Sopenharmony_ci u8 *add_data = NULL; 18562306a36Sopenharmony_ci u8 *arcb = NULL; 18662306a36Sopenharmony_ci int ret; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ret = -EINVAL; 18962306a36Sopenharmony_ci if (uv_ioctl->argument_len != sizeof(*uvio_attest)) 19062306a36Sopenharmony_ci goto out; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci ret = -ENOMEM; 19362306a36Sopenharmony_ci uvio_attest = kzalloc(sizeof(*uvio_attest), GFP_KERNEL); 19462306a36Sopenharmony_ci if (!uvio_attest) 19562306a36Sopenharmony_ci goto out; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci ret = get_uvio_attest(uv_ioctl, uvio_attest); 19862306a36Sopenharmony_ci if (ret) 19962306a36Sopenharmony_ci goto out; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci ret = -ENOMEM; 20262306a36Sopenharmony_ci arcb = kvzalloc(uvio_attest->arcb_len, GFP_KERNEL); 20362306a36Sopenharmony_ci measurement = kvzalloc(uvio_attest->meas_len, GFP_KERNEL); 20462306a36Sopenharmony_ci if (!arcb || !measurement) 20562306a36Sopenharmony_ci goto out; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (uvio_attest->add_data_len) { 20862306a36Sopenharmony_ci add_data = kvzalloc(uvio_attest->add_data_len, GFP_KERNEL); 20962306a36Sopenharmony_ci if (!add_data) 21062306a36Sopenharmony_ci goto out; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci uvcb_attest = kzalloc(sizeof(*uvcb_attest), GFP_KERNEL); 21462306a36Sopenharmony_ci if (!uvcb_attest) 21562306a36Sopenharmony_ci goto out; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ret = uvio_build_uvcb_attest(uvcb_attest, arcb, measurement, add_data, uvio_attest); 21862306a36Sopenharmony_ci if (ret) 21962306a36Sopenharmony_ci goto out; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci uv_call_sched(0, (u64)uvcb_attest); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci uv_ioctl->uv_rc = uvcb_attest->header.rc; 22462306a36Sopenharmony_ci uv_ioctl->uv_rrc = uvcb_attest->header.rrc; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ret = uvio_copy_attest_result_to_user(uvcb_attest, uv_ioctl, measurement, add_data, 22762306a36Sopenharmony_ci uvio_attest); 22862306a36Sopenharmony_ciout: 22962306a36Sopenharmony_ci kvfree(arcb); 23062306a36Sopenharmony_ci kvfree(measurement); 23162306a36Sopenharmony_ci kvfree(add_data); 23262306a36Sopenharmony_ci kfree(uvio_attest); 23362306a36Sopenharmony_ci kfree(uvcb_attest); 23462306a36Sopenharmony_ci return ret; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/** uvio_add_secret() - perform an Add Secret UVC 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * @uv_ioctl: ioctl control block 24062306a36Sopenharmony_ci * 24162306a36Sopenharmony_ci * uvio_add_secret() performs the Add Secret Ultravisor Call. 24262306a36Sopenharmony_ci * 24362306a36Sopenharmony_ci * The given userspace argument address and size are verified to be 24462306a36Sopenharmony_ci * valid but every other check is made by the Ultravisor 24562306a36Sopenharmony_ci * (UV). Therefore UV errors won't result in a negative return 24662306a36Sopenharmony_ci * value. The request is then copied to kernelspace, the UV-call is 24762306a36Sopenharmony_ci * performed and the results are copied back to userspace. 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * The argument has to point to an Add Secret Request Control Block 25062306a36Sopenharmony_ci * which is an encrypted and cryptographically verified request that 25162306a36Sopenharmony_ci * inserts a protected guest's secrets into the Ultravisor for later 25262306a36Sopenharmony_ci * use. 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * If the Add Secret UV facility is not present, UV will return 25562306a36Sopenharmony_ci * invalid command rc. This won't be fenced in the driver and does not 25662306a36Sopenharmony_ci * result in a negative return value. 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * Context: might sleep 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * Return: 0 on success or a negative error code on error. 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_cistatic int uvio_add_secret(struct uvio_ioctl_cb *uv_ioctl) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr; 26562306a36Sopenharmony_ci struct uv_cb_guest_addr uvcb = { 26662306a36Sopenharmony_ci .header.len = sizeof(uvcb), 26762306a36Sopenharmony_ci .header.cmd = UVC_CMD_ADD_SECRET, 26862306a36Sopenharmony_ci }; 26962306a36Sopenharmony_ci void *asrcb = NULL; 27062306a36Sopenharmony_ci int ret; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (uv_ioctl->argument_len > UVIO_ADD_SECRET_MAX_LEN) 27362306a36Sopenharmony_ci return -EINVAL; 27462306a36Sopenharmony_ci if (uv_ioctl->argument_len == 0) 27562306a36Sopenharmony_ci return -EINVAL; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci asrcb = kvzalloc(uv_ioctl->argument_len, GFP_KERNEL); 27862306a36Sopenharmony_ci if (!asrcb) 27962306a36Sopenharmony_ci return -ENOMEM; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ret = -EFAULT; 28262306a36Sopenharmony_ci if (copy_from_user(asrcb, user_buf_arg, uv_ioctl->argument_len)) 28362306a36Sopenharmony_ci goto out; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci ret = 0; 28662306a36Sopenharmony_ci uvcb.addr = (u64)asrcb; 28762306a36Sopenharmony_ci uv_call_sched(0, (u64)&uvcb); 28862306a36Sopenharmony_ci uv_ioctl->uv_rc = uvcb.header.rc; 28962306a36Sopenharmony_ci uv_ioctl->uv_rrc = uvcb.header.rrc; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ciout: 29262306a36Sopenharmony_ci kvfree(asrcb); 29362306a36Sopenharmony_ci return ret; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci/** uvio_list_secrets() - perform a List Secret UVC 29762306a36Sopenharmony_ci * @uv_ioctl: ioctl control block 29862306a36Sopenharmony_ci * 29962306a36Sopenharmony_ci * uvio_list_secrets() performs the List Secret Ultravisor Call. It verifies 30062306a36Sopenharmony_ci * that the given userspace argument address is valid and its size is sane. 30162306a36Sopenharmony_ci * Every other check is made by the Ultravisor (UV) and won't result in a 30262306a36Sopenharmony_ci * negative return value. It builds the request, performs the UV-call, and 30362306a36Sopenharmony_ci * copies the result to userspace. 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * The argument specifies the location for the result of the UV-Call. 30662306a36Sopenharmony_ci * 30762306a36Sopenharmony_ci * If the List Secrets UV facility is not present, UV will return invalid 30862306a36Sopenharmony_ci * command rc. This won't be fenced in the driver and does not result in a 30962306a36Sopenharmony_ci * negative return value. 31062306a36Sopenharmony_ci * 31162306a36Sopenharmony_ci * Context: might sleep 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * Return: 0 on success or a negative error code on error. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_cistatic int uvio_list_secrets(struct uvio_ioctl_cb *uv_ioctl) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr; 31862306a36Sopenharmony_ci struct uv_cb_guest_addr uvcb = { 31962306a36Sopenharmony_ci .header.len = sizeof(uvcb), 32062306a36Sopenharmony_ci .header.cmd = UVC_CMD_LIST_SECRETS, 32162306a36Sopenharmony_ci }; 32262306a36Sopenharmony_ci void *secrets = NULL; 32362306a36Sopenharmony_ci int ret = 0; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (uv_ioctl->argument_len != UVIO_LIST_SECRETS_LEN) 32662306a36Sopenharmony_ci return -EINVAL; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci secrets = kvzalloc(UVIO_LIST_SECRETS_LEN, GFP_KERNEL); 32962306a36Sopenharmony_ci if (!secrets) 33062306a36Sopenharmony_ci return -ENOMEM; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci uvcb.addr = (u64)secrets; 33362306a36Sopenharmony_ci uv_call_sched(0, (u64)&uvcb); 33462306a36Sopenharmony_ci uv_ioctl->uv_rc = uvcb.header.rc; 33562306a36Sopenharmony_ci uv_ioctl->uv_rrc = uvcb.header.rrc; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (copy_to_user(user_buf_arg, secrets, UVIO_LIST_SECRETS_LEN)) 33862306a36Sopenharmony_ci ret = -EFAULT; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci kvfree(secrets); 34162306a36Sopenharmony_ci return ret; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/** uvio_lock_secrets() - perform a Lock Secret Store UVC 34562306a36Sopenharmony_ci * @uv_ioctl: ioctl control block 34662306a36Sopenharmony_ci * 34762306a36Sopenharmony_ci * uvio_lock_secrets() performs the Lock Secret Store Ultravisor Call. It 34862306a36Sopenharmony_ci * performs the UV-call and copies the return codes to the ioctl control block. 34962306a36Sopenharmony_ci * After this call was dispatched successfully every following Add Secret UVC 35062306a36Sopenharmony_ci * and Lock Secrets UVC will fail with return code 0x102. 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * The argument address and size must be 0. 35362306a36Sopenharmony_ci * 35462306a36Sopenharmony_ci * If the Lock Secrets UV facility is not present, UV will return invalid 35562306a36Sopenharmony_ci * command rc. This won't be fenced in the driver and does not result in a 35662306a36Sopenharmony_ci * negative return value. 35762306a36Sopenharmony_ci * 35862306a36Sopenharmony_ci * Context: might sleep 35962306a36Sopenharmony_ci * 36062306a36Sopenharmony_ci * Return: 0 on success or a negative error code on error. 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_cistatic int uvio_lock_secrets(struct uvio_ioctl_cb *ioctl) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct uv_cb_nodata uvcb = { 36562306a36Sopenharmony_ci .header.len = sizeof(uvcb), 36662306a36Sopenharmony_ci .header.cmd = UVC_CMD_LOCK_SECRETS, 36762306a36Sopenharmony_ci }; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (ioctl->argument_addr || ioctl->argument_len) 37062306a36Sopenharmony_ci return -EINVAL; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci uv_call(0, (u64)&uvcb); 37362306a36Sopenharmony_ci ioctl->uv_rc = uvcb.header.rc; 37462306a36Sopenharmony_ci ioctl->uv_rrc = uvcb.header.rrc; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return 0; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp, 38062306a36Sopenharmony_ci unsigned long cmd) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci u8 nr = _IOC_NR(cmd); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE)) 38562306a36Sopenharmony_ci return -ENOIOCTLCMD; 38662306a36Sopenharmony_ci if (_IOC_TYPE(cmd) != UVIO_TYPE_UVC) 38762306a36Sopenharmony_ci return -ENOIOCTLCMD; 38862306a36Sopenharmony_ci if (nr >= UVIO_IOCTL_NUM_IOCTLS) 38962306a36Sopenharmony_ci return -ENOIOCTLCMD; 39062306a36Sopenharmony_ci if (_IOC_SIZE(cmd) != sizeof(*ioctl)) 39162306a36Sopenharmony_ci return -ENOIOCTLCMD; 39262306a36Sopenharmony_ci if (copy_from_user(ioctl, argp, sizeof(*ioctl))) 39362306a36Sopenharmony_ci return -EFAULT; 39462306a36Sopenharmony_ci if (ioctl->flags != 0) 39562306a36Sopenharmony_ci return -EINVAL; 39662306a36Sopenharmony_ci if (memchr_inv(ioctl->reserved14, 0, sizeof(ioctl->reserved14))) 39762306a36Sopenharmony_ci return -EINVAL; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return nr; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci/* 40362306a36Sopenharmony_ci * IOCTL entry point for the Ultravisor device. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_cistatic long uvio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 40862306a36Sopenharmony_ci struct uvio_ioctl_cb uv_ioctl = { }; 40962306a36Sopenharmony_ci long ret; 41062306a36Sopenharmony_ci int nr; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci nr = uvio_copy_and_check_ioctl(&uv_ioctl, argp, cmd); 41362306a36Sopenharmony_ci if (nr < 0) 41462306a36Sopenharmony_ci return nr; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci switch (nr) { 41762306a36Sopenharmony_ci case UVIO_IOCTL_UVDEV_INFO_NR: 41862306a36Sopenharmony_ci ret = uvio_uvdev_info(&uv_ioctl); 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci case UVIO_IOCTL_ATT_NR: 42162306a36Sopenharmony_ci ret = uvio_attestation(&uv_ioctl); 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci case UVIO_IOCTL_ADD_SECRET_NR: 42462306a36Sopenharmony_ci ret = uvio_add_secret(&uv_ioctl); 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci case UVIO_IOCTL_LIST_SECRETS_NR: 42762306a36Sopenharmony_ci ret = uvio_list_secrets(&uv_ioctl); 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci case UVIO_IOCTL_LOCK_SECRETS_NR: 43062306a36Sopenharmony_ci ret = uvio_lock_secrets(&uv_ioctl); 43162306a36Sopenharmony_ci break; 43262306a36Sopenharmony_ci default: 43362306a36Sopenharmony_ci ret = -ENOIOCTLCMD; 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci if (ret) 43762306a36Sopenharmony_ci return ret; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (copy_to_user(argp, &uv_ioctl, sizeof(uv_ioctl))) 44062306a36Sopenharmony_ci ret = -EFAULT; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return ret; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic const struct file_operations uvio_dev_fops = { 44662306a36Sopenharmony_ci .owner = THIS_MODULE, 44762306a36Sopenharmony_ci .unlocked_ioctl = uvio_ioctl, 44862306a36Sopenharmony_ci .llseek = no_llseek, 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic struct miscdevice uvio_dev_miscdev = { 45262306a36Sopenharmony_ci .minor = MISC_DYNAMIC_MINOR, 45362306a36Sopenharmony_ci .name = UVIO_DEVICE_NAME, 45462306a36Sopenharmony_ci .fops = &uvio_dev_fops, 45562306a36Sopenharmony_ci}; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic void __exit uvio_dev_exit(void) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci misc_deregister(&uvio_dev_miscdev); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int __init uvio_dev_init(void) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci set_supp_uv_cmds((unsigned long *)&uvdev_info.supp_uv_cmds); 46562306a36Sopenharmony_ci return misc_register(&uvio_dev_miscdev); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cimodule_cpu_feature_match(S390_CPU_FEATURE_UV, uvio_dev_init); 46962306a36Sopenharmony_cimodule_exit(uvio_dev_exit); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ciMODULE_AUTHOR("IBM Corporation"); 47262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 47362306a36Sopenharmony_ciMODULE_DESCRIPTION("Ultravisor UAPI driver"); 474