e820: properly reserve memory for multiboot modules

In current implementation, if there are multiple continous 4k-aligned
modules, 0-sized e820 entries will be created between these regions.
And for non-4k-aligned modules, when two of them are located in one
page, the second memory range will not be reserved as it was not in
one e820 entry after the first is reserved, making it vulnerable.

This patch fixes it by marking the exact memory range of multiboot
modules as unusable first, then shrinking the e820 entries to page
boundary. If the module crosses multiple e820 entries, possibly due
to a buggy bootloader, hypervisor will panic immediately to prevent
modules getting corrupted.

Tracked-On: #8617
Signed-off-by: Jiaqing Zhao <jiaqing.zhao@linux.intel.com>
Reviewed-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
Jiaqing Zhao 2024-05-30 07:43:56 +00:00 committed by acrnsi-robot
parent b31fcd3519
commit 53825c5cac
1 changed files with 48 additions and 42 deletions

View File

@ -119,43 +119,6 @@ static void insert_e820_entry(uint32_t index, uint64_t addr, uint64_t length, ui
hv_e820[index].type = type;
}
static uint64_t e820_alloc_region(uint64_t addr, uint64_t size)
{
uint32_t i;
uint64_t entry_start;
uint64_t entry_end;
uint64_t start_pa = round_page_down(addr);
uint64_t end_pa = round_page_up(addr + size);
struct e820_entry *entry;
for (i = 0U; i < hv_e820_entries_nr; i++) {
entry = &hv_e820[i];
entry_start = entry->baseaddr;
entry_end = entry->baseaddr + entry->length;
/* No need handle in these cases*/
if ((entry->type != E820_TYPE_RAM) || (entry_end <= start_pa) || (entry_start >= end_pa)) {
continue;
}
if ((entry_start <= start_pa) && (entry_end >= end_pa)) {
entry->length = start_pa - entry_start;
/*
* .......|start_pa... ....................End_pa|.....
* |entry_start..............................entry_end|
*/
if (end_pa < entry_end) {
insert_e820_entry(i + 1, end_pa, entry_end - end_pa, E820_TYPE_RAM);
break;
}
} else {
pr_err("This region not in one entry!");
}
}
return addr;
}
static void init_e820_from_efi_mmap(void)
{
uint32_t i, e820_idx = 0U;
@ -271,14 +234,57 @@ static void calculate_e820_ram_size(void)
static void alloc_mods_memory(void)
{
uint32_t i;
int64_t mod_start = 0UL;
uint32_t mod_index, e820_index, target_index;
uint64_t mod_start, mod_end;
uint64_t entry_start, entry_end;
struct acrn_boot_info *abi = get_acrn_boot_info();
for (i = 0; i < abi->mods_count; i++) {
mod_start = hva2hpa(abi->mods[i].start);
e820_alloc_region(mod_start, abi->mods[i].size);
/* 1st pass: remove the exact region */
for (mod_index = 0; mod_index < abi->mods_count; mod_index++) {
mod_start = hva2hpa(abi->mods[mod_index].start);
mod_end = hva2hpa(abi->mods[mod_index].start) + abi->mods[mod_index].size;
for (e820_index = 0; e820_index < hv_e820_entries_nr; e820_index++) {
entry_start = hv_e820[e820_index].baseaddr;
entry_end = hv_e820[e820_index].baseaddr + hv_e820[e820_index].length;
/* No need handle in these cases*/
if ((hv_e820[e820_index].type != E820_TYPE_RAM) || (entry_end <= mod_start) || (entry_start >= mod_end)) {
continue;
}
if ((entry_start <= mod_start) && (entry_end >= mod_end)) {
hv_e820[e820_index].length = mod_start - entry_start;
if (mod_end < entry_end) {
/*
* .......|start_pa... ....................end_pa|.....
* |entry_start..............................entry_end|
*/
insert_e820_entry(e820_index + 1, mod_end, entry_end - mod_end, E820_TYPE_RAM);
}
} else {
panic("%s: region 0x%016x-0x%016x crosses multiple e820 entries, check your bootloader!",
__func__, entry_start, entry_end);
}
}
}
/* 2nd pass: shrink the entries to page boundary */
target_index = 0;
for (e820_index = 0; e820_index < hv_e820_entries_nr; e820_index++) {
entry_start = round_page_up(hv_e820[e820_index].baseaddr);
entry_end = round_page_down(hv_e820[e820_index].baseaddr + hv_e820[e820_index].length);
if (entry_start < entry_end) {
hv_e820[target_index].baseaddr = entry_start;
hv_e820[target_index].length = entry_end - entry_start;
hv_e820[target_index].type = hv_e820[e820_index].type;
target_index++;
}
}
memset(&hv_e820[target_index], 0, (hv_e820_entries_nr - target_index) * sizeof(struct e820_entry));
hv_e820_entries_nr = target_index;
}