Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (C) 2019 IBM Corporation <nayna@linux.ibm.com>
0004  *
0005  * This code exposes secure variables to user via sysfs
0006  */
0007 
0008 #define pr_fmt(fmt) "secvar-sysfs: "fmt
0009 
0010 #include <linux/slab.h>
0011 #include <linux/compat.h>
0012 #include <linux/string.h>
0013 #include <linux/of.h>
0014 #include <asm/secvar.h>
0015 
0016 #define NAME_MAX_SIZE      1024
0017 
0018 static struct kobject *secvar_kobj;
0019 static struct kset *secvar_kset;
0020 
0021 static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
0022                char *buf)
0023 {
0024     ssize_t rc = 0;
0025     struct device_node *node;
0026     const char *format;
0027 
0028     node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
0029     if (!of_device_is_available(node)) {
0030         rc = -ENODEV;
0031         goto out;
0032     }
0033 
0034     rc = of_property_read_string(node, "format", &format);
0035     if (rc)
0036         goto out;
0037 
0038     rc = sprintf(buf, "%s\n", format);
0039 
0040 out:
0041     of_node_put(node);
0042 
0043     return rc;
0044 }
0045 
0046 
0047 static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
0048              char *buf)
0049 {
0050     uint64_t dsize;
0051     int rc;
0052 
0053     rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
0054     if (rc) {
0055         pr_err("Error retrieving %s variable size %d\n", kobj->name,
0056                rc);
0057         return rc;
0058     }
0059 
0060     return sprintf(buf, "%llu\n", dsize);
0061 }
0062 
0063 static ssize_t data_read(struct file *filep, struct kobject *kobj,
0064              struct bin_attribute *attr, char *buf, loff_t off,
0065              size_t count)
0066 {
0067     uint64_t dsize;
0068     char *data;
0069     int rc;
0070 
0071     rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
0072     if (rc) {
0073         pr_err("Error getting %s variable size %d\n", kobj->name, rc);
0074         return rc;
0075     }
0076     pr_debug("dsize is %llu\n", dsize);
0077 
0078     data = kzalloc(dsize, GFP_KERNEL);
0079     if (!data)
0080         return -ENOMEM;
0081 
0082     rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, data, &dsize);
0083     if (rc) {
0084         pr_err("Error getting %s variable %d\n", kobj->name, rc);
0085         goto data_fail;
0086     }
0087 
0088     rc = memory_read_from_buffer(buf, count, &off, data, dsize);
0089 
0090 data_fail:
0091     kfree(data);
0092     return rc;
0093 }
0094 
0095 static ssize_t update_write(struct file *filep, struct kobject *kobj,
0096                 struct bin_attribute *attr, char *buf, loff_t off,
0097                 size_t count)
0098 {
0099     int rc;
0100 
0101     pr_debug("count is %ld\n", count);
0102     rc = secvar_ops->set(kobj->name, strlen(kobj->name) + 1, buf, count);
0103     if (rc) {
0104         pr_err("Error setting the %s variable %d\n", kobj->name, rc);
0105         return rc;
0106     }
0107 
0108     return count;
0109 }
0110 
0111 static struct kobj_attribute format_attr = __ATTR_RO(format);
0112 
0113 static struct kobj_attribute size_attr = __ATTR_RO(size);
0114 
0115 static struct bin_attribute data_attr = __BIN_ATTR_RO(data, 0);
0116 
0117 static struct bin_attribute update_attr = __BIN_ATTR_WO(update, 0);
0118 
0119 static struct bin_attribute *secvar_bin_attrs[] = {
0120     &data_attr,
0121     &update_attr,
0122     NULL,
0123 };
0124 
0125 static struct attribute *secvar_attrs[] = {
0126     &size_attr.attr,
0127     NULL,
0128 };
0129 
0130 static const struct attribute_group secvar_attr_group = {
0131     .attrs = secvar_attrs,
0132     .bin_attrs = secvar_bin_attrs,
0133 };
0134 __ATTRIBUTE_GROUPS(secvar_attr);
0135 
0136 static struct kobj_type secvar_ktype = {
0137     .sysfs_ops  = &kobj_sysfs_ops,
0138     .default_groups = secvar_attr_groups,
0139 };
0140 
0141 static int update_kobj_size(void)
0142 {
0143 
0144     struct device_node *node;
0145     u64 varsize;
0146     int rc = 0;
0147 
0148     node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
0149     if (!of_device_is_available(node)) {
0150         rc = -ENODEV;
0151         goto out;
0152     }
0153 
0154     rc = of_property_read_u64(node, "max-var-size", &varsize);
0155     if (rc)
0156         goto out;
0157 
0158     data_attr.size = varsize;
0159     update_attr.size = varsize;
0160 
0161 out:
0162     of_node_put(node);
0163 
0164     return rc;
0165 }
0166 
0167 static int secvar_sysfs_load(void)
0168 {
0169     char *name;
0170     uint64_t namesize = 0;
0171     struct kobject *kobj;
0172     int rc;
0173 
0174     name = kzalloc(NAME_MAX_SIZE, GFP_KERNEL);
0175     if (!name)
0176         return -ENOMEM;
0177 
0178     do {
0179         rc = secvar_ops->get_next(name, &namesize, NAME_MAX_SIZE);
0180         if (rc) {
0181             if (rc != -ENOENT)
0182                 pr_err("error getting secvar from firmware %d\n",
0183                        rc);
0184             break;
0185         }
0186 
0187         kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
0188         if (!kobj) {
0189             rc = -ENOMEM;
0190             break;
0191         }
0192 
0193         kobject_init(kobj, &secvar_ktype);
0194 
0195         rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
0196         if (rc) {
0197             pr_warn("kobject_add error %d for attribute: %s\n", rc,
0198                 name);
0199             kobject_put(kobj);
0200             kobj = NULL;
0201         }
0202 
0203         if (kobj)
0204             kobject_uevent(kobj, KOBJ_ADD);
0205 
0206     } while (!rc);
0207 
0208     kfree(name);
0209     return rc;
0210 }
0211 
0212 static int secvar_sysfs_init(void)
0213 {
0214     int rc;
0215 
0216     if (!secvar_ops) {
0217         pr_warn("secvar: failed to retrieve secvar operations.\n");
0218         return -ENODEV;
0219     }
0220 
0221     secvar_kobj = kobject_create_and_add("secvar", firmware_kobj);
0222     if (!secvar_kobj) {
0223         pr_err("secvar: Failed to create firmware kobj\n");
0224         return -ENOMEM;
0225     }
0226 
0227     rc = sysfs_create_file(secvar_kobj, &format_attr.attr);
0228     if (rc) {
0229         kobject_put(secvar_kobj);
0230         return -ENOMEM;
0231     }
0232 
0233     secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
0234     if (!secvar_kset) {
0235         pr_err("secvar: sysfs kobject registration failed.\n");
0236         kobject_put(secvar_kobj);
0237         return -ENOMEM;
0238     }
0239 
0240     rc = update_kobj_size();
0241     if (rc) {
0242         pr_err("Cannot read the size of the attribute\n");
0243         return rc;
0244     }
0245 
0246     secvar_sysfs_load();
0247 
0248     return 0;
0249 }
0250 
0251 late_initcall(secvar_sysfs_init);