drivers/linux: enforce address requirement for IOCTL_ALLOC_PHYSMEM

Try harder to fulfill the physical address constraint for the
IOCTL_ALLOC_PHYSMEM ioctl by trying to allocate memory from the zones
that fit the maximum address best, but fall-back to the normal zone in
case the allocation fails.

If we fail to allocate memory that fulfills the maximum physical address
constraint, make the ioctl() fail as well instead of emitting a warning.

This is safer then making, e.g., the tools.smm.smm_ptr module corrupt
unrelated memory just because the allocation happens to be above 4GB but
the pointer passed to SMM is truncated to 32 bit.

Signed-off-by: Mathias Krause <minipli@grsecurity.net>
This commit is contained in:
Mathias Krause
2022-02-24 16:15:43 +01:00
committed by Nathaniel Mitchell
parent b7cbbd2712
commit 81fa32bd7e
+22 -15
View File
@@ -1173,7 +1173,7 @@ static long d_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioc
//IN params: size
//OUT params: physical address
uint32_t NumberOfBytes = 0;
void *va;
void *va = NULL;
phys_addr_t pa, max_pa;
struct allocated_mem_list *tmp = NULL;
@@ -1186,21 +1186,28 @@ static long d_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioc
NumberOfBytes = ptr[0];
max_pa = ptr[1];
va = kmalloc(NumberOfBytes, GFP_KERNEL );
if( !va )
{
printk(KERN_ALERT "[chipsec] ERROR: STATUS_UNSUCCESSFUL - could not allocate memory\n" );
return -ENOMEM;
}
memset(va, 0, NumberOfBytes);
pa = virt_to_phys(va);
if (pa > max_pa)
{
printk(KERN_ALERT "[chipsec] WARNING: allocated memory (0x%llx) is not below max_pa (0x%llx) (ignoring)", pa, max_pa);
}
if (max_pa <= U32_MAX) {
if (max_pa > 16 * 1024 * 1024)
va = kmalloc(NumberOfBytes, GFP_KERNEL | GFP_DMA32);
if (!va)
va = kmalloc(NumberOfBytes, GFP_KERNEL | GFP_DMA);
}
if (!va)
va = kmalloc(NumberOfBytes, GFP_KERNEL);
if (!va) {
printk(KERN_ALERT "[chipsec] ERROR: STATUS_UNSUCCESSFUL - could not allocate memory\n" );
return -ENOMEM;
}
pa = virt_to_phys(va);
if (pa > max_pa) {
printk(KERN_ALERT "[chipsec] ERROR: allocated memory (0x%llx) is not below max_pa (0x%llx)", pa, max_pa);
kfree(va);
return -ENOMEM;
}
memset(va, 0, NumberOfBytes);
tmp = kmalloc(sizeof(struct allocated_mem_list), GFP_KERNEL);
if (tmp == NULL) {