~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kernel/secvar-sysfs.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 18 static struct kobject *secvar_kobj;
 19 static struct kset *secvar_kset;
 20 
 21 static ssize_t format_show(struct kobject *kobj, struct kobj_attribute *attr,
 22                            char *buf)
 23 {
 24         char tmp[32];
 25         ssize_t len = secvar_ops->format(tmp, sizeof(tmp));
 26 
 27         if (len > 0)
 28                 return sysfs_emit(buf, "%s\n", tmp);
 29         else if (len < 0)
 30                 pr_err("Error %zd reading format string\n", len);
 31         else
 32                 pr_err("Got empty format string from backend\n");
 33 
 34         return -EIO;
 35 }
 36 
 37 
 38 static ssize_t size_show(struct kobject *kobj, struct kobj_attribute *attr,
 39                          char *buf)
 40 {
 41         u64 dsize;
 42         int rc;
 43 
 44         rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
 45         if (rc) {
 46                 if (rc != -ENOENT)
 47                         pr_err("Error retrieving %s variable size %d\n", kobj->name, rc);
 48                 return rc;
 49         }
 50 
 51         return sysfs_emit(buf, "%llu\n", dsize);
 52 }
 53 
 54 static ssize_t data_read(struct file *filep, struct kobject *kobj,
 55                          struct bin_attribute *attr, char *buf, loff_t off,
 56                          size_t count)
 57 {
 58         char *data;
 59         u64 dsize;
 60         int rc;
 61 
 62         rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, NULL, &dsize);
 63         if (rc) {
 64                 if (rc != -ENOENT)
 65                         pr_err("Error getting %s variable size %d\n", kobj->name, rc);
 66                 return rc;
 67         }
 68         pr_debug("dsize is %llu\n", dsize);
 69 
 70         data = kzalloc(dsize, GFP_KERNEL);
 71         if (!data)
 72                 return -ENOMEM;
 73 
 74         rc = secvar_ops->get(kobj->name, strlen(kobj->name) + 1, data, &dsize);
 75         if (rc) {
 76                 pr_err("Error getting %s variable %d\n", kobj->name, rc);
 77                 goto data_fail;
 78         }
 79 
 80         rc = memory_read_from_buffer(buf, count, &off, data, dsize);
 81 
 82 data_fail:
 83         kfree(data);
 84         return rc;
 85 }
 86 
 87 static ssize_t update_write(struct file *filep, struct kobject *kobj,
 88                             struct bin_attribute *attr, char *buf, loff_t off,
 89                             size_t count)
 90 {
 91         int rc;
 92 
 93         pr_debug("count is %ld\n", count);
 94         rc = secvar_ops->set(kobj->name, strlen(kobj->name) + 1, buf, count);
 95         if (rc) {
 96                 pr_err("Error setting the %s variable %d\n", kobj->name, rc);
 97                 return rc;
 98         }
 99 
100         return count;
101 }
102 
103 static struct kobj_attribute format_attr = __ATTR_RO(format);
104 
105 static struct kobj_attribute size_attr = __ATTR_RO(size);
106 
107 static struct bin_attribute data_attr = __BIN_ATTR_RO(data, 0);
108 
109 static struct bin_attribute update_attr = __BIN_ATTR_WO(update, 0);
110 
111 static struct bin_attribute *secvar_bin_attrs[] = {
112         &data_attr,
113         &update_attr,
114         NULL,
115 };
116 
117 static struct attribute *secvar_attrs[] = {
118         &size_attr.attr,
119         NULL,
120 };
121 
122 static const struct attribute_group secvar_attr_group = {
123         .attrs = secvar_attrs,
124         .bin_attrs = secvar_bin_attrs,
125 };
126 __ATTRIBUTE_GROUPS(secvar_attr);
127 
128 static struct kobj_type secvar_ktype = {
129         .sysfs_ops      = &kobj_sysfs_ops,
130         .default_groups = secvar_attr_groups,
131 };
132 
133 static int update_kobj_size(void)
134 {
135 
136         u64 varsize;
137         int rc = secvar_ops->max_size(&varsize);
138 
139         if (rc)
140                 return rc;
141 
142         data_attr.size = varsize;
143         update_attr.size = varsize;
144 
145         return 0;
146 }
147 
148 static int secvar_sysfs_config(struct kobject *kobj)
149 {
150         struct attribute_group config_group = {
151                 .name = "config",
152                 .attrs = (struct attribute **)secvar_ops->config_attrs,
153         };
154 
155         if (secvar_ops->config_attrs)
156                 return sysfs_create_group(kobj, &config_group);
157 
158         return 0;
159 }
160 
161 static int add_var(const char *name)
162 {
163         struct kobject *kobj;
164         int rc;
165 
166         kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
167         if (!kobj)
168                 return -ENOMEM;
169 
170         kobject_init(kobj, &secvar_ktype);
171 
172         rc = kobject_add(kobj, &secvar_kset->kobj, "%s", name);
173         if (rc) {
174                 pr_warn("kobject_add error %d for attribute: %s\n", rc,
175                         name);
176                 kobject_put(kobj);
177                 return rc;
178         }
179 
180         kobject_uevent(kobj, KOBJ_ADD);
181         return 0;
182 }
183 
184 static int secvar_sysfs_load(void)
185 {
186         u64 namesize = 0;
187         char *name;
188         int rc;
189 
190         name = kzalloc(NAME_MAX_SIZE, GFP_KERNEL);
191         if (!name)
192                 return -ENOMEM;
193 
194         do {
195                 rc = secvar_ops->get_next(name, &namesize, NAME_MAX_SIZE);
196                 if (rc) {
197                         if (rc != -ENOENT)
198                                 pr_err("error getting secvar from firmware %d\n", rc);
199                         else
200                                 rc = 0;
201 
202                         break;
203                 }
204 
205                 rc = add_var(name);
206         } while (!rc);
207 
208         kfree(name);
209         return rc;
210 }
211 
212 static int secvar_sysfs_load_static(void)
213 {
214         const char * const *name_ptr = secvar_ops->var_names;
215         int rc;
216 
217         while (*name_ptr) {
218                 rc = add_var(*name_ptr);
219                 if (rc)
220                         return rc;
221                 name_ptr++;
222         }
223 
224         return 0;
225 }
226 
227 static int secvar_sysfs_init(void)
228 {
229         u64 max_size;
230         int rc;
231 
232         if (!secvar_ops) {
233                 pr_warn("Failed to retrieve secvar operations\n");
234                 return -ENODEV;
235         }
236 
237         secvar_kobj = kobject_create_and_add("secvar", firmware_kobj);
238         if (!secvar_kobj) {
239                 pr_err("Failed to create firmware kobj\n");
240                 return -ENOMEM;
241         }
242 
243         rc = sysfs_create_file(secvar_kobj, &format_attr.attr);
244         if (rc) {
245                 pr_err("Failed to create format object\n");
246                 rc = -ENOMEM;
247                 goto err;
248         }
249 
250         secvar_kset = kset_create_and_add("vars", NULL, secvar_kobj);
251         if (!secvar_kset) {
252                 pr_err("sysfs kobject registration failed\n");
253                 rc = -ENOMEM;
254                 goto err;
255         }
256 
257         rc = update_kobj_size();
258         if (rc) {
259                 pr_err("Cannot read the size of the attribute\n");
260                 goto err;
261         }
262 
263         rc = secvar_sysfs_config(secvar_kobj);
264         if (rc) {
265                 pr_err("Failed to create config directory\n");
266                 goto err;
267         }
268 
269         if (secvar_ops->get_next)
270                 rc = secvar_sysfs_load();
271         else
272                 rc = secvar_sysfs_load_static();
273 
274         if (rc) {
275                 pr_err("Failed to create variable attributes\n");
276                 goto err;
277         }
278 
279         // Due to sysfs limitations, we will only ever get a write buffer of
280         // up to 1 page in size. Print a warning if this is potentially going
281         // to cause problems, so that the user is aware.
282         secvar_ops->max_size(&max_size);
283         if (max_size > PAGE_SIZE)
284                 pr_warn_ratelimited("PAGE_SIZE (%lu) is smaller than maximum object size (%llu), writes are limited to PAGE_SIZE\n",
285                                     PAGE_SIZE, max_size);
286 
287         return 0;
288 err:
289         kobject_put(secvar_kobj);
290         return rc;
291 }
292 
293 late_initcall(secvar_sysfs_init);
294 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php