aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/firmware/efi/efivars.c142
1 files changed, 116 insertions, 26 deletions
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index a44310c6a8ba..463c56545ae8 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -69,6 +69,7 @@
69#include <linux/module.h> 69#include <linux/module.h>
70#include <linux/slab.h> 70#include <linux/slab.h>
71#include <linux/ucs2_string.h> 71#include <linux/ucs2_string.h>
72#include <linux/compat.h>
72 73
73#define EFIVARS_VERSION "0.08" 74#define EFIVARS_VERSION "0.08"
74#define EFIVARS_DATE "2004-May-17" 75#define EFIVARS_DATE "2004-May-17"
@@ -86,6 +87,15 @@ static struct kset *efivars_kset;
86static struct bin_attribute *efivars_new_var; 87static struct bin_attribute *efivars_new_var;
87static struct bin_attribute *efivars_del_var; 88static struct bin_attribute *efivars_del_var;
88 89
90struct compat_efi_variable {
91 efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
92 efi_guid_t VendorGuid;
93 __u32 DataSize;
94 __u8 Data[1024];
95 __u32 Status;
96 __u32 Attributes;
97} __packed;
98
89struct efivar_attribute { 99struct efivar_attribute {
90 struct attribute attr; 100 struct attribute attr;
91 ssize_t (*show) (struct efivar_entry *entry, char *buf); 101 ssize_t (*show) (struct efivar_entry *entry, char *buf);
@@ -218,6 +228,25 @@ sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
218 return 0; 228 return 0;
219} 229}
220 230
231static inline bool is_compat(void)
232{
233 if (IS_ENABLED(CONFIG_COMPAT) && is_compat_task())
234 return true;
235
236 return false;
237}
238
239static void
240copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src)
241{
242 memcpy(dst->VariableName, src->VariableName, EFI_VAR_NAME_LEN);
243 memcpy(dst->Data, src->Data, sizeof(src->Data));
244
245 dst->VendorGuid = src->VendorGuid;
246 dst->DataSize = src->DataSize;
247 dst->Attributes = src->Attributes;
248}
249
221/* 250/*
222 * We allow each variable to be edited via rewriting the 251 * We allow each variable to be edited via rewriting the
223 * entire efi variable structure. 252 * entire efi variable structure.
@@ -233,22 +262,42 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
233 u8 *data; 262 u8 *data;
234 int err; 263 int err;
235 264
236 if (count != sizeof(struct efi_variable)) 265 if (is_compat()) {
237 return -EINVAL; 266 struct compat_efi_variable *compat;
238 267
239 new_var = (struct efi_variable *)buf; 268 if (count != sizeof(*compat))
269 return -EINVAL;
240 270
241 attributes = new_var->Attributes; 271 compat = (struct compat_efi_variable *)buf;
242 vendor = new_var->VendorGuid; 272 attributes = compat->Attributes;
243 name = new_var->VariableName; 273 vendor = compat->VendorGuid;
244 size = new_var->DataSize; 274 name = compat->VariableName;
245 data = new_var->Data; 275 size = compat->DataSize;
276 data = compat->Data;
246 277
247 err = sanity_check(var, name, vendor, size, attributes, data); 278 err = sanity_check(var, name, vendor, size, attributes, data);
248 if (err) 279 if (err)
249 return err; 280 return err;
281
282 copy_out_compat(&entry->var, compat);
283 } else {
284 if (count != sizeof(struct efi_variable))
285 return -EINVAL;
286
287 new_var = (struct efi_variable *)buf;
250 288
251 memcpy(&entry->var, new_var, count); 289 attributes = new_var->Attributes;
290 vendor = new_var->VendorGuid;
291 name = new_var->VariableName;
292 size = new_var->DataSize;
293 data = new_var->Data;
294
295 err = sanity_check(var, name, vendor, size, attributes, data);
296 if (err)
297 return err;
298
299 memcpy(&entry->var, new_var, count);
300 }
252 301
253 err = efivar_entry_set(entry, attributes, size, data, NULL); 302 err = efivar_entry_set(entry, attributes, size, data, NULL);
254 if (err) { 303 if (err) {
@@ -263,6 +312,8 @@ static ssize_t
263efivar_show_raw(struct efivar_entry *entry, char *buf) 312efivar_show_raw(struct efivar_entry *entry, char *buf)
264{ 313{
265 struct efi_variable *var = &entry->var; 314 struct efi_variable *var = &entry->var;
315 struct compat_efi_variable *compat;
316 size_t size;
266 317
267 if (!entry || !buf) 318 if (!entry || !buf)
268 return 0; 319 return 0;
@@ -272,9 +323,23 @@ efivar_show_raw(struct efivar_entry *entry, char *buf)
272 &entry->var.DataSize, entry->var.Data)) 323 &entry->var.DataSize, entry->var.Data))
273 return -EIO; 324 return -EIO;
274 325
275 memcpy(buf, var, sizeof(*var)); 326 if (is_compat()) {
327 compat = (struct compat_efi_variable *)buf;
328
329 size = sizeof(*compat);
330 memcpy(compat->VariableName, var->VariableName,
331 EFI_VAR_NAME_LEN);
332 memcpy(compat->Data, var->Data, sizeof(compat->Data));
333
334 compat->VendorGuid = var->VendorGuid;
335 compat->DataSize = var->DataSize;
336 compat->Attributes = var->Attributes;
337 } else {
338 size = sizeof(*var);
339 memcpy(buf, var, size);
340 }
276 341
277 return sizeof(*var); 342 return size;
278} 343}
279 344
280/* 345/*
@@ -349,8 +414,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
349 struct bin_attribute *bin_attr, 414 struct bin_attribute *bin_attr,
350 char *buf, loff_t pos, size_t count) 415 char *buf, loff_t pos, size_t count)
351{ 416{
417 struct compat_efi_variable *compat = (struct compat_efi_variable *)buf;
352 struct efi_variable *new_var = (struct efi_variable *)buf; 418 struct efi_variable *new_var = (struct efi_variable *)buf;
353 struct efivar_entry *new_entry; 419 struct efivar_entry *new_entry;
420 bool need_compat = is_compat();
354 efi_char16_t *name; 421 efi_char16_t *name;
355 unsigned long size; 422 unsigned long size;
356 u32 attributes; 423 u32 attributes;
@@ -360,13 +427,23 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
360 if (!capable(CAP_SYS_ADMIN)) 427 if (!capable(CAP_SYS_ADMIN))
361 return -EACCES; 428 return -EACCES;
362 429
363 if (count != sizeof(*new_var)) 430 if (need_compat) {
364 return -EINVAL; 431 if (count != sizeof(*compat))
365 432 return -EINVAL;
366 attributes = new_var->Attributes; 433
367 name = new_var->VariableName; 434 attributes = compat->Attributes;
368 size = new_var->DataSize; 435 name = compat->VariableName;
369 data = new_var->Data; 436 size = compat->DataSize;
437 data = compat->Data;
438 } else {
439 if (count != sizeof(*new_var))
440 return -EINVAL;
441
442 attributes = new_var->Attributes;
443 name = new_var->VariableName;
444 size = new_var->DataSize;
445 data = new_var->Data;
446 }
370 447
371 if ((attributes & ~EFI_VARIABLE_MASK) != 0 || 448 if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
372 efivar_validate(name, data, size) == false) { 449 efivar_validate(name, data, size) == false) {
@@ -378,7 +455,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
378 if (!new_entry) 455 if (!new_entry)
379 return -ENOMEM; 456 return -ENOMEM;
380 457
381 memcpy(&new_entry->var, new_var, sizeof(*new_var)); 458 if (need_compat)
459 copy_out_compat(&new_entry->var, compat);
460 else
461 memcpy(&new_entry->var, new_var, sizeof(*new_var));
382 462
383 err = efivar_entry_set(new_entry, attributes, size, 463 err = efivar_entry_set(new_entry, attributes, size,
384 data, &efivar_sysfs_list); 464 data, &efivar_sysfs_list);
@@ -404,6 +484,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
404 char *buf, loff_t pos, size_t count) 484 char *buf, loff_t pos, size_t count)
405{ 485{
406 struct efi_variable *del_var = (struct efi_variable *)buf; 486 struct efi_variable *del_var = (struct efi_variable *)buf;
487 struct compat_efi_variable *compat;
407 struct efivar_entry *entry; 488 struct efivar_entry *entry;
408 efi_char16_t *name; 489 efi_char16_t *name;
409 efi_guid_t vendor; 490 efi_guid_t vendor;
@@ -412,11 +493,20 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
412 if (!capable(CAP_SYS_ADMIN)) 493 if (!capable(CAP_SYS_ADMIN))
413 return -EACCES; 494 return -EACCES;
414 495
415 if (count != sizeof(*del_var)) 496 if (is_compat()) {
416 return -EINVAL; 497 if (count != sizeof(*compat))
498 return -EINVAL;
499
500 compat = (struct compat_efi_variable *)buf;
501 name = compat->VariableName;
502 vendor = compat->VendorGuid;
503 } else {
504 if (count != sizeof(*del_var))
505 return -EINVAL;
417 506
418 name = del_var->VariableName; 507 name = del_var->VariableName;
419 vendor = del_var->VendorGuid; 508 vendor = del_var->VendorGuid;
509 }
420 510
421 efivar_entry_iter_begin(); 511 efivar_entry_iter_begin();
422 entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true); 512 entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true);