diff options
Diffstat (limited to 'drivers/firmware/efi/vars.c')
-rw-r--r-- | drivers/firmware/efi/vars.c | 87 |
1 files changed, 64 insertions, 23 deletions
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 9a53da21e7b6..50f10bad2604 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c | |||
@@ -172,10 +172,12 @@ struct variable_validate { | |||
172 | }; | 172 | }; |
173 | 173 | ||
174 | /* | 174 | /* |
175 | * This is the list of variables we need to validate. | 175 | * This is the list of variables we need to validate, as well as the |
176 | * whitelist for what we think is safe not to default to immutable. | ||
176 | * | 177 | * |
177 | * If it has a validate() method that's not NULL, it'll go into the | 178 | * If it has a validate() method that's not NULL, it'll go into the |
178 | * validation routine. If not, it is assumed valid. | 179 | * validation routine. If not, it is assumed valid, but still used for |
180 | * whitelisting. | ||
179 | * | 181 | * |
180 | * Note that it's sorted by {vendor,name}, but globbed names must come after | 182 | * Note that it's sorted by {vendor,name}, but globbed names must come after |
181 | * any other name with the same prefix. | 183 | * any other name with the same prefix. |
@@ -193,11 +195,37 @@ static const struct variable_validate variable_validate[] = { | |||
193 | { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path }, | 195 | { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path }, |
194 | { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path }, | 196 | { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path }, |
195 | { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string }, | 197 | { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string }, |
198 | { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL }, | ||
196 | { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string }, | 199 | { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string }, |
197 | { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 }, | 200 | { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 }, |
198 | { NULL_GUID, "", NULL }, | 201 | { NULL_GUID, "", NULL }, |
199 | }; | 202 | }; |
200 | 203 | ||
204 | static bool | ||
205 | variable_matches(const char *var_name, size_t len, const char *match_name, | ||
206 | int *match) | ||
207 | { | ||
208 | for (*match = 0; ; (*match)++) { | ||
209 | char c = match_name[*match]; | ||
210 | char u = var_name[*match]; | ||
211 | |||
212 | /* Wildcard in the matching name means we've matched */ | ||
213 | if (c == '*') | ||
214 | return true; | ||
215 | |||
216 | /* Case sensitive match */ | ||
217 | if (!c && *match == len) | ||
218 | return true; | ||
219 | |||
220 | if (c != u) | ||
221 | return false; | ||
222 | |||
223 | if (!c) | ||
224 | return true; | ||
225 | } | ||
226 | return true; | ||
227 | } | ||
228 | |||
201 | bool | 229 | bool |
202 | efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, | 230 | efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, |
203 | unsigned long data_size) | 231 | unsigned long data_size) |
@@ -221,35 +249,48 @@ efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, | |||
221 | if (efi_guidcmp(vendor, variable_validate[i].vendor)) | 249 | if (efi_guidcmp(vendor, variable_validate[i].vendor)) |
222 | continue; | 250 | continue; |
223 | 251 | ||
224 | for (match = 0; ; match++) { | 252 | if (variable_matches(utf8_name, utf8_size+1, name, &match)) { |
225 | char c = name[match]; | 253 | if (variable_validate[i].validate == NULL) |
226 | char u = utf8_name[match]; | ||
227 | |||
228 | /* Wildcard in the matching name means we've matched */ | ||
229 | if (c == '*') { | ||
230 | kfree(utf8_name); | ||
231 | return variable_validate[i].validate(var_name, | ||
232 | match, data, data_size); | ||
233 | } | ||
234 | |||
235 | /* Case sensitive match */ | ||
236 | if (c != u) | ||
237 | break; | 254 | break; |
238 | 255 | kfree(utf8_name); | |
239 | /* Reached the end of the string while matching */ | 256 | return variable_validate[i].validate(var_name, match, |
240 | if (!c) { | 257 | data, data_size); |
241 | kfree(utf8_name); | ||
242 | return variable_validate[i].validate(var_name, | ||
243 | match, data, data_size); | ||
244 | } | ||
245 | } | 258 | } |
246 | } | 259 | } |
247 | |||
248 | kfree(utf8_name); | 260 | kfree(utf8_name); |
249 | return true; | 261 | return true; |
250 | } | 262 | } |
251 | EXPORT_SYMBOL_GPL(efivar_validate); | 263 | EXPORT_SYMBOL_GPL(efivar_validate); |
252 | 264 | ||
265 | bool | ||
266 | efivar_variable_is_removable(efi_guid_t vendor, const char *var_name, | ||
267 | size_t len) | ||
268 | { | ||
269 | int i; | ||
270 | bool found = false; | ||
271 | int match = 0; | ||
272 | |||
273 | /* | ||
274 | * Check if our variable is in the validated variables list | ||
275 | */ | ||
276 | for (i = 0; variable_validate[i].name[0] != '\0'; i++) { | ||
277 | if (efi_guidcmp(variable_validate[i].vendor, vendor)) | ||
278 | continue; | ||
279 | |||
280 | if (variable_matches(var_name, len, | ||
281 | variable_validate[i].name, &match)) { | ||
282 | found = true; | ||
283 | break; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * If it's in our list, it is removable. | ||
289 | */ | ||
290 | return found; | ||
291 | } | ||
292 | EXPORT_SYMBOL_GPL(efivar_variable_is_removable); | ||
293 | |||
253 | static efi_status_t | 294 | static efi_status_t |
254 | check_var_size(u32 attributes, unsigned long size) | 295 | check_var_size(u32 attributes, unsigned long size) |
255 | { | 296 | { |