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);
        }
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to