diff options
-rw-r--r-- | drivers/firmware/efivars.c | 46 |
1 files changed, 30 insertions, 16 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 891e4674d29b..47408e802ab6 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c | |||
@@ -192,18 +192,21 @@ utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len) | |||
192 | } | 192 | } |
193 | 193 | ||
194 | static bool | 194 | static bool |
195 | validate_device_path(struct efi_variable *var, int match, u8 *buffer, int len) | 195 | validate_device_path(struct efi_variable *var, int match, u8 *buffer, |
196 | unsigned long len) | ||
196 | { | 197 | { |
197 | struct efi_generic_dev_path *node; | 198 | struct efi_generic_dev_path *node; |
198 | int offset = 0; | 199 | int offset = 0; |
199 | 200 | ||
200 | node = (struct efi_generic_dev_path *)buffer; | 201 | node = (struct efi_generic_dev_path *)buffer; |
201 | 202 | ||
202 | while (offset < len) { | 203 | if (len < sizeof(*node)) |
203 | offset += node->length; | 204 | return false; |
204 | 205 | ||
205 | if (offset > len) | 206 | while (offset <= len - sizeof(*node) && |
206 | return false; | 207 | node->length >= sizeof(*node) && |
208 | node->length <= len - offset) { | ||
209 | offset += node->length; | ||
207 | 210 | ||
208 | if ((node->type == EFI_DEV_END_PATH || | 211 | if ((node->type == EFI_DEV_END_PATH || |
209 | node->type == EFI_DEV_END_PATH2) && | 212 | node->type == EFI_DEV_END_PATH2) && |
@@ -222,7 +225,8 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer, int len) | |||
222 | } | 225 | } |
223 | 226 | ||
224 | static bool | 227 | static bool |
225 | validate_boot_order(struct efi_variable *var, int match, u8 *buffer, int len) | 228 | validate_boot_order(struct efi_variable *var, int match, u8 *buffer, |
229 | unsigned long len) | ||
226 | { | 230 | { |
227 | /* An array of 16-bit integers */ | 231 | /* An array of 16-bit integers */ |
228 | if ((len % 2) != 0) | 232 | if ((len % 2) != 0) |
@@ -232,19 +236,27 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer, int len) | |||
232 | } | 236 | } |
233 | 237 | ||
234 | static bool | 238 | static bool |
235 | validate_load_option(struct efi_variable *var, int match, u8 *buffer, int len) | 239 | validate_load_option(struct efi_variable *var, int match, u8 *buffer, |
240 | unsigned long len) | ||
236 | { | 241 | { |
237 | u16 filepathlength; | 242 | u16 filepathlength; |
238 | int i, desclength = 0; | 243 | int i, desclength = 0, namelen; |
244 | |||
245 | namelen = utf16_strnlen(var->VariableName, sizeof(var->VariableName)); | ||
239 | 246 | ||
240 | /* Either "Boot" or "Driver" followed by four digits of hex */ | 247 | /* Either "Boot" or "Driver" followed by four digits of hex */ |
241 | for (i = match; i < match+4; i++) { | 248 | for (i = match; i < match+4; i++) { |
242 | if (hex_to_bin(var->VariableName[i] & 0xff) < 0) | 249 | if (var->VariableName[i] > 127 || |
250 | hex_to_bin(var->VariableName[i] & 0xff) < 0) | ||
243 | return true; | 251 | return true; |
244 | } | 252 | } |
245 | 253 | ||
246 | /* A valid entry must be at least 6 bytes */ | 254 | /* Reject it if there's 4 digits of hex and then further content */ |
247 | if (len < 6) | 255 | if (namelen > match + 4) |
256 | return false; | ||
257 | |||
258 | /* A valid entry must be at least 8 bytes */ | ||
259 | if (len < 8) | ||
248 | return false; | 260 | return false; |
249 | 261 | ||
250 | filepathlength = buffer[4] | buffer[5] << 8; | 262 | filepathlength = buffer[4] | buffer[5] << 8; |
@@ -253,7 +265,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, int len) | |||
253 | * There's no stored length for the description, so it has to be | 265 | * There's no stored length for the description, so it has to be |
254 | * found by hand | 266 | * found by hand |
255 | */ | 267 | */ |
256 | desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len) + 2; | 268 | desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2; |
257 | 269 | ||
258 | /* Each boot entry must have a descriptor */ | 270 | /* Each boot entry must have a descriptor */ |
259 | if (!desclength) | 271 | if (!desclength) |
@@ -275,7 +287,8 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, int len) | |||
275 | } | 287 | } |
276 | 288 | ||
277 | static bool | 289 | static bool |
278 | validate_uint16(struct efi_variable *var, int match, u8 *buffer, int len) | 290 | validate_uint16(struct efi_variable *var, int match, u8 *buffer, |
291 | unsigned long len) | ||
279 | { | 292 | { |
280 | /* A single 16-bit integer */ | 293 | /* A single 16-bit integer */ |
281 | if (len != 2) | 294 | if (len != 2) |
@@ -285,7 +298,8 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer, int len) | |||
285 | } | 298 | } |
286 | 299 | ||
287 | static bool | 300 | static bool |
288 | validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, int len) | 301 | validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, |
302 | unsigned long len) | ||
289 | { | 303 | { |
290 | int i; | 304 | int i; |
291 | 305 | ||
@@ -303,7 +317,7 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, int len) | |||
303 | struct variable_validate { | 317 | struct variable_validate { |
304 | char *name; | 318 | char *name; |
305 | bool (*validate)(struct efi_variable *var, int match, u8 *data, | 319 | bool (*validate)(struct efi_variable *var, int match, u8 *data, |
306 | int len); | 320 | unsigned long len); |
307 | }; | 321 | }; |
308 | 322 | ||
309 | static const struct variable_validate variable_validate[] = { | 323 | static const struct variable_validate variable_validate[] = { |
@@ -325,7 +339,7 @@ static const struct variable_validate variable_validate[] = { | |||
325 | }; | 339 | }; |
326 | 340 | ||
327 | static bool | 341 | static bool |
328 | validate_var(struct efi_variable *var, u8 *data, int len) | 342 | validate_var(struct efi_variable *var, u8 *data, unsigned long len) |
329 | { | 343 | { |
330 | int i; | 344 | int i; |
331 | u16 *unicode_name = var->VariableName; | 345 | u16 *unicode_name = var->VariableName; |