* efi-vars: efivars: Improve variable validation
Unified · Split
| @@ -192,18 +192,21 @@ utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len) · 191 unmodified lines | |||
| 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) · 12 unmodified lines | |||
| 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) · 3 unmodified lines | |||
| 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) · 2 unmodified lines | |||
| 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) · 15 unmodified lines | |||
| 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) · 3 unmodified lines | |||
| 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) · 11 unmodified lines | |||
| 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[] = { · 15 unmodified lines | |||
| 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; |