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
This commit is contained in:
Andrew Turner 2018-03-20 13:35:20 +00:00
parent 400326b667
commit ed4c884f2e

View File

@ -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)
{
@ -164,6 +183,24 @@ efi_init(void)
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);
}
return (0);
}