|
|
5fb29d |
From 50ae3bd11b51f8e6cd86d4b4f2c8322a7036d095 Mon Sep 17 00:00:00 2001
|
|
|
5fb29d |
From: Lenny Szubowicz <lszubowi@redhat.com>
|
|
|
5fb29d |
Date: Tue, 6 Jan 2015 11:17:01 -0500
|
|
|
5fb29d |
Subject: [PATCH] Fix buffer overflow when remove_from_boot_order removes
|
|
|
5fb29d |
nothing
|
|
|
5fb29d |
|
|
|
5fb29d |
Deleting a boot entry via "-b xxxx -B" also attempts to remove
|
|
|
5fb29d |
that entry from boot order via a call to remove_from_boot_order.
|
|
|
5fb29d |
Although unusual, it's possible that the entry being deleted is
|
|
|
5fb29d |
not in boot order. Correct the handling of this case in
|
|
|
5fb29d |
remove_from_boot_order, which malloc's space for the new boot
|
|
|
5fb29d |
order list wrongly assuming that at least one entry will be
|
|
|
5fb29d |
removed. However, if no entry is removed, then 2 bytes are
|
|
|
5fb29d |
overwritten beyond the malloc'ed space. This can result in heap
|
|
|
5fb29d |
corruption and possible termination via a SIGABRT if the
|
|
|
5fb29d |
corruption is detected by the heap allocation routines.
|
|
|
5fb29d |
|
|
|
5fb29d |
While there, simplify the routine to do the removal of boot
|
|
|
5fb29d |
entries in place in the original data buffer, skip the
|
|
|
5fb29d |
unnecessary BootOrder variable update if nothing got removed,
|
|
|
5fb29d |
and free the malloc'ed boot_order struct on the way out.
|
|
|
5fb29d |
|
|
|
5fb29d |
Resolves: RH BZ 1168019
|
|
|
5fb29d |
|
|
|
5fb29d |
Signed-off-by: Lenny Szubowicz <lszubowi@redhat.com>
|
|
|
5fb29d |
---
|
|
|
5fb29d |
src/efibootmgr/efibootmgr.c | 33 +++++++++++++++------------------
|
|
|
5fb29d |
1 file changed, 15 insertions(+), 18 deletions(-)
|
|
|
5fb29d |
|
|
|
5fb29d |
diff --git a/src/efibootmgr/efibootmgr.c b/src/efibootmgr/efibootmgr.c
|
|
|
5fb29d |
index eb13942..1b55125 100644
|
|
|
5fb29d |
--- a/src/efibootmgr/efibootmgr.c
|
|
|
5fb29d |
+++ b/src/efibootmgr/efibootmgr.c
|
|
|
5fb29d |
@@ -429,8 +429,7 @@ static int
|
|
|
5fb29d |
remove_from_boot_order(uint16_t num)
|
|
|
5fb29d |
{
|
|
|
5fb29d |
efi_variable_t *boot_order = NULL;
|
|
|
5fb29d |
- uint64_t new_data_size;
|
|
|
5fb29d |
- uint16_t *new_data, *old_data;
|
|
|
5fb29d |
+ uint16_t *data;
|
|
|
5fb29d |
unsigned int old_i,new_i;
|
|
|
5fb29d |
int rc;
|
|
|
5fb29d |
|
|
|
5fb29d |
@@ -442,34 +441,32 @@ remove_from_boot_order(uint16_t num)
|
|
|
5fb29d |
}
|
|
|
5fb29d |
|
|
|
5fb29d |
/* We've now got an array (in boot_order->data) of the
|
|
|
5fb29d |
- boot order. Simply copy the array, skipping the
|
|
|
5fb29d |
- entry we're deleting.
|
|
|
5fb29d |
+ boot order. Squeeze out any instance of the entry we're
|
|
|
5fb29d |
+ deleting by shifting the remainder down.
|
|
|
5fb29d |
*/
|
|
|
5fb29d |
- old_data = (uint16_t *)(boot_order->data);
|
|
|
5fb29d |
- /* Start with the same size */
|
|
|
5fb29d |
- new_data_size = boot_order->data_size - sizeof (*new_data);
|
|
|
5fb29d |
- new_data = malloc(new_data_size);
|
|
|
5fb29d |
- if (!new_data)
|
|
|
5fb29d |
- return -1;
|
|
|
5fb29d |
+ data = (uint16_t *)(boot_order->data);
|
|
|
5fb29d |
|
|
|
5fb29d |
for (old_i=0,new_i=0;
|
|
|
5fb29d |
- old_i < boot_order->data_size / sizeof(*new_data);
|
|
|
5fb29d |
+ old_i < boot_order->data_size / sizeof(data[0]);
|
|
|
5fb29d |
old_i++) {
|
|
|
5fb29d |
- if (old_data[old_i] != num) {
|
|
|
5fb29d |
- /* Copy this value */
|
|
|
5fb29d |
- new_data[new_i] = old_data[old_i];
|
|
|
5fb29d |
+ if (data[old_i] != num) {
|
|
|
5fb29d |
+ if (new_i != old_i)
|
|
|
5fb29d |
+ data[new_i] = data[old_i];
|
|
|
5fb29d |
new_i++;
|
|
|
5fb29d |
}
|
|
|
5fb29d |
}
|
|
|
5fb29d |
|
|
|
5fb29d |
- /* Now new_data has what we need */
|
|
|
5fb29d |
- free(boot_order->data);
|
|
|
5fb29d |
- boot_order->data = (uint8_t *)new_data;
|
|
|
5fb29d |
- boot_order->data_size = new_data_size;
|
|
|
5fb29d |
+ /* If nothing removed, no need to update the BootOrder variable */
|
|
|
5fb29d |
+ if (new_i == old_i)
|
|
|
5fb29d |
+ goto all_done;
|
|
|
5fb29d |
+
|
|
|
5fb29d |
+ /* BootOrder variable needs to be updated */
|
|
|
5fb29d |
efi_del_variable(EFI_GLOBAL_GUID, "BootOrder");
|
|
|
5fb29d |
rc = efi_set_variable(EFI_GLOBAL_GUID, "BootOrder", boot_order->data,
|
|
|
5fb29d |
boot_order->data_size, boot_order->attributes);
|
|
|
5fb29d |
+all_done:
|
|
|
5fb29d |
free(boot_order->data);
|
|
|
5fb29d |
+ free(boot_order);
|
|
|
5fb29d |
return rc;
|
|
|
5fb29d |
}
|
|
|
5fb29d |
|
|
|
5fb29d |
--
|
|
|
5fb29d |
2.1.0
|
|
|
5fb29d |
|