[parent not found: <1395259200-27732-1-git-send-email-matt-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>]
* [PATCH 1/5] efivars: Use local variables instead of a pointer dereference
[not found] ` <1395259200-27732-1-git-send-email-matt-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
@ 2014-03-19 19:59 ` Matt Fleming
0 siblings, 0 replies; 6+ messages in thread
From: Matt Fleming @ 2014-03-19 19:59 UTC (permalink / raw)
To: linux-efi-u79uwXL29TY76Z2rM5mHXA
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Matt Fleming
From: Matt Fleming <matt.fleming-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
In order to support a compat interface we need to stop passing pointers
to structures around, since the type of structure is going to depend on
whether the current task is a compat task.
Signed-off-by: Matt Fleming <matt.fleming-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
drivers/firmware/efi/efivars.c | 48 ++++++++++++++++++++++++++++++------------
1 file changed, 35 insertions(+), 13 deletions(-)
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 50ea412a25e6..06ec6ee1c58a 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -197,37 +197,48 @@ static ssize_t
efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
{
struct efi_variable *new_var, *var = &entry->var;
+ efi_char16_t *name;
+ unsigned long size;
+ efi_guid_t vendor;
+ u32 attributes;
+ u8 *data;
int err;
if (count != sizeof(struct efi_variable))
return -EINVAL;
new_var = (struct efi_variable *)buf;
+
+ attributes = new_var->Attributes;
+ vendor = new_var->VendorGuid;
+ name = new_var->VariableName;
+ size = new_var->DataSize;
+ data = new_var->Data;
+
/*
* If only updating the variable data, then the name
* and guid should remain the same
*/
- if (memcmp(new_var->VariableName, var->VariableName, sizeof(var->VariableName)) ||
- efi_guidcmp(new_var->VendorGuid, var->VendorGuid)) {
+ if (memcmp(name, var->VariableName, sizeof(var->VariableName)) ||
+ efi_guidcmp(vendor, var->VendorGuid)) {
printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
return -EINVAL;
}
- if ((new_var->DataSize <= 0) || (new_var->Attributes == 0)){
+ if ((size <= 0) || (attributes == 0)){
printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
return -EINVAL;
}
- if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
- efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
+ if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
+ efivar_validate(new_var, data, size) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
memcpy(&entry->var, new_var, count);
- err = efivar_entry_set(entry, new_var->Attributes,
- new_var->DataSize, new_var->Data, NULL);
+ err = efivar_entry_set(entry, attributes, size, data, NULL);
if (err) {
printk(KERN_WARNING "efivars: set_variable() failed: status=%d\n", err);
return -EIO;
@@ -328,13 +339,20 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
{
struct efi_variable *new_var = (struct efi_variable *)buf;
struct efivar_entry *new_entry;
+ unsigned long size;
+ u32 attributes;
+ u8 *data;
int err;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 ||
- efivar_validate(new_var, new_var->Data, new_var->DataSize) == false) {
+ attributes = new_var->Attributes;
+ size = new_var->DataSize;
+ data = new_var->Data;
+
+ if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
+ efivar_validate(new_var, data, size) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
@@ -345,8 +363,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
memcpy(&new_entry->var, new_var, sizeof(*new_var));
- err = efivar_entry_set(new_entry, new_var->Attributes, new_var->DataSize,
- new_var->Data, &efivar_sysfs_list);
+ err = efivar_entry_set(new_entry, attributes, size,
+ data, &efivar_sysfs_list);
if (err) {
if (err == -EEXIST)
err = -EINVAL;
@@ -370,14 +388,18 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
{
struct efi_variable *del_var = (struct efi_variable *)buf;
struct efivar_entry *entry;
+ efi_char16_t *name;
+ efi_guid_t vendor;
int err = 0;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
+ name = del_var->VariableName;
+ vendor = del_var->VendorGuid;
+
efivar_entry_iter_begin();
- entry = efivar_entry_find(del_var->VariableName, del_var->VendorGuid,
- &efivar_sysfs_list, true);
+ entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true);
if (!entry)
err = -EINVAL;
else if (__efivar_entry_delete(entry))
--
1.8.5.3
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/5] efivars: Check size of user object
2014-03-19 19:59 [PATCH 0/5] efivars compat support Matt Fleming
[not found] ` <1395259200-27732-1-git-send-email-matt-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
@ 2014-03-19 19:59 ` Matt Fleming
2014-03-19 19:59 ` [PATCH 3/5] efivars: Stop passing a struct argument to efivar_validate() Matt Fleming
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Matt Fleming @ 2014-03-19 19:59 UTC (permalink / raw)
To: linux-efi; +Cc: linux-kernel, Matt Fleming
From: Matt Fleming <matt.fleming@intel.com>
Unbelieavably there are no checks to see whether the data structure
passed to 'new_var' and 'del_var' is the size that we expect. Let's add
some for better robustness.
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
---
drivers/firmware/efi/efivars.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 06ec6ee1c58a..2c21cccc2572 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -347,6 +347,9 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
+ if (count != sizeof(*new_var))
+ return -EINVAL;
+
attributes = new_var->Attributes;
size = new_var->DataSize;
data = new_var->Data;
@@ -395,6 +398,9 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
+ if (count != sizeof(*del_var))
+ return -EINVAL;
+
name = del_var->VariableName;
vendor = del_var->VendorGuid;
--
1.8.5.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/5] efivars: Stop passing a struct argument to efivar_validate()
2014-03-19 19:59 [PATCH 0/5] efivars compat support Matt Fleming
[not found] ` <1395259200-27732-1-git-send-email-matt-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
2014-03-19 19:59 ` [PATCH 2/5] efivars: Check size of user object Matt Fleming
@ 2014-03-19 19:59 ` Matt Fleming
2014-03-19 19:59 ` [PATCH 4/5] efivars: Refactor sanity checking code into separate function Matt Fleming
2014-03-19 20:00 ` [PATCH 5/5] efivars: Add compatibility code for compat tasks Matt Fleming
4 siblings, 0 replies; 6+ messages in thread
From: Matt Fleming @ 2014-03-19 19:59 UTC (permalink / raw)
To: linux-efi; +Cc: linux-kernel, Matt Fleming
From: Matt Fleming <matt.fleming@intel.com>
In preparation for compat support, we can't assume that user variable
object is represented by a 'struct efi_variable'. Convert the validation
functions to take the variable name as an argument, which is the only
piece of the struct that was ever used anyway.
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
---
drivers/firmware/efi/efivars.c | 6 ++++--
drivers/firmware/efi/vars.c | 30 +++++++++++++++---------------
include/linux/efi.h | 6 ++++--
3 files changed, 23 insertions(+), 19 deletions(-)
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 2c21cccc2572..5ee2cfb96698 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -231,7 +231,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
}
if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
- efivar_validate(new_var, data, size) == false) {
+ efivar_validate(name, data, size) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
@@ -339,6 +339,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
{
struct efi_variable *new_var = (struct efi_variable *)buf;
struct efivar_entry *new_entry;
+ efi_char16_t *name;
unsigned long size;
u32 attributes;
u8 *data;
@@ -351,11 +352,12 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
return -EINVAL;
attributes = new_var->Attributes;
+ name = new_var->VariableName;
size = new_var->DataSize;
data = new_var->Data;
if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
- efivar_validate(new_var, data, size) == false) {
+ efivar_validate(name, data, size) == false) {
printk(KERN_ERR "efivars: Malformed variable content\n");
return -EINVAL;
}
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index b22659cccca4..f0a43646a2f3 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -42,7 +42,7 @@ DECLARE_WORK(efivar_work, NULL);
EXPORT_SYMBOL_GPL(efivar_work);
static bool
-validate_device_path(struct efi_variable *var, int match, u8 *buffer,
+validate_device_path(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
struct efi_generic_dev_path *node;
@@ -75,7 +75,7 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer,
}
static bool
-validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
+validate_boot_order(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
/* An array of 16-bit integers */
@@ -86,18 +86,18 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
}
static bool
-validate_load_option(struct efi_variable *var, int match, u8 *buffer,
+validate_load_option(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
u16 filepathlength;
int i, desclength = 0, namelen;
- namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName));
+ namelen = ucs2_strnlen(var_name, EFI_VAR_NAME_LEN);
/* Either "Boot" or "Driver" followed by four digits of hex */
for (i = match; i < match+4; i++) {
- if (var->VariableName[i] > 127 ||
- hex_to_bin(var->VariableName[i] & 0xff) < 0)
+ if (var_name[i] > 127 ||
+ hex_to_bin(var_name[i] & 0xff) < 0)
return true;
}
@@ -132,12 +132,12 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
/*
* And, finally, check the filepath
*/
- return validate_device_path(var, match, buffer + desclength + 6,
+ return validate_device_path(var_name, match, buffer + desclength + 6,
filepathlength);
}
static bool
-validate_uint16(struct efi_variable *var, int match, u8 *buffer,
+validate_uint16(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
/* A single 16-bit integer */
@@ -148,7 +148,7 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer,
}
static bool
-validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
+validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer,
unsigned long len)
{
int i;
@@ -166,7 +166,7 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
struct variable_validate {
char *name;
- bool (*validate)(struct efi_variable *var, int match, u8 *data,
+ bool (*validate)(efi_char16_t *var_name, int match, u8 *data,
unsigned long len);
};
@@ -189,10 +189,10 @@ static const struct variable_validate variable_validate[] = {
};
bool
-efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
+efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len)
{
int i;
- u16 *unicode_name = var->VariableName;
+ u16 *unicode_name = var_name;
for (i = 0; variable_validate[i].validate != NULL; i++) {
const char *name = variable_validate[i].name;
@@ -208,7 +208,7 @@ efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
/* Wildcard in the matching name means we've matched */
if (c == '*')
- return variable_validate[i].validate(var,
+ return variable_validate[i].validate(var_name,
match, data, len);
/* Case sensitive match */
@@ -217,7 +217,7 @@ efivar_validate(struct efi_variable *var, u8 *data, unsigned long len)
/* Reached the end of the string while matching */
if (!c)
- return variable_validate[i].validate(var,
+ return variable_validate[i].validate(var_name,
match, data, len);
}
}
@@ -805,7 +805,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
*set = false;
- if (efivar_validate(&entry->var, data, *size) == false)
+ if (efivar_validate(name, data, *size) == false)
return -EINVAL;
/*
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 6c100ff0cae4..0f5f6d54fb56 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1033,8 +1033,10 @@ struct efivars {
* and we use a page for reading/writing.
*/
+#define EFI_VAR_NAME_LEN 1024
+
struct efi_variable {
- efi_char16_t VariableName[1024/sizeof(efi_char16_t)];
+ efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
efi_guid_t VendorGuid;
unsigned long DataSize;
__u8 Data[1024];
@@ -1116,7 +1118,7 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
struct list_head *head, bool remove);
-bool efivar_validate(struct efi_variable *var, u8 *data, unsigned long len);
+bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len);
extern struct work_struct efivar_work;
void efivar_run_worker(void);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/5] efivars: Refactor sanity checking code into separate function
2014-03-19 19:59 [PATCH 0/5] efivars compat support Matt Fleming
` (2 preceding siblings ...)
2014-03-19 19:59 ` [PATCH 3/5] efivars: Stop passing a struct argument to efivar_validate() Matt Fleming
@ 2014-03-19 19:59 ` Matt Fleming
2014-03-19 20:00 ` [PATCH 5/5] efivars: Add compatibility code for compat tasks Matt Fleming
4 siblings, 0 replies; 6+ messages in thread
From: Matt Fleming @ 2014-03-19 19:59 UTC (permalink / raw)
To: linux-efi; +Cc: linux-kernel, Matt Fleming
From: Matt Fleming <matt.fleming@intel.com>
Move a large chunk of code that checks the validity of efi_variable into
a new function, because we'll also need to use it for the compat code.
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
---
drivers/firmware/efi/efivars.c | 52 ++++++++++++++++++++++++++----------------
1 file changed, 32 insertions(+), 20 deletions(-)
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 5ee2cfb96698..a44310c6a8ba 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -189,6 +189,35 @@ efivar_data_read(struct efivar_entry *entry, char *buf)
memcpy(buf, var->Data, var->DataSize);
return var->DataSize;
}
+
+static inline int
+sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor,
+ unsigned long size, u32 attributes, u8 *data)
+{
+ /*
+ * If only updating the variable data, then the name
+ * and guid should remain the same
+ */
+ if (memcmp(name, var->VariableName, sizeof(var->VariableName)) ||
+ efi_guidcmp(vendor, var->VendorGuid)) {
+ printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
+ return -EINVAL;
+ }
+
+ if ((size <= 0) || (attributes == 0)){
+ printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
+ return -EINVAL;
+ }
+
+ if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
+ efivar_validate(name, data, size) == false) {
+ printk(KERN_ERR "efivars: Malformed variable content\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/*
* We allow each variable to be edited via rewriting the
* entire efi variable structure.
@@ -215,26 +244,9 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
size = new_var->DataSize;
data = new_var->Data;
- /*
- * If only updating the variable data, then the name
- * and guid should remain the same
- */
- if (memcmp(name, var->VariableName, sizeof(var->VariableName)) ||
- efi_guidcmp(vendor, var->VendorGuid)) {
- printk(KERN_ERR "efivars: Cannot edit the wrong variable!\n");
- return -EINVAL;
- }
-
- if ((size <= 0) || (attributes == 0)){
- printk(KERN_ERR "efivars: DataSize & Attributes must be valid!\n");
- return -EINVAL;
- }
-
- if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
- efivar_validate(name, data, size) == false) {
- printk(KERN_ERR "efivars: Malformed variable content\n");
- return -EINVAL;
- }
+ err = sanity_check(var, name, vendor, size, attributes, data);
+ if (err)
+ return err;
memcpy(&entry->var, new_var, count);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 5/5] efivars: Add compatibility code for compat tasks
2014-03-19 19:59 [PATCH 0/5] efivars compat support Matt Fleming
` (3 preceding siblings ...)
2014-03-19 19:59 ` [PATCH 4/5] efivars: Refactor sanity checking code into separate function Matt Fleming
@ 2014-03-19 20:00 ` Matt Fleming
4 siblings, 0 replies; 6+ messages in thread
From: Matt Fleming @ 2014-03-19 20:00 UTC (permalink / raw)
To: linux-efi; +Cc: linux-kernel, Matt Fleming
From: Matt Fleming <matt.fleming@intel.com>
It seems people are using 32-bit efibootmgr on top of 64-bit kernels,
which will currently fail horribly when using the efivars interface,
which is the traditional efibootmgr backend (the other being efivarfs).
Since there is no versioning info in the data structure, figure out when
we need to munge the structure data via judicious use of
is_compat_task().
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
---
drivers/firmware/efi/efivars.c | 142 +++++++++++++++++++++++++++++++++--------
1 file 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 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ucs2_string.h>
+#include <linux/compat.h>
#define EFIVARS_VERSION "0.08"
#define EFIVARS_DATE "2004-May-17"
@@ -86,6 +87,15 @@ static struct kset *efivars_kset;
static struct bin_attribute *efivars_new_var;
static struct bin_attribute *efivars_del_var;
+struct compat_efi_variable {
+ efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];
+ efi_guid_t VendorGuid;
+ __u32 DataSize;
+ __u8 Data[1024];
+ __u32 Status;
+ __u32 Attributes;
+} __packed;
+
struct efivar_attribute {
struct attribute attr;
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,
return 0;
}
+static inline bool is_compat(void)
+{
+ if (IS_ENABLED(CONFIG_COMPAT) && is_compat_task())
+ return true;
+
+ return false;
+}
+
+static void
+copy_out_compat(struct efi_variable *dst, struct compat_efi_variable *src)
+{
+ memcpy(dst->VariableName, src->VariableName, EFI_VAR_NAME_LEN);
+ memcpy(dst->Data, src->Data, sizeof(src->Data));
+
+ dst->VendorGuid = src->VendorGuid;
+ dst->DataSize = src->DataSize;
+ dst->Attributes = src->Attributes;
+}
+
/*
* We allow each variable to be edited via rewriting the
* entire efi variable structure.
@@ -233,22 +262,42 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
u8 *data;
int err;
- if (count != sizeof(struct efi_variable))
- return -EINVAL;
+ if (is_compat()) {
+ struct compat_efi_variable *compat;
- new_var = (struct efi_variable *)buf;
+ if (count != sizeof(*compat))
+ return -EINVAL;
- attributes = new_var->Attributes;
- vendor = new_var->VendorGuid;
- name = new_var->VariableName;
- size = new_var->DataSize;
- data = new_var->Data;
+ compat = (struct compat_efi_variable *)buf;
+ attributes = compat->Attributes;
+ vendor = compat->VendorGuid;
+ name = compat->VariableName;
+ size = compat->DataSize;
+ data = compat->Data;
- err = sanity_check(var, name, vendor, size, attributes, data);
- if (err)
- return err;
+ err = sanity_check(var, name, vendor, size, attributes, data);
+ if (err)
+ return err;
+
+ copy_out_compat(&entry->var, compat);
+ } else {
+ if (count != sizeof(struct efi_variable))
+ return -EINVAL;
+
+ new_var = (struct efi_variable *)buf;
- memcpy(&entry->var, new_var, count);
+ attributes = new_var->Attributes;
+ vendor = new_var->VendorGuid;
+ name = new_var->VariableName;
+ size = new_var->DataSize;
+ data = new_var->Data;
+
+ err = sanity_check(var, name, vendor, size, attributes, data);
+ if (err)
+ return err;
+
+ memcpy(&entry->var, new_var, count);
+ }
err = efivar_entry_set(entry, attributes, size, data, NULL);
if (err) {
@@ -263,6 +312,8 @@ static ssize_t
efivar_show_raw(struct efivar_entry *entry, char *buf)
{
struct efi_variable *var = &entry->var;
+ struct compat_efi_variable *compat;
+ size_t size;
if (!entry || !buf)
return 0;
@@ -272,9 +323,23 @@ efivar_show_raw(struct efivar_entry *entry, char *buf)
&entry->var.DataSize, entry->var.Data))
return -EIO;
- memcpy(buf, var, sizeof(*var));
+ if (is_compat()) {
+ compat = (struct compat_efi_variable *)buf;
+
+ size = sizeof(*compat);
+ memcpy(compat->VariableName, var->VariableName,
+ EFI_VAR_NAME_LEN);
+ memcpy(compat->Data, var->Data, sizeof(compat->Data));
+
+ compat->VendorGuid = var->VendorGuid;
+ compat->DataSize = var->DataSize;
+ compat->Attributes = var->Attributes;
+ } else {
+ size = sizeof(*var);
+ memcpy(buf, var, size);
+ }
- return sizeof(*var);
+ return size;
}
/*
@@ -349,8 +414,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t count)
{
+ struct compat_efi_variable *compat = (struct compat_efi_variable *)buf;
struct efi_variable *new_var = (struct efi_variable *)buf;
struct efivar_entry *new_entry;
+ bool need_compat = is_compat();
efi_char16_t *name;
unsigned long size;
u32 attributes;
@@ -360,13 +427,23 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (count != sizeof(*new_var))
- return -EINVAL;
-
- attributes = new_var->Attributes;
- name = new_var->VariableName;
- size = new_var->DataSize;
- data = new_var->Data;
+ if (need_compat) {
+ if (count != sizeof(*compat))
+ return -EINVAL;
+
+ attributes = compat->Attributes;
+ name = compat->VariableName;
+ size = compat->DataSize;
+ data = compat->Data;
+ } else {
+ if (count != sizeof(*new_var))
+ return -EINVAL;
+
+ attributes = new_var->Attributes;
+ name = new_var->VariableName;
+ size = new_var->DataSize;
+ data = new_var->Data;
+ }
if ((attributes & ~EFI_VARIABLE_MASK) != 0 ||
efivar_validate(name, data, size) == false) {
@@ -378,7 +455,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
if (!new_entry)
return -ENOMEM;
- memcpy(&new_entry->var, new_var, sizeof(*new_var));
+ if (need_compat)
+ copy_out_compat(&new_entry->var, compat);
+ else
+ memcpy(&new_entry->var, new_var, sizeof(*new_var));
err = efivar_entry_set(new_entry, attributes, size,
data, &efivar_sysfs_list);
@@ -404,6 +484,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
char *buf, loff_t pos, size_t count)
{
struct efi_variable *del_var = (struct efi_variable *)buf;
+ struct compat_efi_variable *compat;
struct efivar_entry *entry;
efi_char16_t *name;
efi_guid_t vendor;
@@ -412,11 +493,20 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (count != sizeof(*del_var))
- return -EINVAL;
+ if (is_compat()) {
+ if (count != sizeof(*compat))
+ return -EINVAL;
+
+ compat = (struct compat_efi_variable *)buf;
+ name = compat->VariableName;
+ vendor = compat->VendorGuid;
+ } else {
+ if (count != sizeof(*del_var))
+ return -EINVAL;
- name = del_var->VariableName;
- vendor = del_var->VendorGuid;
+ name = del_var->VariableName;
+ vendor = del_var->VendorGuid;
+ }
efivar_entry_iter_begin();
entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 6+ messages in thread