mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
efivars: Improve variable validation
commit 54b3a4d311 upstream.
Ben Hutchings pointed out that the validation in efivars was inadequate -
most obviously, an entry with size 0 would server as a DoS against the
kernel. Improve this based on his suggestions.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
173c412ef8
commit
ecc53109a0
|
|
@ -167,18 +167,21 @@ utf16_strsize(efi_char16_t *data, unsigned long maxlength)
|
|||
}
|
||||
|
||||
static bool
|
||||
validate_device_path(struct efi_variable *var, int match, u8 *buffer, int len)
|
||||
validate_device_path(struct efi_variable *var, int match, u8 *buffer,
|
||||
unsigned long len)
|
||||
{
|
||||
struct efi_generic_dev_path *node;
|
||||
int offset = 0;
|
||||
|
||||
node = (struct efi_generic_dev_path *)buffer;
|
||||
|
||||
while (offset < len) {
|
||||
offset += node->length;
|
||||
if (len < sizeof(*node))
|
||||
return false;
|
||||
|
||||
if (offset > len)
|
||||
return false;
|
||||
while (offset <= len - sizeof(*node) &&
|
||||
node->length >= sizeof(*node) &&
|
||||
node->length <= len - offset) {
|
||||
offset += node->length;
|
||||
|
||||
if ((node->type == EFI_DEV_END_PATH ||
|
||||
node->type == EFI_DEV_END_PATH2) &&
|
||||
|
|
@ -197,7 +200,8 @@ validate_device_path(struct efi_variable *var, int match, u8 *buffer, int len)
|
|||
}
|
||||
|
||||
static bool
|
||||
validate_boot_order(struct efi_variable *var, int match, u8 *buffer, int len)
|
||||
validate_boot_order(struct efi_variable *var, int match, u8 *buffer,
|
||||
unsigned long len)
|
||||
{
|
||||
/* An array of 16-bit integers */
|
||||
if ((len % 2) != 0)
|
||||
|
|
@ -207,19 +211,27 @@ validate_boot_order(struct efi_variable *var, int match, u8 *buffer, int len)
|
|||
}
|
||||
|
||||
static bool
|
||||
validate_load_option(struct efi_variable *var, int match, u8 *buffer, int len)
|
||||
validate_load_option(struct efi_variable *var, int match, u8 *buffer,
|
||||
unsigned long len)
|
||||
{
|
||||
u16 filepathlength;
|
||||
int i, desclength = 0;
|
||||
int i, desclength = 0, namelen;
|
||||
|
||||
namelen = utf16_strnlen(var->VariableName, sizeof(var->VariableName));
|
||||
|
||||
/* Either "Boot" or "Driver" followed by four digits of hex */
|
||||
for (i = match; i < match+4; i++) {
|
||||
if (hex_to_bin(var->VariableName[i] & 0xff) < 0)
|
||||
if (var->VariableName[i] > 127 ||
|
||||
hex_to_bin(var->VariableName[i] & 0xff) < 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* A valid entry must be at least 6 bytes */
|
||||
if (len < 6)
|
||||
/* Reject it if there's 4 digits of hex and then further content */
|
||||
if (namelen > match + 4)
|
||||
return false;
|
||||
|
||||
/* A valid entry must be at least 8 bytes */
|
||||
if (len < 8)
|
||||
return false;
|
||||
|
||||
filepathlength = buffer[4] | buffer[5] << 8;
|
||||
|
|
@ -228,7 +240,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, int len)
|
|||
* There's no stored length for the description, so it has to be
|
||||
* found by hand
|
||||
*/
|
||||
desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len) + 2;
|
||||
desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2;
|
||||
|
||||
/* Each boot entry must have a descriptor */
|
||||
if (!desclength)
|
||||
|
|
@ -250,7 +262,8 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, int len)
|
|||
}
|
||||
|
||||
static bool
|
||||
validate_uint16(struct efi_variable *var, int match, u8 *buffer, int len)
|
||||
validate_uint16(struct efi_variable *var, int match, u8 *buffer,
|
||||
unsigned long len)
|
||||
{
|
||||
/* A single 16-bit integer */
|
||||
if (len != 2)
|
||||
|
|
@ -260,7 +273,8 @@ validate_uint16(struct efi_variable *var, int match, u8 *buffer, int len)
|
|||
}
|
||||
|
||||
static bool
|
||||
validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, int len)
|
||||
validate_ascii_string(struct efi_variable *var, int match, u8 *buffer,
|
||||
unsigned long len)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -278,7 +292,7 @@ validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, int len)
|
|||
struct variable_validate {
|
||||
char *name;
|
||||
bool (*validate)(struct efi_variable *var, int match, u8 *data,
|
||||
int len);
|
||||
unsigned long len);
|
||||
};
|
||||
|
||||
static const struct variable_validate variable_validate[] = {
|
||||
|
|
@ -300,7 +314,7 @@ static const struct variable_validate variable_validate[] = {
|
|||
};
|
||||
|
||||
static bool
|
||||
validate_var(struct efi_variable *var, u8 *data, int len)
|
||||
validate_var(struct efi_variable *var, u8 *data, unsigned long len)
|
||||
{
|
||||
int i;
|
||||
u16 *unicode_name = var->VariableName;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user