xref: /OK3568_Linux_fs/kernel/drivers/firmware/efi/efivars.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Originally from efivars.c,
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2001,2003,2004 Dell <Matt_Domsch@dell.com>
6*4882a593Smuzhiyun  * Copyright (C) 2004 Intel Corporation <matthew.e.tolentino@intel.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * This code takes all variables accessible from EFI runtime and
9*4882a593Smuzhiyun  *  exports them via sysfs
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/efi.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun #include <linux/ucs2_string.h>
16*4882a593Smuzhiyun #include <linux/compat.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #define EFIVARS_VERSION "0.08"
19*4882a593Smuzhiyun #define EFIVARS_DATE "2004-May-17"
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
22*4882a593Smuzhiyun MODULE_DESCRIPTION("sysfs interface to EFI Variables");
23*4882a593Smuzhiyun MODULE_LICENSE("GPL");
24*4882a593Smuzhiyun MODULE_VERSION(EFIVARS_VERSION);
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun static LIST_HEAD(efivar_sysfs_list);
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static struct kset *efivars_kset;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static struct bin_attribute *efivars_new_var;
31*4882a593Smuzhiyun static struct bin_attribute *efivars_del_var;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun struct compat_efi_variable {
34*4882a593Smuzhiyun 	efi_char16_t  VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
35*4882a593Smuzhiyun 	efi_guid_t    VendorGuid;
36*4882a593Smuzhiyun 	__u32         DataSize;
37*4882a593Smuzhiyun 	__u8          Data[1024];
38*4882a593Smuzhiyun 	__u32         Status;
39*4882a593Smuzhiyun 	__u32         Attributes;
40*4882a593Smuzhiyun } __packed;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun struct efivar_attribute {
43*4882a593Smuzhiyun 	struct attribute attr;
44*4882a593Smuzhiyun 	ssize_t (*show) (struct efivar_entry *entry, char *buf);
45*4882a593Smuzhiyun 	ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #define EFIVAR_ATTR(_name, _mode, _show, _store) \
49*4882a593Smuzhiyun struct efivar_attribute efivar_attr_##_name = { \
50*4882a593Smuzhiyun 	.attr = {.name = __stringify(_name), .mode = _mode}, \
51*4882a593Smuzhiyun 	.show = _show, \
52*4882a593Smuzhiyun 	.store = _store, \
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr)
56*4882a593Smuzhiyun #define to_efivar_entry(obj)  container_of(obj, struct efivar_entry, kobj)
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun  * Prototype for sysfs creation function
60*4882a593Smuzhiyun  */
61*4882a593Smuzhiyun static int
62*4882a593Smuzhiyun efivar_create_sysfs_entry(struct efivar_entry *new_var);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun static ssize_t
efivar_guid_read(struct efivar_entry * entry,char * buf)65*4882a593Smuzhiyun efivar_guid_read(struct efivar_entry *entry, char *buf)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	struct efi_variable *var = &entry->var;
68*4882a593Smuzhiyun 	char *str = buf;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	if (!entry || !buf)
71*4882a593Smuzhiyun 		return 0;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	efi_guid_to_str(&var->VendorGuid, str);
74*4882a593Smuzhiyun 	str += strlen(str);
75*4882a593Smuzhiyun 	str += sprintf(str, "\n");
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return str - buf;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun static ssize_t
efivar_attr_read(struct efivar_entry * entry,char * buf)81*4882a593Smuzhiyun efivar_attr_read(struct efivar_entry *entry, char *buf)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	struct efi_variable *var = &entry->var;
84*4882a593Smuzhiyun 	unsigned long size = sizeof(var->Data);
85*4882a593Smuzhiyun 	char *str = buf;
86*4882a593Smuzhiyun 	int ret;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	if (!entry || !buf)
89*4882a593Smuzhiyun 		return -EINVAL;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
92*4882a593Smuzhiyun 	var->DataSize = size;
93*4882a593Smuzhiyun 	if (ret)
94*4882a593Smuzhiyun 		return -EIO;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
97*4882a593Smuzhiyun 		str += sprintf(str, "EFI_VARIABLE_NON_VOLATILE\n");
98*4882a593Smuzhiyun 	if (var->Attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)
99*4882a593Smuzhiyun 		str += sprintf(str, "EFI_VARIABLE_BOOTSERVICE_ACCESS\n");
100*4882a593Smuzhiyun 	if (var->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)
101*4882a593Smuzhiyun 		str += sprintf(str, "EFI_VARIABLE_RUNTIME_ACCESS\n");
102*4882a593Smuzhiyun 	if (var->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD)
103*4882a593Smuzhiyun 		str += sprintf(str, "EFI_VARIABLE_HARDWARE_ERROR_RECORD\n");
104*4882a593Smuzhiyun 	if (var->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
105*4882a593Smuzhiyun 		str += sprintf(str,
106*4882a593Smuzhiyun 			"EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\n");
107*4882a593Smuzhiyun 	if (var->Attributes &
108*4882a593Smuzhiyun 			EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
109*4882a593Smuzhiyun 		str += sprintf(str,
110*4882a593Smuzhiyun 			"EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS\n");
111*4882a593Smuzhiyun 	if (var->Attributes & EFI_VARIABLE_APPEND_WRITE)
112*4882a593Smuzhiyun 		str += sprintf(str, "EFI_VARIABLE_APPEND_WRITE\n");
113*4882a593Smuzhiyun 	return str - buf;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun static ssize_t
efivar_size_read(struct efivar_entry * entry,char * buf)117*4882a593Smuzhiyun efivar_size_read(struct efivar_entry *entry, char *buf)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	struct efi_variable *var = &entry->var;
120*4882a593Smuzhiyun 	unsigned long size = sizeof(var->Data);
121*4882a593Smuzhiyun 	char *str = buf;
122*4882a593Smuzhiyun 	int ret;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	if (!entry || !buf)
125*4882a593Smuzhiyun 		return -EINVAL;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
128*4882a593Smuzhiyun 	var->DataSize = size;
129*4882a593Smuzhiyun 	if (ret)
130*4882a593Smuzhiyun 		return -EIO;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	str += sprintf(str, "0x%lx\n", var->DataSize);
133*4882a593Smuzhiyun 	return str - buf;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun static ssize_t
efivar_data_read(struct efivar_entry * entry,char * buf)137*4882a593Smuzhiyun efivar_data_read(struct efivar_entry *entry, char *buf)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	struct efi_variable *var = &entry->var;
140*4882a593Smuzhiyun 	unsigned long size = sizeof(var->Data);
141*4882a593Smuzhiyun 	int ret;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (!entry || !buf)
144*4882a593Smuzhiyun 		return -EINVAL;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
147*4882a593Smuzhiyun 	var->DataSize = size;
148*4882a593Smuzhiyun 	if (ret)
149*4882a593Smuzhiyun 		return -EIO;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	memcpy(buf, var->Data, var->DataSize);
152*4882a593Smuzhiyun 	return var->DataSize;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun static inline int
sanity_check(struct efi_variable * var,efi_char16_t * name,efi_guid_t vendor,unsigned long size,u32 attributes,u8 * data)156*4882a593Smuzhiyun sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
157*4882a593Smuzhiyun 	     unsigned long size, u32 attributes, u8 *data)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	/*
160*4882a593Smuzhiyun 	 * If only updating the variable data, then the name
161*4882a593Smuzhiyun 	 * and guid should remain the same
162*4882a593Smuzhiyun 	 */
163*4882a593Smuzhiyun 	if (memcmp(name, var->VariableName, sizeof(var->VariableName)) ||
164*4882a593Smuzhiyun 		efi_guidcmp(vendor, var->VendorGuid)) {
165*4882a593Smuzhiyun 		printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
166*4882a593Smuzhiyun 		return -EINVAL;
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	if ((size <= 0) || (attributes == 0)){
170*4882a593Smuzhiyun 		printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
171*4882a593Smuzhiyun 		return -EINVAL;
172*4882a593Smuzhiyun 	}
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
175*4882a593Smuzhiyun 	    efivar_validate(vendor, name, data, size) == false) {
176*4882a593Smuzhiyun 		printk(KERN_ERR "efivars: Malformed variable content\n");
177*4882a593Smuzhiyun 		return -EINVAL;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	return 0;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun static void
copy_out_compat(struct efi_variable * dst,struct compat_efi_variable * src)184*4882a593Smuzhiyun copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	memcpy(dst->VariableName, src->VariableName, EFI_VAR_NAME_LEN);
187*4882a593Smuzhiyun 	memcpy(dst->Data, src->Data, sizeof(src->Data));
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	dst->VendorGuid = src->VendorGuid;
190*4882a593Smuzhiyun 	dst->DataSize = src->DataSize;
191*4882a593Smuzhiyun 	dst->Attributes = src->Attributes;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun /*
195*4882a593Smuzhiyun  * We allow each variable to be edited via rewriting the
196*4882a593Smuzhiyun  * entire efi variable structure.
197*4882a593Smuzhiyun  */
198*4882a593Smuzhiyun static ssize_t
efivar_store_raw(struct efivar_entry * entry,const char * buf,size_t count)199*4882a593Smuzhiyun efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	struct efi_variable *new_var, *var = &entry->var;
202*4882a593Smuzhiyun 	efi_char16_t *name;
203*4882a593Smuzhiyun 	unsigned long size;
204*4882a593Smuzhiyun 	efi_guid_t vendor;
205*4882a593Smuzhiyun 	u32 attributes;
206*4882a593Smuzhiyun 	u8 *data;
207*4882a593Smuzhiyun 	int err;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	if (!entry || !buf)
210*4882a593Smuzhiyun 		return -EINVAL;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	if (in_compat_syscall()) {
213*4882a593Smuzhiyun 		struct compat_efi_variable *compat;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 		if (count != sizeof(*compat))
216*4882a593Smuzhiyun 			return -EINVAL;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 		compat = (struct compat_efi_variable *)buf;
219*4882a593Smuzhiyun 		attributes = compat->Attributes;
220*4882a593Smuzhiyun 		vendor = compat->VendorGuid;
221*4882a593Smuzhiyun 		name = compat->VariableName;
222*4882a593Smuzhiyun 		size = compat->DataSize;
223*4882a593Smuzhiyun 		data = compat->Data;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 		err = sanity_check(var, name, vendor, size, attributes, data);
226*4882a593Smuzhiyun 		if (err)
227*4882a593Smuzhiyun 			return err;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 		copy_out_compat(&entry->var, compat);
230*4882a593Smuzhiyun 	} else {
231*4882a593Smuzhiyun 		if (count != sizeof(struct efi_variable))
232*4882a593Smuzhiyun 			return -EINVAL;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 		new_var = (struct efi_variable *)buf;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 		attributes = new_var->Attributes;
237*4882a593Smuzhiyun 		vendor = new_var->VendorGuid;
238*4882a593Smuzhiyun 		name = new_var->VariableName;
239*4882a593Smuzhiyun 		size = new_var->DataSize;
240*4882a593Smuzhiyun 		data = new_var->Data;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 		err = sanity_check(var, name, vendor, size, attributes, data);
243*4882a593Smuzhiyun 		if (err)
244*4882a593Smuzhiyun 			return err;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 		memcpy(&entry->var, new_var, count);
247*4882a593Smuzhiyun 	}
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	err = efivar_entry_set(entry, attributes, size, data, NULL);
250*4882a593Smuzhiyun 	if (err) {
251*4882a593Smuzhiyun 		printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
252*4882a593Smuzhiyun 		return -EIO;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	return count;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun static ssize_t
efivar_show_raw(struct efivar_entry * entry,char * buf)259*4882a593Smuzhiyun efivar_show_raw(struct efivar_entry *entry, char *buf)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	struct efi_variable *var = &entry->var;
262*4882a593Smuzhiyun 	struct compat_efi_variable *compat;
263*4882a593Smuzhiyun 	unsigned long datasize = sizeof(var->Data);
264*4882a593Smuzhiyun 	size_t size;
265*4882a593Smuzhiyun 	int ret;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (!entry || !buf)
268*4882a593Smuzhiyun 		return 0;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	ret = efivar_entry_get(entry, &var->Attributes, &datasize, var->Data);
271*4882a593Smuzhiyun 	var->DataSize = datasize;
272*4882a593Smuzhiyun 	if (ret)
273*4882a593Smuzhiyun 		return -EIO;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	if (in_compat_syscall()) {
276*4882a593Smuzhiyun 		compat = (struct compat_efi_variable *)buf;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		size = sizeof(*compat);
279*4882a593Smuzhiyun 		memcpy(compat->VariableName, var->VariableName,
280*4882a593Smuzhiyun 			EFI_VAR_NAME_LEN);
281*4882a593Smuzhiyun 		memcpy(compat->Data, var->Data, sizeof(compat->Data));
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		compat->VendorGuid = var->VendorGuid;
284*4882a593Smuzhiyun 		compat->DataSize = var->DataSize;
285*4882a593Smuzhiyun 		compat->Attributes = var->Attributes;
286*4882a593Smuzhiyun 	} else {
287*4882a593Smuzhiyun 		size = sizeof(*var);
288*4882a593Smuzhiyun 		memcpy(buf, var, size);
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	return size;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun /*
295*4882a593Smuzhiyun  * Generic read/write functions that call the specific functions of
296*4882a593Smuzhiyun  * the attributes...
297*4882a593Smuzhiyun  */
efivar_attr_show(struct kobject * kobj,struct attribute * attr,char * buf)298*4882a593Smuzhiyun static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
299*4882a593Smuzhiyun 				char *buf)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	struct efivar_entry *var = to_efivar_entry(kobj);
302*4882a593Smuzhiyun 	struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
303*4882a593Smuzhiyun 	ssize_t ret = -EIO;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
306*4882a593Smuzhiyun 		return -EACCES;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (efivar_attr->show) {
309*4882a593Smuzhiyun 		ret = efivar_attr->show(var, buf);
310*4882a593Smuzhiyun 	}
311*4882a593Smuzhiyun 	return ret;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
efivar_attr_store(struct kobject * kobj,struct attribute * attr,const char * buf,size_t count)314*4882a593Smuzhiyun static ssize_t efivar_attr_store(struct kobject *kobj, struct attribute *attr,
315*4882a593Smuzhiyun 				const char *buf, size_t count)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	struct efivar_entry *var = to_efivar_entry(kobj);
318*4882a593Smuzhiyun 	struct efivar_attribute *efivar_attr = to_efivar_attr(attr);
319*4882a593Smuzhiyun 	ssize_t ret = -EIO;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
322*4882a593Smuzhiyun 		return -EACCES;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	if (efivar_attr->store)
325*4882a593Smuzhiyun 		ret = efivar_attr->store(var, buf, count);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	return ret;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun static const struct sysfs_ops efivar_attr_ops = {
331*4882a593Smuzhiyun 	.show = efivar_attr_show,
332*4882a593Smuzhiyun 	.store = efivar_attr_store,
333*4882a593Smuzhiyun };
334*4882a593Smuzhiyun 
efivar_release(struct kobject * kobj)335*4882a593Smuzhiyun static void efivar_release(struct kobject *kobj)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun 	struct efivar_entry *var = to_efivar_entry(kobj);
338*4882a593Smuzhiyun 	kfree(var);
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);
342*4882a593Smuzhiyun static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);
343*4882a593Smuzhiyun static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);
344*4882a593Smuzhiyun static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);
345*4882a593Smuzhiyun static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun static struct attribute *def_attrs[] = {
348*4882a593Smuzhiyun 	&efivar_attr_guid.attr,
349*4882a593Smuzhiyun 	&efivar_attr_size.attr,
350*4882a593Smuzhiyun 	&efivar_attr_attributes.attr,
351*4882a593Smuzhiyun 	&efivar_attr_data.attr,
352*4882a593Smuzhiyun 	&efivar_attr_raw_var.attr,
353*4882a593Smuzhiyun 	NULL,
354*4882a593Smuzhiyun };
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun static struct kobj_type efivar_ktype = {
357*4882a593Smuzhiyun 	.release = efivar_release,
358*4882a593Smuzhiyun 	.sysfs_ops = &efivar_attr_ops,
359*4882a593Smuzhiyun 	.default_attrs = def_attrs,
360*4882a593Smuzhiyun };
361*4882a593Smuzhiyun 
efivar_create(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)362*4882a593Smuzhiyun static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
363*4882a593Smuzhiyun 			     struct bin_attribute *bin_attr,
364*4882a593Smuzhiyun 			     char *buf, loff_t pos, size_t count)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	struct compat_efi_variable *compat = (struct compat_efi_variable *)buf;
367*4882a593Smuzhiyun 	struct efi_variable *new_var = (struct efi_variable *)buf;
368*4882a593Smuzhiyun 	struct efivar_entry *new_entry;
369*4882a593Smuzhiyun 	bool need_compat = in_compat_syscall();
370*4882a593Smuzhiyun 	efi_char16_t *name;
371*4882a593Smuzhiyun 	unsigned long size;
372*4882a593Smuzhiyun 	u32 attributes;
373*4882a593Smuzhiyun 	u8 *data;
374*4882a593Smuzhiyun 	int err;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
377*4882a593Smuzhiyun 		return -EACCES;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	if (need_compat) {
380*4882a593Smuzhiyun 		if (count != sizeof(*compat))
381*4882a593Smuzhiyun 			return -EINVAL;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 		attributes = compat->Attributes;
384*4882a593Smuzhiyun 		name = compat->VariableName;
385*4882a593Smuzhiyun 		size = compat->DataSize;
386*4882a593Smuzhiyun 		data = compat->Data;
387*4882a593Smuzhiyun 	} else {
388*4882a593Smuzhiyun 		if (count != sizeof(*new_var))
389*4882a593Smuzhiyun 			return -EINVAL;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 		attributes = new_var->Attributes;
392*4882a593Smuzhiyun 		name = new_var->VariableName;
393*4882a593Smuzhiyun 		size = new_var->DataSize;
394*4882a593Smuzhiyun 		data = new_var->Data;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
398*4882a593Smuzhiyun 	    efivar_validate(new_var->VendorGuid, name, data,
399*4882a593Smuzhiyun 			    size) == false) {
400*4882a593Smuzhiyun 		printk(KERN_ERR "efivars: Malformed variable content\n");
401*4882a593Smuzhiyun 		return -EINVAL;
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
405*4882a593Smuzhiyun 	if (!new_entry)
406*4882a593Smuzhiyun 		return -ENOMEM;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if (need_compat)
409*4882a593Smuzhiyun 		copy_out_compat(&new_entry->var, compat);
410*4882a593Smuzhiyun 	else
411*4882a593Smuzhiyun 		memcpy(&new_entry->var, new_var, sizeof(*new_var));
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	err = efivar_entry_set(new_entry, attributes, size,
414*4882a593Smuzhiyun 			       data, &efivar_sysfs_list);
415*4882a593Smuzhiyun 	if (err) {
416*4882a593Smuzhiyun 		if (err == -EEXIST)
417*4882a593Smuzhiyun 			err = -EINVAL;
418*4882a593Smuzhiyun 		goto out;
419*4882a593Smuzhiyun 	}
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	if (efivar_create_sysfs_entry(new_entry)) {
422*4882a593Smuzhiyun 		printk(KERN_WARNING "efivars: failed to create sysfs entry.\n");
423*4882a593Smuzhiyun 		kfree(new_entry);
424*4882a593Smuzhiyun 	}
425*4882a593Smuzhiyun 	return count;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun out:
428*4882a593Smuzhiyun 	kfree(new_entry);
429*4882a593Smuzhiyun 	return err;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun 
efivar_delete(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)432*4882a593Smuzhiyun static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
433*4882a593Smuzhiyun 			     struct bin_attribute *bin_attr,
434*4882a593Smuzhiyun 			     char *buf, loff_t pos, size_t count)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun 	struct efi_variable *del_var = (struct efi_variable *)buf;
437*4882a593Smuzhiyun 	struct compat_efi_variable *compat;
438*4882a593Smuzhiyun 	struct efivar_entry *entry;
439*4882a593Smuzhiyun 	efi_char16_t *name;
440*4882a593Smuzhiyun 	efi_guid_t vendor;
441*4882a593Smuzhiyun 	int err = 0;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	if (!capable(CAP_SYS_ADMIN))
444*4882a593Smuzhiyun 		return -EACCES;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	if (in_compat_syscall()) {
447*4882a593Smuzhiyun 		if (count != sizeof(*compat))
448*4882a593Smuzhiyun 			return -EINVAL;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 		compat = (struct compat_efi_variable *)buf;
451*4882a593Smuzhiyun 		name = compat->VariableName;
452*4882a593Smuzhiyun 		vendor = compat->VendorGuid;
453*4882a593Smuzhiyun 	} else {
454*4882a593Smuzhiyun 		if (count != sizeof(*del_var))
455*4882a593Smuzhiyun 			return -EINVAL;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 		name = del_var->VariableName;
458*4882a593Smuzhiyun 		vendor = del_var->VendorGuid;
459*4882a593Smuzhiyun 	}
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	if (efivar_entry_iter_begin())
462*4882a593Smuzhiyun 		return -EINTR;
463*4882a593Smuzhiyun 	entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true);
464*4882a593Smuzhiyun 	if (!entry)
465*4882a593Smuzhiyun 		err = -EINVAL;
466*4882a593Smuzhiyun 	else if (__efivar_entry_delete(entry))
467*4882a593Smuzhiyun 		err = -EIO;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	if (err) {
470*4882a593Smuzhiyun 		efivar_entry_iter_end();
471*4882a593Smuzhiyun 		return err;
472*4882a593Smuzhiyun 	}
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	if (!entry->scanning) {
475*4882a593Smuzhiyun 		efivar_entry_iter_end();
476*4882a593Smuzhiyun 		efivar_unregister(entry);
477*4882a593Smuzhiyun 	} else
478*4882a593Smuzhiyun 		efivar_entry_iter_end();
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	/* It's dead Jim.... */
481*4882a593Smuzhiyun 	return count;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun /**
485*4882a593Smuzhiyun  * efivar_create_sysfs_entry - create a new entry in sysfs
486*4882a593Smuzhiyun  * @new_var: efivar entry to create
487*4882a593Smuzhiyun  *
488*4882a593Smuzhiyun  * Returns 0 on success, negative error code on failure
489*4882a593Smuzhiyun  */
490*4882a593Smuzhiyun static int
efivar_create_sysfs_entry(struct efivar_entry * new_var)491*4882a593Smuzhiyun efivar_create_sysfs_entry(struct efivar_entry *new_var)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	int short_name_size;
494*4882a593Smuzhiyun 	char *short_name;
495*4882a593Smuzhiyun 	unsigned long utf8_name_size;
496*4882a593Smuzhiyun 	efi_char16_t *variable_name = new_var->var.VariableName;
497*4882a593Smuzhiyun 	int ret;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	/*
500*4882a593Smuzhiyun 	 * Length of the variable bytes in UTF8, plus the '-' separator,
501*4882a593Smuzhiyun 	 * plus the GUID, plus trailing NUL
502*4882a593Smuzhiyun 	 */
503*4882a593Smuzhiyun 	utf8_name_size = ucs2_utf8size(variable_name);
504*4882a593Smuzhiyun 	short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	short_name = kmalloc(short_name_size, GFP_KERNEL);
507*4882a593Smuzhiyun 	if (!short_name)
508*4882a593Smuzhiyun 		return -ENOMEM;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	ucs2_as_utf8(short_name, variable_name, short_name_size);
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	/* This is ugly, but necessary to separate one vendor's
513*4882a593Smuzhiyun 	   private variables from another's.         */
514*4882a593Smuzhiyun 	short_name[utf8_name_size] = '-';
515*4882a593Smuzhiyun 	efi_guid_to_str(&new_var->var.VendorGuid,
516*4882a593Smuzhiyun 			 short_name + utf8_name_size + 1);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	new_var->kobj.kset = efivars_kset;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	ret = kobject_init_and_add(&new_var->kobj, &efivar_ktype,
521*4882a593Smuzhiyun 				   NULL, "%s", short_name);
522*4882a593Smuzhiyun 	kfree(short_name);
523*4882a593Smuzhiyun 	if (ret) {
524*4882a593Smuzhiyun 		kobject_put(&new_var->kobj);
525*4882a593Smuzhiyun 		return ret;
526*4882a593Smuzhiyun 	}
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	kobject_uevent(&new_var->kobj, KOBJ_ADD);
529*4882a593Smuzhiyun 	if (efivar_entry_add(new_var, &efivar_sysfs_list)) {
530*4882a593Smuzhiyun 		efivar_unregister(new_var);
531*4882a593Smuzhiyun 		return -EINTR;
532*4882a593Smuzhiyun 	}
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	return 0;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun static int
create_efivars_bin_attributes(void)538*4882a593Smuzhiyun create_efivars_bin_attributes(void)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	struct bin_attribute *attr;
541*4882a593Smuzhiyun 	int error;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	/* new_var */
544*4882a593Smuzhiyun 	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
545*4882a593Smuzhiyun 	if (!attr)
546*4882a593Smuzhiyun 		return -ENOMEM;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	attr->attr.name = "new_var";
549*4882a593Smuzhiyun 	attr->attr.mode = 0200;
550*4882a593Smuzhiyun 	attr->write = efivar_create;
551*4882a593Smuzhiyun 	efivars_new_var = attr;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	/* del_var */
554*4882a593Smuzhiyun 	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
555*4882a593Smuzhiyun 	if (!attr) {
556*4882a593Smuzhiyun 		error = -ENOMEM;
557*4882a593Smuzhiyun 		goto out_free;
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 	attr->attr.name = "del_var";
560*4882a593Smuzhiyun 	attr->attr.mode = 0200;
561*4882a593Smuzhiyun 	attr->write = efivar_delete;
562*4882a593Smuzhiyun 	efivars_del_var = attr;
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	sysfs_bin_attr_init(efivars_new_var);
565*4882a593Smuzhiyun 	sysfs_bin_attr_init(efivars_del_var);
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* Register */
568*4882a593Smuzhiyun 	error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_new_var);
569*4882a593Smuzhiyun 	if (error) {
570*4882a593Smuzhiyun 		printk(KERN_ERR "efivars: unable to create new_var sysfs file"
571*4882a593Smuzhiyun 			" due to error %d\n", error);
572*4882a593Smuzhiyun 		goto out_free;
573*4882a593Smuzhiyun 	}
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	error = sysfs_create_bin_file(&efivars_kset->kobj, efivars_del_var);
576*4882a593Smuzhiyun 	if (error) {
577*4882a593Smuzhiyun 		printk(KERN_ERR "efivars: unable to create del_var sysfs file"
578*4882a593Smuzhiyun 			" due to error %d\n", error);
579*4882a593Smuzhiyun 		sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
580*4882a593Smuzhiyun 		goto out_free;
581*4882a593Smuzhiyun 	}
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	return 0;
584*4882a593Smuzhiyun out_free:
585*4882a593Smuzhiyun 	kfree(efivars_del_var);
586*4882a593Smuzhiyun 	efivars_del_var = NULL;
587*4882a593Smuzhiyun 	kfree(efivars_new_var);
588*4882a593Smuzhiyun 	efivars_new_var = NULL;
589*4882a593Smuzhiyun 	return error;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun 
efivars_sysfs_callback(efi_char16_t * name,efi_guid_t vendor,unsigned long name_size,void * data)592*4882a593Smuzhiyun static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
593*4882a593Smuzhiyun 				  unsigned long name_size, void *data)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun 	struct efivar_entry *entry;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
598*4882a593Smuzhiyun 	if (!entry)
599*4882a593Smuzhiyun 		return -ENOMEM;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	memcpy(entry->var.VariableName, name, name_size);
602*4882a593Smuzhiyun 	memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t));
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	efivar_create_sysfs_entry(entry);
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	return 0;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
efivar_sysfs_destroy(struct efivar_entry * entry,void * data)609*4882a593Smuzhiyun static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun 	int err = efivar_entry_remove(entry);
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	if (err)
614*4882a593Smuzhiyun 		return err;
615*4882a593Smuzhiyun 	efivar_unregister(entry);
616*4882a593Smuzhiyun 	return 0;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun 
efivars_sysfs_exit(void)619*4882a593Smuzhiyun static void efivars_sysfs_exit(void)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	/* Remove all entries and destroy */
622*4882a593Smuzhiyun 	int err;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	err = __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list,
625*4882a593Smuzhiyun 				  NULL, NULL);
626*4882a593Smuzhiyun 	if (err) {
627*4882a593Smuzhiyun 		pr_err("efivars: Failed to destroy sysfs entries\n");
628*4882a593Smuzhiyun 		return;
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	if (efivars_new_var)
632*4882a593Smuzhiyun 		sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
633*4882a593Smuzhiyun 	if (efivars_del_var)
634*4882a593Smuzhiyun 		sysfs_remove_bin_file(&efivars_kset->kobj, efivars_del_var);
635*4882a593Smuzhiyun 	kfree(efivars_new_var);
636*4882a593Smuzhiyun 	kfree(efivars_del_var);
637*4882a593Smuzhiyun 	kset_unregister(efivars_kset);
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun 
efivars_sysfs_init(void)640*4882a593Smuzhiyun static int efivars_sysfs_init(void)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun 	struct kobject *parent_kobj = efivars_kobject();
643*4882a593Smuzhiyun 	int error = 0;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	/* No efivars has been registered yet */
646*4882a593Smuzhiyun 	if (!parent_kobj || !efivar_supports_writes())
647*4882a593Smuzhiyun 		return 0;
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
650*4882a593Smuzhiyun 	       EFIVARS_DATE);
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	efivars_kset = kset_create_and_add("vars", NULL, parent_kobj);
653*4882a593Smuzhiyun 	if (!efivars_kset) {
654*4882a593Smuzhiyun 		printk(KERN_ERR "efivars: Subsystem registration failed.\n");
655*4882a593Smuzhiyun 		return -ENOMEM;
656*4882a593Smuzhiyun 	}
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	efivar_init(efivars_sysfs_callback, NULL, true, &efivar_sysfs_list);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	error = create_efivars_bin_attributes();
661*4882a593Smuzhiyun 	if (error) {
662*4882a593Smuzhiyun 		efivars_sysfs_exit();
663*4882a593Smuzhiyun 		return error;
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	return 0;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun module_init(efivars_sysfs_init);
670*4882a593Smuzhiyun module_exit(efivars_sysfs_exit);
671