Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 20 Mar 2018 13:35:20 +0000 (UTC)
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r331241 - head/sys/dev/efidev
Message-ID:  <201803201335.w2KDZKs1029315@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: andrew
Date: Tue Mar 20 13:35:20 2018
New Revision: 331241
URL: https://svnweb.freebsd.org/changeset/base/331241

Log:
  Check if the gettime runtime service is valid.
  
  The U-Boot efi runtime service expects us to set the address map before
  calling any runtime services. It will then remap a few functions to their
  runtime version. One of these is the gettime function. If we call into
  this without having set a runtime map we get a page fault.
  
  Add a check to see if this is valid in efi_init() so we don't try to use
  the possibly invalid pointer.
  
  Reviewed by:	imp, kevans (both previous version)
  X-MFC-With:	r330868
  Sponsored by:	DARPA, AFRL
  Differential Revision:	https://reviews.freebsd.org/D14759

Modified:
  head/sys/dev/efidev/efirt.c

Modified: head/sys/dev/efidev/efirt.c
==============================================================================
--- head/sys/dev/efidev/efirt.c	Tue Mar 20 13:14:10 2018	(r331240)
+++ head/sys/dev/efidev/efirt.c	Tue Mar 20 13:35:20 2018	(r331241)
@@ -99,6 +99,25 @@ efi_status_to_errno(efi_status status)
 
 static struct mtx efi_lock;
 
+static bool
+efi_is_in_map(struct efi_md *map, int ndesc, int descsz, vm_offset_t addr)
+{
+	struct efi_md *p;
+	int i;
+
+	for (i = 0, p = map; i < ndesc; i++, p = efi_next_descriptor(p,
+	    descsz)) {
+		if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
+			continue;
+
+		if (addr >= (uintptr_t)p->md_virt &&
+		    addr < (uintptr_t)p->md_virt + p->md_pages * PAGE_SIZE)
+			return (true);
+	}
+
+	return (false);
+}
+
 static int
 efi_init(void)
 {
@@ -160,6 +179,24 @@ efi_init(void)
 	if (efi_runtime == NULL) {
 		if (bootverbose)
 			printf("EFI runtime services table is not present\n");
+		efi_destroy_1t1_map();
+		return (ENXIO);
+	}
+
+	/*
+	 * Some UEFI implementations have multiple implementations of the
+	 * RS->GetTime function. They switch from one we can only use early
+	 * in the boot process to one valid as a RunTime service only when we
+	 * call RS->SetVirtualAddressMap. As this is not always the case, e.g.
+	 * with an old loader.efi, check if the RS->GetTime function is within
+	 * the EFI map, and fail to attach if not.
+	 */
+	if (!efi_is_in_map(map, efihdr->memory_size / efihdr->descriptor_size,
+	    efihdr->descriptor_size, (vm_offset_t)efi_runtime->rt_gettime)) {
+		if (bootverbose)
+			printf(
+			 "EFI runtime services table has an invalid pointer\n");
+		efi_runtime = NULL;
 		efi_destroy_1t1_map();
 		return (ENXIO);
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201803201335.w2KDZKs1029315>