Blame SOURCES/0001-Fix-buffer-overflow-when-remove_from_boot_order-remo.patch

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