Skip to content

Commit 6e0dfea

Browse files
executor: add boot arguments page to SYZOS layout
Introduce a dedicated page at X86_SYZOS_ADDR_BOOT_ARGS to pass configuration data from the executor to the SYZOS guest. This will allow dynamic adjustments to the guest environment, such as specifying memory region sizes. - Added `MEM_REGION_FLAG_REMAINING` to flag the last memory region, which will consume the rest of the available guest memory. - Defined `struct syzos_boot_args` to pass the memory region layout to the guest. - Modified `syzos_mem_regions`: - Reduced X86_SYZOS_ADDR_VAR_IDT size to 10 pages. - Inserted the new X86_SYZOS_ADDR_BOOT_ARGS region. - Added a final region with MEM_REGION_FLAG_REMAINING. - Updated `setup_vm` to: - Calculate the size of the REMAINING region. - Populate the `syzos_boot_args` structure in the boot args page. - Updated `setup_pg_table` to use the REMAINING flag to map the last region.
1 parent ef19d98 commit 6e0dfea

File tree

2 files changed

+52
-13
lines changed

2 files changed

+52
-13
lines changed

executor/common_kvm_amd64.h

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -213,19 +213,28 @@ static void setup_64bit_idt(struct kvm_sregs* sregs, char* host_mem, uintptr_t g
213213
#define MEM_REGION_FLAG_EXECUTOR_CODE (1 << 3)
214214
#define MEM_REGION_FLAG_GPA0 (1 << 5)
215215
#define MEM_REGION_FLAG_NO_HOST_MEM (1 << 6)
216+
#define MEM_REGION_FLAG_REMAINING (1 << 7)
216217

217218
struct mem_region {
218219
uint64 gpa;
219220
int pages;
220221
uint32 flags;
221222
};
222223

224+
struct syzos_boot_args {
225+
uint32 region_count;
226+
uint32 reserved;
227+
struct mem_region regions[];
228+
};
229+
223230
// SYZOS guest virtual memory layout (must be in sync with executor/kvm.h):
224231
static const struct mem_region syzos_mem_regions[] = {
225232
// AMD64 fixed data structures (5 pages: Zero, GDT, PML4, PDP, PD).
226233
{X86_SYZOS_ADDR_ZERO, 5, MEM_REGION_FLAG_GPA0},
227-
// High fixed data (IDT, TSS).
228-
{X86_SYZOS_ADDR_VAR_IDT, 11, 0},
234+
// High fixed data (IDT, TSS). Reduced to 10 pages to make room for Boot Args.
235+
{X86_SYZOS_ADDR_VAR_IDT, 10, 0},
236+
// Boot Configuration Page.
237+
{X86_SYZOS_ADDR_BOOT_ARGS, 1, 0},
229238
// Dynamic Page Table Pool.
230239
{X86_SYZOS_ADDR_PT_POOL, X86_SYZOS_PT_POOL_SIZE, 0},
231240
// SMRAM memory.
@@ -246,6 +255,8 @@ static const struct mem_region syzos_mem_regions[] = {
246255
{X86_SYZOS_PER_VCPU_REGIONS_BASE, (KVM_MAX_VCPU * X86_SYZOS_L1_VCPU_REGION_SIZE) / KVM_PAGE_SIZE, 0},
247256
// IOAPIC memory.
248257
{X86_SYZOS_ADDR_IOAPIC, 1, 0},
258+
// Remainder of memory (Unused Heap). Must be last.
259+
{X86_SYZOS_ADDR_UNUSED, 0, MEM_REGION_FLAG_REMAINING},
249260
};
250261
#endif
251262

@@ -376,15 +387,25 @@ static void setup_pg_table(struct kvm_syz_vm* vm)
376387

377388
// Zero-out the PT Pool memory.
378389
memset(vm->pt_pool_mem, 0, X86_SYZOS_PT_POOL_SIZE * KVM_PAGE_SIZE);
379-
380390
// Zero-out the fixed system pages (PML4/PDP/PD).
381-
// They are in the first 5 pages of gpa0_mem.
382391
memset(vm->gpa0_mem, 0, 5 * KVM_PAGE_SIZE);
383392

384393
// Map all the regions defined in setup_vm()
385-
for (size_t i = 0; i < sizeof(syzos_mem_regions) / sizeof(syzos_mem_regions[0]); i++)
386-
total -= map_4k_region(vm, &alloc, syzos_mem_regions[i].gpa, syzos_mem_regions[i].pages);
387-
map_4k_region(vm, &alloc, X86_SYZOS_ADDR_UNUSED, total);
394+
for (size_t i = 0; i < sizeof(syzos_mem_regions) / sizeof(syzos_mem_regions[0]); i++) {
395+
int pages = syzos_mem_regions[i].pages;
396+
if (syzos_mem_regions[i].flags & MEM_REGION_FLAG_REMAINING) {
397+
if (total < 0)
398+
fail("Guest memory accounting underflow");
399+
pages = total;
400+
}
401+
map_4k_region(vm, &alloc, syzos_mem_regions[i].gpa, pages);
402+
403+
// Only consume 'total' if the region is actually backed by host RAM.
404+
if (!(syzos_mem_regions[i].flags & MEM_REGION_FLAG_NO_HOST_MEM))
405+
total -= pages;
406+
if (syzos_mem_regions[i].flags & MEM_REGION_FLAG_REMAINING)
407+
break;
408+
}
388409
}
389410

390411
// A 64-bit GDT entry for a code or data segment.
@@ -1152,12 +1173,18 @@ static void setup_vm(int vmfd, struct kvm_syz_vm* vm)
11521173
{
11531174
struct addr_size allocator = {.addr = vm->host_mem, .size = vm->total_pages * KVM_PAGE_SIZE};
11541175
int slot = 0; // Slot numbers do not matter, they just have to be different.
1176+
struct syzos_boot_args* boot_args = NULL;
11551177

11561178
for (size_t i = 0; i < sizeof(syzos_mem_regions) / sizeof(syzos_mem_regions[0]); i++) {
11571179
const struct mem_region* r = &syzos_mem_regions[i];
11581180
if (r->flags & MEM_REGION_FLAG_NO_HOST_MEM)
11591181
continue;
1160-
struct addr_size next = alloc_guest_mem(&allocator, r->pages * KVM_PAGE_SIZE);
1182+
1183+
size_t pages = r->pages;
1184+
if (r->flags & MEM_REGION_FLAG_REMAINING)
1185+
pages = allocator.size / KVM_PAGE_SIZE;
1186+
1187+
struct addr_size next = alloc_guest_mem(&allocator, pages * KVM_PAGE_SIZE);
11611188
uint32 flags = 0;
11621189
if (r->flags & MEM_REGION_FLAG_DIRTY_LOG)
11631190
flags |= KVM_MEM_LOG_DIRTY_PAGES;
@@ -1169,14 +1196,24 @@ static void setup_vm(int vmfd, struct kvm_syz_vm* vm)
11691196
vm->gpa0_mem = next.addr;
11701197
if (r->gpa == X86_SYZOS_ADDR_PT_POOL)
11711198
vm->pt_pool_mem = next.addr;
1199+
1200+
if (r->gpa == X86_SYZOS_ADDR_BOOT_ARGS) {
1201+
boot_args = (struct syzos_boot_args*)next.addr;
1202+
boot_args->region_count = sizeof(syzos_mem_regions) / sizeof(syzos_mem_regions[0]);
1203+
for (size_t k = 0; k < boot_args->region_count; k++)
1204+
boot_args->regions[k] = syzos_mem_regions[k];
1205+
}
1206+
1207+
if ((r->flags & MEM_REGION_FLAG_REMAINING) && boot_args)
1208+
boot_args->regions[i].pages = pages;
1209+
11721210
if (r->flags & MEM_REGION_FLAG_EXECUTOR_CODE)
11731211
install_syzos_code(next.addr, next.size);
11741212
vm_set_user_memory_region(vmfd, slot++, flags, r->gpa, next.size, (uintptr_t)next.addr);
1175-
}
11761213

1177-
// Map the remaining pages at an unused address.
1178-
struct addr_size next = alloc_guest_mem(&allocator, allocator.size);
1179-
vm_set_user_memory_region(vmfd, slot++, 0, X86_SYZOS_ADDR_UNUSED, next.size, (uintptr_t)next.addr);
1214+
if (r->flags & MEM_REGION_FLAG_REMAINING)
1215+
break;
1216+
}
11801217
}
11811218
#endif
11821219

@@ -1289,4 +1326,4 @@ static long syz_kvm_assert_syzos_uexit(volatile long a0, volatile long a1, volat
12891326
}
12901327
#endif
12911328

1292-
#endif // EXECUTOR_COMMON_KVM_AMD64_H
1329+
#endif // EXECUTOR_COMMON_KVM_AMD64_H

executor/kvm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
#define X86_SYZOS_ADDR_PDP 0x3000
4848
#define X86_SYZOS_ADDR_VAR_IDT 0x25000
4949
#define X86_SYZOS_ADDR_VAR_TSS 0x26000
50+
// Dedicated page for passing configuration (memory map) to L1.
51+
#define X86_SYZOS_ADDR_BOOT_ARGS 0x2F000
5052

5153
#define X86_SYZOS_ADDR_SMRAM 0x30000
5254
// Write to this page to trigger a page fault and stop KVM_RUN.

0 commit comments

Comments
 (0)