]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/uv: Provide host-key hashes in sysfs
authorSteffen Eiden <seiden@linux.ibm.com>
Wed, 23 Oct 2024 07:55:28 +0000 (09:55 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Tue, 29 Oct 2024 10:17:16 +0000 (11:17 +0100)
Utilize the new Query Ultravisor Keys UVC to give user space the
information which host-keys are installed on the system.

Create a new sysfs directory 'firmware/uv/keys' that contains the hash
of the host-key and the backup host-key of that system. Additionally,
the file 'all' contains the response from the UVC possibly containing
more key-hashes than currently known.

Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Link: https://lore.kernel.org/r/20241023075529.2561384-1-seiden@linux.ibm.com
Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
arch/s390/include/asm/uv.h
arch/s390/kernel/uv.c

index 153d93468b77c0331605bbe418c99d920e049372..cce2568cfaddb49cccea47f083f56361148ec514 100644 (file)
@@ -31,6 +31,7 @@
 #define UVC_RC_NEED_DESTROY    0x8000
 
 #define UVC_CMD_QUI                    0x0001
+#define UVC_CMD_QUERY_KEYS             0x0002
 #define UVC_CMD_INIT_UV                        0x000f
 #define UVC_CMD_CREATE_SEC_CONF                0x0100
 #define UVC_CMD_DESTROY_SEC_CONF       0x0101
@@ -94,6 +95,7 @@ enum uv_cmds_inst {
        BIT_UVC_CMD_ADD_SECRET = 29,
        BIT_UVC_CMD_LIST_SECRETS = 30,
        BIT_UVC_CMD_LOCK_SECRETS = 31,
+       BIT_UVC_CMD_QUERY_KEYS = 34,
 };
 
 enum uv_feat_ind {
@@ -145,6 +147,21 @@ struct uv_cb_qui {
        u8 reserved112[0x120 - 0x112];          /* 0x0112 */
 } __packed __aligned(8);
 
+struct uv_key_hash {
+       u64 dword[4];
+} __packed __aligned(8);
+
+#define UVC_QUERY_KEYS_IDX_HK          0
+#define UVC_QUERY_KEYS_IDX_BACK_HK     1
+
+/* Query Ultravisor Keys */
+struct uv_cb_query_keys {
+       struct uv_cb_header header;             /* 0x0000 */
+       u64 reserved08[3];                      /* 0x0008 */
+       struct uv_key_hash key_hashes[15];      /* 0x0020 */
+} __packed __aligned(8);
+static_assert(sizeof(struct uv_cb_query_keys) == 0x200);
+
 /* Initialize Ultravisor */
 struct uv_cb_init {
        struct uv_cb_header header;
index ba514b9dca6ae2ca376cf8a6639601b017dfc524..3c74e6179cdca1d711b0f9458aa704d56d0b1505 100644 (file)
@@ -722,10 +722,76 @@ static struct attribute *uv_query_attrs[] = {
        NULL,
 };
 
+static inline struct uv_cb_query_keys uv_query_keys(void)
+{
+       struct uv_cb_query_keys uvcb = {
+               .header.cmd = UVC_CMD_QUERY_KEYS,
+               .header.len = sizeof(uvcb)
+       };
+
+       uv_call(0, (uint64_t)&uvcb);
+       return uvcb;
+}
+
+static inline ssize_t emit_hash(struct uv_key_hash *hash, char *buf, int at)
+{
+       return sysfs_emit_at(buf, at, "%016llx%016llx%016llx%016llx\n",
+                           hash->dword[0], hash->dword[1], hash->dword[2], hash->dword[3]);
+}
+
+static ssize_t uv_keys_host_key(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *buf)
+{
+       struct uv_cb_query_keys uvcb = uv_query_keys();
+
+       return emit_hash(&uvcb.key_hashes[UVC_QUERY_KEYS_IDX_HK], buf, 0);
+}
+
+static struct kobj_attribute uv_keys_host_key_attr =
+       __ATTR(host_key, 0444, uv_keys_host_key, NULL);
+
+static ssize_t uv_keys_backup_host_key(struct kobject *kobj,
+                                      struct kobj_attribute *attr, char *buf)
+{
+       struct uv_cb_query_keys uvcb = uv_query_keys();
+
+       return emit_hash(&uvcb.key_hashes[UVC_QUERY_KEYS_IDX_BACK_HK], buf, 0);
+}
+
+static struct kobj_attribute uv_keys_backup_host_key_attr =
+       __ATTR(backup_host_key, 0444, uv_keys_backup_host_key, NULL);
+
+static ssize_t uv_keys_all(struct kobject *kobj,
+                          struct kobj_attribute *attr, char *buf)
+{
+       struct uv_cb_query_keys uvcb = uv_query_keys();
+       ssize_t len = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(uvcb.key_hashes); i++)
+               len += emit_hash(uvcb.key_hashes + i, buf, len);
+
+       return len;
+}
+
+static struct kobj_attribute uv_keys_all_attr =
+       __ATTR(all, 0444, uv_keys_all, NULL);
+
 static struct attribute_group uv_query_attr_group = {
        .attrs = uv_query_attrs,
 };
 
+static struct attribute *uv_keys_attrs[] = {
+       &uv_keys_host_key_attr.attr,
+       &uv_keys_backup_host_key_attr.attr,
+       &uv_keys_all_attr.attr,
+       NULL,
+};
+
+static struct attribute_group uv_keys_attr_group = {
+       .attrs = uv_keys_attrs,
+};
+
 static ssize_t uv_is_prot_virt_guest(struct kobject *kobj,
                                     struct kobj_attribute *attr, char *buf)
 {
@@ -751,6 +817,7 @@ static const struct attribute *uv_prot_virt_attrs[] = {
 };
 
 static struct kset *uv_query_kset;
+static struct kset *uv_keys_kset;
 static struct kobject *uv_kobj;
 
 static int __init uv_sysfs_dir_init(const struct attribute_group *grp,
@@ -789,6 +856,10 @@ static int __init uv_sysfs_init(void)
        if (rc)
                goto out_ind_files;
 
+       /* Get installed key hashes if available, ignore any errors */
+       if (test_bit_inv(BIT_UVC_CMD_QUERY_KEYS, uv_info.inst_calls_list))
+               uv_sysfs_dir_init(&uv_keys_attr_group, &uv_keys_kset, "keys");
+
        return 0;
 
 out_ind_files: