cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

secvar-sysfs.c (4995B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright (C) 2019 IBM Corporation <nayna@linux.ibm.com>
      4 *
      5 * This code exposes secure variables to user via sysfs
      6 */
      7
      8#define pr_fmt(fmt) "secvar-sysfs: "fmt
      9
     10#include <linux/slab.h>
     11#include <linux/compat.h>
     12#include <linux/string.h>
     13#include <linux/of.h>
     14#include <asm/secvar.h>
     15
     16#define NAME_MAX_SIZE	   1024
     17
     18static struct kobject *secvar_kobj;
     19static struct kset *secvar_kset;
     20
     21static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
     22			   char *buf)
     23{
     24	ssize_t rc = 0;
     25	struct device_node *node;
     26	const char *format;
     27
     28	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
     29	if (!of_device_is_available(node)) {
     30		rc = -ENODEV;
     31		goto out;
     32	}
     33
     34	rc = of_property_read_string(node, "format", &format);
     35	if (rc)
     36		goto out;
     37
     38	rc = sprintf(buf, "%s\n", format);
     39
     40out:
     41	of_node_put(node);
     42
     43	return rc;
     44}
     45
     46
     47static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
     48			 char *buf)
     49{
     50	uint64_t dsize;
     51	int rc;
     52
     53	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
     54	if (rc) {
     55		pr_err("Error retrieving %s variable size %d\n", kobj->name,
     56		       rc);
     57		return rc;
     58	}
     59
     60	return sprintf(buf, "%llu\n", dsize);
     61}
     62
     63static ssize_t data_read(struct file *filep, struct kobject *kobj,
     64			 struct bin_attribute *attr, char *buf, loff_t off,
     65			 size_t count)
     66{
     67	uint64_t dsize;
     68	char *data;
     69	int rc;
     70
     71	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
     72	if (rc) {
     73		pr_err("Error getting %s variable size %d\n", kobj->name, rc);
     74		return rc;
     75	}
     76	pr_debug("dsize is %llu\n", dsize);
     77
     78	data = kzalloc(dsize, GFP_KERNEL);
     79	if (!data)
     80		return -ENOMEM;
     81
     82	rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, data, &dsize);
     83	if (rc) {
     84		pr_err("Error getting %s variable %d\n", kobj->name, rc);
     85		goto data_fail;
     86	}
     87
     88	rc = memory_read_from_buffer(buf, count, &off, data, dsize);
     89
     90data_fail:
     91	kfree(data);
     92	return rc;
     93}
     94
     95static ssize_t update_write(struct file *filep, struct kobject *kobj,
     96			    struct bin_attribute *attr, char *buf, loff_t off,
     97			    size_t count)
     98{
     99	int rc;
    100
    101	pr_debug("count is %ld\n", count);
    102	rc = secvar_ops->set(kobj->name, strlen(kobj->name) + 1, buf, count);
    103	if (rc) {
    104		pr_err("Error setting the %s variable %d\n", kobj->name, rc);
    105		return rc;
    106	}
    107
    108	return count;
    109}
    110
    111static struct kobj_attribute format_attr = __ATTR_RO(format);
    112
    113static struct kobj_attribute size_attr = __ATTR_RO(size);
    114
    115static struct bin_attribute data_attr = __BIN_ATTR_RO(data, 0);
    116
    117static struct bin_attribute update_attr = __BIN_ATTR_WO(update, 0);
    118
    119static struct bin_attribute *secvar_bin_attrs[] = {
    120	&data_attr,
    121	&update_attr,
    122	NULL,
    123};
    124
    125static struct attribute *secvar_attrs[] = {
    126	&size_attr.attr,
    127	NULL,
    128};
    129
    130static const struct attribute_group secvar_attr_group = {
    131	.attrs = secvar_attrs,
    132	.bin_attrs = secvar_bin_attrs,
    133};
    134__ATTRIBUTE_GROUPS(secvar_attr);
    135
    136static struct kobj_type secvar_ktype = {
    137	.sysfs_ops	= &kobj_sysfs_ops,
    138	.default_groups = secvar_attr_groups,
    139};
    140
    141static int update_kobj_size(void)
    142{
    143
    144	struct device_node *node;
    145	u64 varsize;
    146	int rc = 0;
    147
    148	node = of_find_compatible_node(NULL, NULL, "ibm,secvar-backend");
    149	if (!of_device_is_available(node)) {
    150		rc = -ENODEV;
    151		goto out;
    152	}
    153
    154	rc = of_property_read_u64(node, "max-var-size", &varsize);
    155	if (rc)
    156		goto out;
    157
    158	data_attr.size = varsize;
    159	update_attr.size = varsize;
    160
    161out:
    162	of_node_put(node);
    163
    164	return rc;
    165}
    166
    167static int secvar_sysfs_load(void)
    168{
    169	char *name;
    170	uint64_t namesize = 0;
    171	struct kobject *kobj;
    172	int rc;
    173
    174	name = kzalloc(NAME_MAX_SIZE, GFP_KERNEL);
    175	if (!name)
    176		return -ENOMEM;
    177
    178	do {
    179		rc = secvar_ops->get_next(name, &namesize, NAME_MAX_SIZE);
    180		if (rc) {
    181			if (rc != -ENOENT)
    182				pr_err("error getting secvar from firmware %d\n",
    183				       rc);
    184			break;
    185		}
    186
    187		kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
    188		if (!kobj) {
    189			rc = -ENOMEM;
    190			break;
    191		}
    192
    193		kobject_init(kobj, &secvar_ktype);
    194
    195		rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
    196		if (rc) {
    197			pr_warn("kobject_add error %d for attribute: %s\n", rc,
    198				name);
    199			kobject_put(kobj);
    200			kobj = NULL;
    201		}
    202
    203		if (kobj)
    204			kobject_uevent(kobj, KOBJ_ADD);
    205
    206	} while (!rc);
    207
    208	kfree(name);
    209	return rc;
    210}
    211
    212static int secvar_sysfs_init(void)
    213{
    214	int rc;
    215
    216	if (!secvar_ops) {
    217		pr_warn("secvar: failed to retrieve secvar operations.\n");
    218		return -ENODEV;
    219	}
    220
    221	secvar_kobj = kobject_create_and_add("secvar", firmware_kobj);
    222	if (!secvar_kobj) {
    223		pr_err("secvar: Failed to create firmware kobj\n");
    224		return -ENOMEM;
    225	}
    226
    227	rc = sysfs_create_file(secvar_kobj, &format_attr.attr);
    228	if (rc) {
    229		kobject_put(secvar_kobj);
    230		return -ENOMEM;
    231	}
    232
    233	secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
    234	if (!secvar_kset) {
    235		pr_err("secvar: sysfs kobject registration failed.\n");
    236		kobject_put(secvar_kobj);
    237		return -ENOMEM;
    238	}
    239
    240	rc = update_kobj_size();
    241	if (rc) {
    242		pr_err("Cannot read the size of the attribute\n");
    243		return rc;
    244	}
    245
    246	secvar_sysfs_load();
    247
    248	return 0;
    249}
    250
    251late_initcall(secvar_sysfs_init);