Browse Source

Merge tag 'efi-2021-01-rc5-2' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi

Pull request for UEFI sub-system for efi-2021-01-rc5 (2)

The following errors in the UEFI sub-system are fixed:

* use after free in efi_exit()
* invalid free when using the boot manager
* pressing escape key once not recognized
Tom Rini 3 years ago
parent
commit
21e1cae790
4 changed files with 33 additions and 12 deletions
  1. 5 3
      include/efi_loader.h
  2. 1 1
      lib/efi_loader/efi_bootmgr.c
  3. 15 8
      lib/efi_loader/efi_boottime.c
  4. 12 0
      lib/efi_loader/efi_console.c

+ 5 - 3
include/efi_loader.h

@@ -297,15 +297,17 @@ enum efi_image_auth_status {
  * @exit_status:	exit status passed to Exit()
  * @exit_data_size:	exit data size passed to Exit()
  * @exit_data:		exit data passed to Exit()
- * @exit_jmp:		long jump buffer for returning form started image
+ * @exit_jmp:		long jump buffer for returning from started image
  * @entry:		entry address of the relocated image
+ * @image_type:		indicates if the image is an applicition or a driver
+ * @auth_status:	indicates if the image is authenticated
  */
 struct efi_loaded_image_obj {
 	struct efi_object header;
-	efi_status_t exit_status;
+	efi_status_t *exit_status;
 	efi_uintn_t *exit_data_size;
 	u16 **exit_data;
-	struct jmp_buf_data exit_jmp;
+	struct jmp_buf_data *exit_jmp;
 	EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
 				     struct efi_system_table *st);
 	u16 image_type;

+ 1 - 1
lib/efi_loader/efi_bootmgr.c

@@ -275,7 +275,7 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle,
 		memcpy(*load_options, lo.optional_data, size);
 		ret = efi_set_load_options(*handle, size, *load_options);
 	} else {
-		load_options = NULL;
+		*load_options = NULL;
 	}
 
 error:

+ 15 - 8
lib/efi_loader/efi_boottime.c

@@ -271,8 +271,8 @@ efi_status_t is_valid_tpl(efi_uintn_t tpl)
  * efi_signal_event() - signal an EFI event
  * @event:     event to signal
  *
- * This function signals an event. If the event belongs to an event group all
- * events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL
+ * This function signals an event. If the event belongs to an event group, all
+ * events of the group are signaled. If they are of type EVT_NOTIFY_SIGNAL,
  * their notification function is queued.
  *
  * For the SignalEvent service see efi_signal_event_ext.
@@ -2000,7 +2000,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
 	}
 
 	if (!efi_st_keep_devices) {
-		if IS_ENABLED(CONFIG_USB_DEVICE)
+		if (IS_ENABLED(CONFIG_USB_DEVICE))
 			udc_disconnect();
 		board_quiesce_devices();
 		dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
@@ -2899,6 +2899,8 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
 	efi_status_t ret;
 	void *info;
 	efi_handle_t parent_image = current_image;
+	efi_status_t exit_status;
+	struct jmp_buf_data exit_jmp;
 
 	EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
 
@@ -2920,9 +2922,11 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
 
 	image_obj->exit_data_size = exit_data_size;
 	image_obj->exit_data = exit_data;
+	image_obj->exit_status = &exit_status;
+	image_obj->exit_jmp = &exit_jmp;
 
 	/* call the image! */
-	if (setjmp(&image_obj->exit_jmp)) {
+	if (setjmp(&exit_jmp)) {
 		/*
 		 * We called the entry point of the child image with EFI_CALL
 		 * in the lines below. The child image called the Exit() boot
@@ -2944,10 +2948,10 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle,
 		 */
 		assert(__efi_entry_check());
 		EFI_PRINT("%lu returned by started image\n",
-			  (unsigned long)((uintptr_t)image_obj->exit_status &
+			  (unsigned long)((uintptr_t)exit_status &
 			  ~EFI_ERROR_MASK));
 		current_image = parent_image;
-		return EFI_EXIT(image_obj->exit_status);
+		return EFI_EXIT(exit_status);
 	}
 
 	current_image = image_handle;
@@ -3130,6 +3134,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
 	struct efi_loaded_image *loaded_image_protocol;
 	struct efi_loaded_image_obj *image_obj =
 		(struct efi_loaded_image_obj *)image_handle;
+	struct jmp_buf_data *exit_jmp;
 
 	EFI_ENTRY("%p, %ld, %zu, %p", image_handle, exit_status,
 		  exit_data_size, exit_data);
@@ -3171,6 +3176,9 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
 		if (ret != EFI_SUCCESS)
 			EFI_PRINT("%s: out of memory\n", __func__);
 	}
+	/* efi_delete_image() frees image_obj. Copy before the call. */
+	exit_jmp = image_obj->exit_jmp;
+	*image_obj->exit_status = exit_status;
 	if (image_obj->image_type == IMAGE_SUBSYSTEM_EFI_APPLICATION ||
 	    exit_status != EFI_SUCCESS)
 		efi_delete_image(image_obj, loaded_image_protocol);
@@ -3184,8 +3192,7 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle,
 	 */
 	efi_restore_gd();
 
-	image_obj->exit_status = exit_status;
-	longjmp(&image_obj->exit_jmp, 1);
+	longjmp(exit_jmp, 1);
 
 	panic("EFI application exited");
 out:

+ 12 - 0
lib/efi_loader/efi_console.c

@@ -14,6 +14,7 @@
 #include <env.h>
 #include <stdio_dev.h>
 #include <video_console.h>
+#include <linux/delay.h>
 
 #define EFI_COUT_MODE_2 2
 #define EFI_MAX_COUT_MODE 3
@@ -688,6 +689,17 @@ static efi_status_t efi_cin_read_key(struct efi_key_data *key)
 
 	switch (ch) {
 	case 0x1b:
+		/*
+		 * If a second key is received within 10 ms, assume that we are
+		 * dealing with an escape sequence. Otherwise consider this the
+		 * escape key being hit. 10 ms is long enough to work fine at
+		 * 1200 baud and above.
+		 */
+		udelay(10000);
+		if (!tstc()) {
+			pressed_key.scan_code = 23;
+			break;
+		}
 		/*
 		 * Xterm Control Sequences
 		 * https://www.xfree86.org/4.8.0/ctlseqs.html