secvar-sysfs.c 5.8 KB

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