|
@@ -172,10 +172,12 @@ struct variable_validate {
|
|
|
};
|
|
|
|
|
|
/*
|
|
|
- * This is the list of variables we need to validate.
|
|
|
+ * This is the list of variables we need to validate, as well as the
|
|
|
+ * whitelist for what we think is safe not to default to immutable.
|
|
|
*
|
|
|
* If it has a validate() method that's not NULL, it'll go into the
|
|
|
- * validation routine. If not, it is assumed valid.
|
|
|
+ * validation routine. If not, it is assumed valid, but still used for
|
|
|
+ * whitelisting.
|
|
|
*
|
|
|
* Note that it's sorted by {vendor,name}, but globbed names must come after
|
|
|
* any other name with the same prefix.
|
|
@@ -193,11 +195,37 @@ static const struct variable_validate variable_validate[] = {
|
|
|
{ EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path },
|
|
|
{ EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path },
|
|
|
{ EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string },
|
|
|
+ { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL },
|
|
|
{ EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string },
|
|
|
{ EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 },
|
|
|
{ NULL_GUID, "", NULL },
|
|
|
};
|
|
|
|
|
|
+static bool
|
|
|
+variable_matches(const char *var_name, size_t len, const char *match_name,
|
|
|
+ int *match)
|
|
|
+{
|
|
|
+ for (*match = 0; ; (*match)++) {
|
|
|
+ char c = match_name[*match];
|
|
|
+ char u = var_name[*match];
|
|
|
+
|
|
|
+ /* Wildcard in the matching name means we've matched */
|
|
|
+ if (c == '*')
|
|
|
+ return true;
|
|
|
+
|
|
|
+ /* Case sensitive match */
|
|
|
+ if (!c && *match == len)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (c != u)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (!c)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
bool
|
|
|
efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
|
|
|
unsigned long data_size)
|
|
@@ -221,35 +249,48 @@ efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data,
|
|
|
if (efi_guidcmp(vendor, variable_validate[i].vendor))
|
|
|
continue;
|
|
|
|
|
|
- for (match = 0; ; match++) {
|
|
|
- char c = name[match];
|
|
|
- char u = utf8_name[match];
|
|
|
-
|
|
|
- /* Wildcard in the matching name means we've matched */
|
|
|
- if (c == '*') {
|
|
|
- kfree(utf8_name);
|
|
|
- return variable_validate[i].validate(var_name,
|
|
|
- match, data, data_size);
|
|
|
- }
|
|
|
-
|
|
|
- /* Case sensitive match */
|
|
|
- if (c != u)
|
|
|
+ if (variable_matches(utf8_name, utf8_size+1, name, &match)) {
|
|
|
+ if (variable_validate[i].validate == NULL)
|
|
|
break;
|
|
|
-
|
|
|
- /* Reached the end of the string while matching */
|
|
|
- if (!c) {
|
|
|
- kfree(utf8_name);
|
|
|
- return variable_validate[i].validate(var_name,
|
|
|
- match, data, data_size);
|
|
|
- }
|
|
|
+ kfree(utf8_name);
|
|
|
+ return variable_validate[i].validate(var_name, match,
|
|
|
+ data, data_size);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
kfree(utf8_name);
|
|
|
return true;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(efivar_validate);
|
|
|
|
|
|
+bool
|
|
|
+efivar_variable_is_removable(efi_guid_t vendor, const char *var_name,
|
|
|
+ size_t len)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ bool found = false;
|
|
|
+ int match = 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Check if our variable is in the validated variables list
|
|
|
+ */
|
|
|
+ for (i = 0; variable_validate[i].name[0] != '\0'; i++) {
|
|
|
+ if (efi_guidcmp(variable_validate[i].vendor, vendor))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (variable_matches(var_name, len,
|
|
|
+ variable_validate[i].name, &match)) {
|
|
|
+ found = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If it's in our list, it is removable.
|
|
|
+ */
|
|
|
+ return found;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(efivar_variable_is_removable);
|
|
|
+
|
|
|
static efi_status_t
|
|
|
check_var_size(u32 attributes, unsigned long size)
|
|
|
{
|