From ea9d97163523d299022fc78258eccc466d92102a Mon Sep 17 00:00:00 2001 From: Steffen Eiden Date: Thu, 15 Jun 2023 12:05:28 +0200 Subject: s390/uvdevice: Add info IOCTL Add an IOCTL that allows userspace to find out which IOCTLs the uvdevice supports without trial and error. Explicitly expose the IOCTL nr for the request types. Signed-off-by: Steffen Eiden Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20230615100533.3996107-3-seiden@linux.ibm.com Signed-off-by: Janosch Frank Message-Id: <20230615100533.3996107-3-seiden@linux.ibm.com> --- drivers/s390/char/Kconfig | 2 +- drivers/s390/char/uvdevice.c | 77 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 8 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 80c4e5101c97..8a03af5ee5b3 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -96,7 +96,7 @@ config SCLP_OFB config S390_UV_UAPI def_tristate m prompt "Ultravisor userspace API" - depends on S390 + depends on S390 && (KVM || PROTECTED_VIRTUALIZATION_GUEST) help Selecting exposes parts of the UV interface to userspace by providing a misc character device at /dev/uv. diff --git a/drivers/s390/char/uvdevice.c b/drivers/s390/char/uvdevice.c index 1d40457c7b10..7d7866be389b 100644 --- a/drivers/s390/char/uvdevice.c +++ b/drivers/s390/char/uvdevice.c @@ -32,6 +32,52 @@ #include #include +#define BIT_UVIO_INTERNAL U32_MAX +/* Mapping from IOCTL-nr to UVC-bit */ +static const u32 ioctl_nr_to_uvc_bit[] __initconst = { + [UVIO_IOCTL_UVDEV_INFO_NR] = BIT_UVIO_INTERNAL, + [UVIO_IOCTL_ATT_NR] = BIT_UVC_CMD_RETR_ATTEST, +}; + +static_assert(ARRAY_SIZE(ioctl_nr_to_uvc_bit) == UVIO_IOCTL_NUM_IOCTLS); + +static struct uvio_uvdev_info uvdev_info = { + .supp_uvio_cmds = GENMASK_ULL(UVIO_IOCTL_NUM_IOCTLS - 1, 0), +}; + +static void __init set_supp_uv_cmds(unsigned long *supp_uv_cmds) +{ + int i; + + for (i = 0; i < UVIO_IOCTL_NUM_IOCTLS; i++) { + if (ioctl_nr_to_uvc_bit[i] == BIT_UVIO_INTERNAL) + continue; + if (!test_bit_inv(ioctl_nr_to_uvc_bit[i], uv_info.inst_calls_list)) + continue; + __set_bit(i, supp_uv_cmds); + } +} + +/** + * uvio_uvdev_info() - get information about the uvdevice + * + * @uv_ioctl: ioctl control block + * + * Lists all IOCTLs that are supported by this uvdevice + */ +static int uvio_uvdev_info(struct uvio_ioctl_cb *uv_ioctl) +{ + void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr; + + if (uv_ioctl->argument_len < sizeof(uvdev_info)) + return -EINVAL; + if (copy_to_user(user_buf_arg, &uvdev_info, sizeof(uvdev_info))) + return -EFAULT; + + uv_ioctl->uv_rc = UVC_RC_EXECUTED; + return 0; +} + static int uvio_build_uvcb_attest(struct uv_cb_attest *uvcb_attest, u8 *arcb, u8 *meas, u8 *add_data, struct uvio_attest *uvio_attest) { @@ -185,8 +231,19 @@ out: return ret; } -static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp) +static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp, + unsigned long cmd) { + u8 nr = _IOC_NR(cmd); + + if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE)) + return -ENOIOCTLCMD; + if (_IOC_TYPE(cmd) != UVIO_TYPE_UVC) + return -ENOIOCTLCMD; + if (nr >= UVIO_IOCTL_NUM_IOCTLS) + return -ENOIOCTLCMD; + if (_IOC_SIZE(cmd) != sizeof(*ioctl)) + return -ENOIOCTLCMD; if (copy_from_user(ioctl, argp, sizeof(*ioctl))) return -EFAULT; if (ioctl->flags != 0) @@ -194,7 +251,7 @@ static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *a if (memchr_inv(ioctl->reserved14, 0, sizeof(ioctl->reserved14))) return -EINVAL; - return 0; + return nr; } /* @@ -205,12 +262,17 @@ static long uvio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) void __user *argp = (void __user *)arg; struct uvio_ioctl_cb uv_ioctl = { }; long ret; + int nr; + + nr = uvio_copy_and_check_ioctl(&uv_ioctl, argp, cmd); + if (nr < 0) + return nr; - switch (cmd) { - case UVIO_IOCTL_ATT: - ret = uvio_copy_and_check_ioctl(&uv_ioctl, argp); - if (ret) - return ret; + switch (nr) { + case UVIO_IOCTL_UVDEV_INFO_NR: + ret = uvio_uvdev_info(&uv_ioctl); + break; + case UVIO_IOCTL_ATT_NR: ret = uvio_attestation(&uv_ioctl); break; default: @@ -245,6 +307,7 @@ static void __exit uvio_dev_exit(void) static int __init uvio_dev_init(void) { + set_supp_uv_cmds((unsigned long *)&uvdev_info.supp_uv_cmds); return misc_register(&uvio_dev_miscdev); } -- cgit v1.2.3 From 44567ca21aaf6f60cb5dcde180b1f6aab9da33dd Mon Sep 17 00:00:00 2001 From: Steffen Eiden Date: Thu, 15 Jun 2023 12:05:29 +0200 Subject: s390/uvdevice: Add 'Add Secret' UVC Userspace can call the Add Secret Ultravisor Call using IOCTLs on the uvdevice. The Add Secret UV call sends an encrypted and cryptographically verified request to the Ultravisor. The request inserts a protected guest's secret into the Ultravisor for later use. The uvdevice is merely transporting the request from userspace to the Ultravisor. It's neither checking nor manipulating the request data. Signed-off-by: Steffen Eiden Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20230615100533.3996107-4-seiden@linux.ibm.com Signed-off-by: Janosch Frank Message-Id: <20230615100533.3996107-4-seiden@linux.ibm.com> --- arch/s390/include/asm/uv.h | 14 ++++++++ arch/s390/include/uapi/asm/uvdevice.h | 4 +++ drivers/s390/char/uvdevice.c | 63 +++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index 28a9ad57b6f1..1babc70ea5d4 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -58,6 +58,7 @@ #define UVC_CMD_SET_SHARED_ACCESS 0x1000 #define UVC_CMD_REMOVE_SHARED_ACCESS 0x1001 #define UVC_CMD_RETR_ATTEST 0x1020 +#define UVC_CMD_ADD_SECRET 0x1031 /* Bits in installed uv calls */ enum uv_cmds_inst { @@ -88,6 +89,7 @@ enum uv_cmds_inst { BIT_UVC_CMD_DUMP_CPU = 26, BIT_UVC_CMD_DUMP_COMPLETE = 27, BIT_UVC_CMD_RETR_ATTEST = 28, + BIT_UVC_CMD_ADD_SECRET = 29, }; enum uv_feat_ind { @@ -292,6 +294,18 @@ struct uv_cb_dump_complete { u64 reserved30[5]; } __packed __aligned(8); +/* + * A common UV call struct for pv guests that contains a single address + * Examples: + * Add Secret + */ +struct uv_cb_guest_addr { + struct uv_cb_header header; + u64 reserved08[3]; + u64 addr; + u64 reserved28[4]; +} __packed __aligned(8); + static inline int __uv_call(unsigned long r1, unsigned long r2) { int cc; diff --git a/arch/s390/include/uapi/asm/uvdevice.h b/arch/s390/include/uapi/asm/uvdevice.h index 9d9b684836c2..e77410226598 100644 --- a/arch/s390/include/uapi/asm/uvdevice.h +++ b/arch/s390/include/uapi/asm/uvdevice.h @@ -69,6 +69,7 @@ struct uvio_uvdev_info { #define UVIO_ATT_ARCB_MAX_LEN 0x100000 #define UVIO_ATT_MEASUREMENT_MAX_LEN 0x8000 #define UVIO_ATT_ADDITIONAL_MAX_LEN 0x8000 +#define UVIO_ADD_SECRET_MAX_LEN 0x100000 #define UVIO_DEVICE_NAME "uv" #define UVIO_TYPE_UVC 'u' @@ -76,6 +77,7 @@ struct uvio_uvdev_info { enum UVIO_IOCTL_NR { UVIO_IOCTL_UVDEV_INFO_NR = 0x00, UVIO_IOCTL_ATT_NR, + UVIO_IOCTL_ADD_SECRET_NR, /* must be the last entry */ UVIO_IOCTL_NUM_IOCTLS }; @@ -83,9 +85,11 @@ enum UVIO_IOCTL_NR { #define UVIO_IOCTL(nr) _IOWR(UVIO_TYPE_UVC, nr, struct uvio_ioctl_cb) #define UVIO_IOCTL_UVDEV_INFO UVIO_IOCTL(UVIO_IOCTL_UVDEV_INFO_NR) #define UVIO_IOCTL_ATT UVIO_IOCTL(UVIO_IOCTL_ATT_NR) +#define UVIO_IOCTL_ADD_SECRET UVIO_IOCTL(UVIO_IOCTL_ADD_SECRET_NR) #define UVIO_SUPP_CALL(nr) (1ULL << (nr)) #define UVIO_SUPP_UDEV_INFO UVIO_SUPP_CALL(UVIO_IOCTL_UDEV_INFO_NR) #define UVIO_SUPP_ATT UVIO_SUPP_CALL(UVIO_IOCTL_ATT_NR) +#define UVIO_SUPP_ADD_SECRET UVIO_SUPP_CALL(UVIO_IOCTL_ADD_SECRET_NR) #endif /* __S390_ASM_UVDEVICE_H */ diff --git a/drivers/s390/char/uvdevice.c b/drivers/s390/char/uvdevice.c index 7d7866be389b..7221e987703a 100644 --- a/drivers/s390/char/uvdevice.c +++ b/drivers/s390/char/uvdevice.c @@ -37,6 +37,7 @@ static const u32 ioctl_nr_to_uvc_bit[] __initconst = { [UVIO_IOCTL_UVDEV_INFO_NR] = BIT_UVIO_INTERNAL, [UVIO_IOCTL_ATT_NR] = BIT_UVC_CMD_RETR_ATTEST, + [UVIO_IOCTL_ADD_SECRET_NR] = BIT_UVC_CMD_ADD_SECRET, }; static_assert(ARRAY_SIZE(ioctl_nr_to_uvc_bit) == UVIO_IOCTL_NUM_IOCTLS); @@ -231,6 +232,65 @@ out: return ret; } +/** uvio_add_secret() - perform an Add Secret UVC + * + * @uv_ioctl: ioctl control block + * + * uvio_add_secret() performs the Add Secret Ultravisor Call. + * + * The given userspace argument address and size are verified to be + * valid but every other check is made by the Ultravisor + * (UV). Therefore UV errors won't result in a negative return + * value. The request is then copied to kernelspace, the UV-call is + * performed and the results are copied back to userspace. + * + * The argument has to point to an Add Secret Request Control Block + * which is an encrypted and cryptographically verified request that + * inserts a protected guest's secrets into the Ultravisor for later + * use. + * + * If the Add Secret UV facility is not present, UV will return + * invalid command rc. This won't be fenced in the driver and does not + * result in a negative return value. + * + * Context: might sleep + * + * Return: 0 on success or a negative error code on error. + */ +static int uvio_add_secret(struct uvio_ioctl_cb *uv_ioctl) +{ + void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr; + struct uv_cb_guest_addr uvcb = { + .header.len = sizeof(uvcb), + .header.cmd = UVC_CMD_ADD_SECRET, + }; + void *asrcb = NULL; + int ret; + + if (uv_ioctl->argument_len > UVIO_ADD_SECRET_MAX_LEN) + return -EINVAL; + if (uv_ioctl->argument_len == 0) + return -EINVAL; + + asrcb = kvzalloc(uv_ioctl->argument_len, GFP_KERNEL); + if (!asrcb) + return -ENOMEM; + + ret = -EFAULT; + if (copy_from_user(asrcb, user_buf_arg, uv_ioctl->argument_len)) + goto out; + + ret = 0; + uvcb.addr = (u64)asrcb; + uv_call_sched(0, (u64)&uvcb); + uv_ioctl->uv_rc = uvcb.header.rc; + uv_ioctl->uv_rrc = uvcb.header.rrc; + +out: + kvfree(asrcb); + return ret; +} + static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp, unsigned long cmd) { @@ -275,6 +335,9 @@ static long uvio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case UVIO_IOCTL_ATT_NR: ret = uvio_attestation(&uv_ioctl); break; + case UVIO_IOCTL_ADD_SECRET_NR: + ret = uvio_add_secret(&uv_ioctl); + break; default: ret = -ENOIOCTLCMD; break; -- cgit v1.2.3 From b96b3ce2720145bd981988443288fbc4bdf37854 Mon Sep 17 00:00:00 2001 From: Steffen Eiden Date: Thu, 15 Jun 2023 12:05:30 +0200 Subject: s390/uvdevice: Add 'List Secrets' UVC Userspace can call the List Secrets Ultravisor Call using IOCTLs on the uvdevice. The List Secrets UV call lists the identifier of the secrets in the UV secret store. The uvdevice is merely transporting the request from userspace to Ultravisor. It's neither checking nor manipulating the request or response data. Signed-off-by: Steffen Eiden Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20230615100533.3996107-5-seiden@linux.ibm.com Signed-off-by: Janosch Frank Message-Id: <20230615100533.3996107-5-seiden@linux.ibm.com> --- arch/s390/include/asm/uv.h | 3 ++ arch/s390/include/uapi/asm/uvdevice.h | 4 +++ drivers/s390/char/uvdevice.c | 52 +++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index 1babc70ea5d4..3739c8f6a129 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -59,6 +59,7 @@ #define UVC_CMD_REMOVE_SHARED_ACCESS 0x1001 #define UVC_CMD_RETR_ATTEST 0x1020 #define UVC_CMD_ADD_SECRET 0x1031 +#define UVC_CMD_LIST_SECRETS 0x1033 /* Bits in installed uv calls */ enum uv_cmds_inst { @@ -90,6 +91,7 @@ enum uv_cmds_inst { BIT_UVC_CMD_DUMP_COMPLETE = 27, BIT_UVC_CMD_RETR_ATTEST = 28, BIT_UVC_CMD_ADD_SECRET = 29, + BIT_UVC_CMD_LIST_SECRETS = 30, }; enum uv_feat_ind { @@ -298,6 +300,7 @@ struct uv_cb_dump_complete { * A common UV call struct for pv guests that contains a single address * Examples: * Add Secret + * List Secrets */ struct uv_cb_guest_addr { struct uv_cb_header header; diff --git a/arch/s390/include/uapi/asm/uvdevice.h b/arch/s390/include/uapi/asm/uvdevice.h index e77410226598..76045da44868 100644 --- a/arch/s390/include/uapi/asm/uvdevice.h +++ b/arch/s390/include/uapi/asm/uvdevice.h @@ -70,6 +70,7 @@ struct uvio_uvdev_info { #define UVIO_ATT_MEASUREMENT_MAX_LEN 0x8000 #define UVIO_ATT_ADDITIONAL_MAX_LEN 0x8000 #define UVIO_ADD_SECRET_MAX_LEN 0x100000 +#define UVIO_LIST_SECRETS_LEN 0x1000 #define UVIO_DEVICE_NAME "uv" #define UVIO_TYPE_UVC 'u' @@ -78,6 +79,7 @@ enum UVIO_IOCTL_NR { UVIO_IOCTL_UVDEV_INFO_NR = 0x00, UVIO_IOCTL_ATT_NR, UVIO_IOCTL_ADD_SECRET_NR, + UVIO_IOCTL_LIST_SECRETS_NR, /* must be the last entry */ UVIO_IOCTL_NUM_IOCTLS }; @@ -86,10 +88,12 @@ enum UVIO_IOCTL_NR { #define UVIO_IOCTL_UVDEV_INFO UVIO_IOCTL(UVIO_IOCTL_UVDEV_INFO_NR) #define UVIO_IOCTL_ATT UVIO_IOCTL(UVIO_IOCTL_ATT_NR) #define UVIO_IOCTL_ADD_SECRET UVIO_IOCTL(UVIO_IOCTL_ADD_SECRET_NR) +#define UVIO_IOCTL_LIST_SECRETS UVIO_IOCTL(UVIO_IOCTL_LIST_SECRETS_NR) #define UVIO_SUPP_CALL(nr) (1ULL << (nr)) #define UVIO_SUPP_UDEV_INFO UVIO_SUPP_CALL(UVIO_IOCTL_UDEV_INFO_NR) #define UVIO_SUPP_ATT UVIO_SUPP_CALL(UVIO_IOCTL_ATT_NR) #define UVIO_SUPP_ADD_SECRET UVIO_SUPP_CALL(UVIO_IOCTL_ADD_SECRET_NR) +#define UVIO_SUPP_LIST_SECRETS UVIO_SUPP_CALL(UVIO_IOCTL_LIST_SECRETS_NR) #endif /* __S390_ASM_UVDEVICE_H */ diff --git a/drivers/s390/char/uvdevice.c b/drivers/s390/char/uvdevice.c index 7221e987703a..70502c4ec290 100644 --- a/drivers/s390/char/uvdevice.c +++ b/drivers/s390/char/uvdevice.c @@ -38,6 +38,7 @@ static const u32 ioctl_nr_to_uvc_bit[] __initconst = { [UVIO_IOCTL_UVDEV_INFO_NR] = BIT_UVIO_INTERNAL, [UVIO_IOCTL_ATT_NR] = BIT_UVC_CMD_RETR_ATTEST, [UVIO_IOCTL_ADD_SECRET_NR] = BIT_UVC_CMD_ADD_SECRET, + [UVIO_IOCTL_LIST_SECRETS_NR] = BIT_UVC_CMD_LIST_SECRETS, }; static_assert(ARRAY_SIZE(ioctl_nr_to_uvc_bit) == UVIO_IOCTL_NUM_IOCTLS); @@ -291,6 +292,54 @@ out: return ret; } +/** uvio_list_secrets() - perform a List Secret UVC + * @uv_ioctl: ioctl control block + * + * uvio_list_secrets() performs the List Secret Ultravisor Call. It verifies + * that the given userspace argument address is valid and its size is sane. + * Every other check is made by the Ultravisor (UV) and won't result in a + * negative return value. It builds the request, performs the UV-call, and + * copies the result to userspace. + * + * The argument specifies the location for the result of the UV-Call. + * + * If the List Secrets UV facility is not present, UV will return invalid + * command rc. This won't be fenced in the driver and does not result in a + * negative return value. + * + * Context: might sleep + * + * Return: 0 on success or a negative error code on error. + */ +static int uvio_list_secrets(struct uvio_ioctl_cb *uv_ioctl) +{ + void __user *user_buf_arg = (void __user *)uv_ioctl->argument_addr; + struct uv_cb_guest_addr uvcb = { + .header.len = sizeof(uvcb), + .header.cmd = UVC_CMD_LIST_SECRETS, + }; + void *secrets = NULL; + int ret = 0; + + if (uv_ioctl->argument_len != UVIO_LIST_SECRETS_LEN) + return -EINVAL; + + secrets = kvzalloc(UVIO_LIST_SECRETS_LEN, GFP_KERNEL); + if (!secrets) + return -ENOMEM; + + uvcb.addr = (u64)secrets; + uv_call_sched(0, (u64)&uvcb); + uv_ioctl->uv_rc = uvcb.header.rc; + uv_ioctl->uv_rrc = uvcb.header.rrc; + + if (copy_to_user(user_buf_arg, secrets, UVIO_LIST_SECRETS_LEN)) + ret = -EFAULT; + + kvfree(secrets); + return ret; +} + static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp, unsigned long cmd) { @@ -338,6 +387,9 @@ static long uvio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case UVIO_IOCTL_ADD_SECRET_NR: ret = uvio_add_secret(&uv_ioctl); break; + case UVIO_IOCTL_LIST_SECRETS_NR: + ret = uvio_list_secrets(&uv_ioctl); + break; default: ret = -ENOIOCTLCMD; break; -- cgit v1.2.3 From 2d8a26acaf88a9174bcd44b607c5aa2ca9f5718f Mon Sep 17 00:00:00 2001 From: Steffen Eiden Date: Thu, 15 Jun 2023 12:05:31 +0200 Subject: s390/uvdevice: Add 'Lock Secret Store' UVC Userspace can call the Lock Secret Store Ultravisor Call using IOCTLs on the uvdevice. The Lock Secret Store UV call disables all additions of secrets for the future. The uvdevice is merely transporting the request from userspace to the Ultravisor. Signed-off-by: Steffen Eiden Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20230615100533.3996107-6-seiden@linux.ibm.com Signed-off-by: Janosch Frank Message-Id: <20230615100533.3996107-6-seiden@linux.ibm.com> --- arch/s390/include/asm/uv.h | 2 ++ arch/s390/include/uapi/asm/uvdevice.h | 3 +++ drivers/s390/char/uvdevice.c | 39 +++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) (limited to 'drivers/s390') diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index 3739c8f6a129..3203ffbdde6b 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -60,6 +60,7 @@ #define UVC_CMD_RETR_ATTEST 0x1020 #define UVC_CMD_ADD_SECRET 0x1031 #define UVC_CMD_LIST_SECRETS 0x1033 +#define UVC_CMD_LOCK_SECRETS 0x1034 /* Bits in installed uv calls */ enum uv_cmds_inst { @@ -92,6 +93,7 @@ enum uv_cmds_inst { BIT_UVC_CMD_RETR_ATTEST = 28, BIT_UVC_CMD_ADD_SECRET = 29, BIT_UVC_CMD_LIST_SECRETS = 30, + BIT_UVC_CMD_LOCK_SECRETS = 31, }; enum uv_feat_ind { diff --git a/arch/s390/include/uapi/asm/uvdevice.h b/arch/s390/include/uapi/asm/uvdevice.h index 76045da44868..b9c2f14a6af3 100644 --- a/arch/s390/include/uapi/asm/uvdevice.h +++ b/arch/s390/include/uapi/asm/uvdevice.h @@ -80,6 +80,7 @@ enum UVIO_IOCTL_NR { UVIO_IOCTL_ATT_NR, UVIO_IOCTL_ADD_SECRET_NR, UVIO_IOCTL_LIST_SECRETS_NR, + UVIO_IOCTL_LOCK_SECRETS_NR, /* must be the last entry */ UVIO_IOCTL_NUM_IOCTLS }; @@ -89,11 +90,13 @@ enum UVIO_IOCTL_NR { #define UVIO_IOCTL_ATT UVIO_IOCTL(UVIO_IOCTL_ATT_NR) #define UVIO_IOCTL_ADD_SECRET UVIO_IOCTL(UVIO_IOCTL_ADD_SECRET_NR) #define UVIO_IOCTL_LIST_SECRETS UVIO_IOCTL(UVIO_IOCTL_LIST_SECRETS_NR) +#define UVIO_IOCTL_LOCK_SECRETS UVIO_IOCTL(UVIO_IOCTL_LOCK_SECRETS_NR) #define UVIO_SUPP_CALL(nr) (1ULL << (nr)) #define UVIO_SUPP_UDEV_INFO UVIO_SUPP_CALL(UVIO_IOCTL_UDEV_INFO_NR) #define UVIO_SUPP_ATT UVIO_SUPP_CALL(UVIO_IOCTL_ATT_NR) #define UVIO_SUPP_ADD_SECRET UVIO_SUPP_CALL(UVIO_IOCTL_ADD_SECRET_NR) #define UVIO_SUPP_LIST_SECRETS UVIO_SUPP_CALL(UVIO_IOCTL_LIST_SECRETS_NR) +#define UVIO_SUPP_LOCK_SECRETS UVIO_SUPP_CALL(UVIO_IOCTL_LOCK_SECRETS_NR) #endif /* __S390_ASM_UVDEVICE_H */ diff --git a/drivers/s390/char/uvdevice.c b/drivers/s390/char/uvdevice.c index 70502c4ec290..144cd2e03590 100644 --- a/drivers/s390/char/uvdevice.c +++ b/drivers/s390/char/uvdevice.c @@ -39,6 +39,7 @@ static const u32 ioctl_nr_to_uvc_bit[] __initconst = { [UVIO_IOCTL_ATT_NR] = BIT_UVC_CMD_RETR_ATTEST, [UVIO_IOCTL_ADD_SECRET_NR] = BIT_UVC_CMD_ADD_SECRET, [UVIO_IOCTL_LIST_SECRETS_NR] = BIT_UVC_CMD_LIST_SECRETS, + [UVIO_IOCTL_LOCK_SECRETS_NR] = BIT_UVC_CMD_LOCK_SECRETS, }; static_assert(ARRAY_SIZE(ioctl_nr_to_uvc_bit) == UVIO_IOCTL_NUM_IOCTLS); @@ -340,6 +341,41 @@ static int uvio_list_secrets(struct uvio_ioctl_cb *uv_ioctl) return ret; } +/** uvio_lock_secrets() - perform a Lock Secret Store UVC + * @uv_ioctl: ioctl control block + * + * uvio_lock_secrets() performs the Lock Secret Store Ultravisor Call. It + * performs the UV-call and copies the return codes to the ioctl control block. + * After this call was dispatched successfully every following Add Secret UVC + * and Lock Secrets UVC will fail with return code 0x102. + * + * The argument address and size must be 0. + * + * If the Lock Secrets UV facility is not present, UV will return invalid + * command rc. This won't be fenced in the driver and does not result in a + * negative return value. + * + * Context: might sleep + * + * Return: 0 on success or a negative error code on error. + */ +static int uvio_lock_secrets(struct uvio_ioctl_cb *ioctl) +{ + struct uv_cb_nodata uvcb = { + .header.len = sizeof(uvcb), + .header.cmd = UVC_CMD_LOCK_SECRETS, + }; + + if (ioctl->argument_addr || ioctl->argument_len) + return -EINVAL; + + uv_call(0, (u64)&uvcb); + ioctl->uv_rc = uvcb.header.rc; + ioctl->uv_rrc = uvcb.header.rrc; + + return 0; +} + static int uvio_copy_and_check_ioctl(struct uvio_ioctl_cb *ioctl, void __user *argp, unsigned long cmd) { @@ -390,6 +426,9 @@ static long uvio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case UVIO_IOCTL_LIST_SECRETS_NR: ret = uvio_list_secrets(&uv_ioctl); break; + case UVIO_IOCTL_LOCK_SECRETS_NR: + ret = uvio_lock_secrets(&uv_ioctl); + break; default: ret = -ENOIOCTLCMD; break; -- cgit v1.2.3