--- a/sys/dev/misc/efirt/efidev.c +++ b/sys/dev/misc/efirt/efidev.c @@ -39,6 +39,22 @@ #include #include +/* + * DF-5119: sanity limits for user-supplied buffer sizes. + * + * efi_var_ioc::datasize / ::namesize come straight from the ioctl and + * were passed unvalidated to kmalloc(M_WAITOK). Huge sizes panic the + * kernel ("kmem_slab_alloc(): kernel_map ran out of space!") and sizes + * near SIZE_MAX wrap round_page() down to 0, producing a zero-length + * kernel_map entry (duplicate-address map corruption) and a pointer that + * kfree() misclassifies as a slab-zone chunk. Real EFI variables are + * orders of magnitude smaller (UEFI firmware typically caps them at + * 64KB), so cap requests at 1 MiB (matching Linux efivarfs) and require + * a name buffer big enough to hold at least the NUL terminator. + */ +#define EFI_IOC_MAX_DATA (1024 * 1024) +#define EFI_IOC_MAX_NAME (1024 * 1024) + static struct lock efidev_lock = LOCK_INITIALIZER("efidev", 0, 0); static d_ioctl_t efidev_ioctl; @@ -102,6 +118,12 @@ void *data; efi_char *name; + if (ev->datasize > EFI_IOC_MAX_DATA || + ev->namesize < sizeof(efi_char) || + ev->namesize > EFI_IOC_MAX_NAME) { + error = EINVAL; + break; + } data = kmalloc(ev->datasize, M_TEMP, M_WAITOK); name = kmalloc(ev->namesize, M_TEMP, M_WAITOK); error = copyin(ev->name, name, ev->namesize); @@ -137,6 +159,11 @@ struct efi_var_ioc *ev = (struct efi_var_ioc *)addr; efi_char *name; + if (ev->namesize < sizeof(efi_char) || + ev->namesize > EFI_IOC_MAX_NAME) { + error = EINVAL; + break; + } name = kmalloc(ev->namesize, M_TEMP, M_WAITOK); error = copyin(ev->name, name, ev->namesize); if (error) @@ -160,6 +187,12 @@ void *data = NULL; efi_char *name; + if (ev->datasize > EFI_IOC_MAX_DATA || + ev->namesize < sizeof(efi_char) || + ev->namesize > EFI_IOC_MAX_NAME) { + error = EINVAL; + break; + } /* datasize == 0 -> delete (more or less) */ if (ev->datasize > 0) data = kmalloc(ev->datasize, M_TEMP, M_WAITOK);