* 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 | 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 | 198 | struct efi_generic_dev_path *node; |
| 198 | 199 | int offset = 0; |
| 199 | 200 | |
| 200 | 201 | node = (struct efi_generic_dev_path *)buffer; |
| 201 | 202 | |
| 202 | − while (offset < len) { | |
| 203 | − offset += node->length; | |
| 203 | + if (len < sizeof(*node)) | |
| 204 | + return false; | |
| 204 | 205 | |
| 205 | − if (offset > len) | |
| 206 | − return false; | |
| 206 | + while (offset <= len - sizeof(*node) && | |
| 207 | + node->length >= sizeof(*node) && | |
| 208 | + node->length <= len - offset) { | |
| 209 | + offset += node->length; | |
| 207 | 210 | |
| 208 | 211 | if ((node->type == EFI_DEV_END_PATH || |
| 209 | 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 | 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 | 231 | /* An array of 16-bit integers */ |
| 228 | 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 | 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 | 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 | 247 | /* Either "Boot" or "Driver" followed by four digits of hex */ |
| 241 | 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 | 251 | return true; |
| 244 | 252 | } |
| 245 | 253 | |
| 246 | − /* A valid entry must be at least 6 bytes */ | |
| 247 | − if (len < 6) | |
| 254 | + /* Reject it if there's 4 digits of hex and then further content */ | |
| 255 | + if (namelen > match + 4) | |
| 256 | + return false; | |
| 257 | + | |
| 258 | + /* A valid entry must be at least 8 bytes */ | |
| 259 | + if (len < 8) | |
| 248 | 260 | return false; |
| 249 | 261 | |
| 250 | 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 | 265 | * There's no stored length for the description, so it has to be |
| 254 | 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 | 270 | /* Each boot entry must have a descriptor */ |
| 259 | 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 | 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 | 293 | /* A single 16-bit integer */ |
| 281 | 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 | 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 | 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 | 317 | struct variable_validate { |
| 304 | 318 | char *name; |
| 305 | 319 | bool (*validate)(struct efi_variable *var, int match, u8 *data, |
| 306 | − int len); | |
| 320 | + unsigned long len); | |
| 307 | 321 | }; |
| 308 | 322 | |
| 309 | 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 | 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 | 344 | int i; |
| 331 | 345 | u16 *unicode_name = var->VariableName; |