Skip to content

Commit c9146fa

Browse files
committed
Update tests
1 parent 91f3276 commit c9146fa

1 file changed

Lines changed: 141 additions & 0 deletions

File tree

tests/test_kasld.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "../src/inference/dram_bound.c"
1212
#include "../src/inference/image_size_from_text_data_gap.c"
1313
#include "../src/inference/kaslr_ceiling.c"
14+
#include "../src/inference/kernel_image_phys_bound.c"
1415
#include "../src/inference/layout_adjust.c"
1516
#include "../src/inference/module_text_bound.c"
1617
#include "../src/inference/phys_virt_synth.c"
@@ -2343,6 +2344,138 @@ static void test_randomize_memory_non_ram_base_witness_noop(void) {
23432344
assert(g_ctx.page_offset_max == po_max);
23442345
}
23452346

2347+
/* =========================================================================
2348+
* kernel_image_phys_bound (POST_COLLECTION)
2349+
* Bounds phys_base from kernel-locating PHYS witnesses; BSS-resident
2350+
* witnesses (e.g. cr3) refine the upper bound using virt TEXT/DATA gap.
2351+
* =========================================================================
2352+
*/
2353+
2354+
#define KIPB_MAX_IMAGE_SIZE (256ul * 1024 * 1024)
2355+
2356+
/* Witnessless: no kernel-locating PHYS results → no change. */
2357+
static void test_kernel_image_phys_no_witness_noop(void) {
2358+
reset_state();
2359+
/* Non-kernel-locating PHYS witnesses must be ignored. */
2360+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, 0x1000,
2361+
KASLD_REGION_RAM_BASE);
2362+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, 0x100000000ul,
2363+
KASLD_REGION_RAM_TOP);
2364+
init_inference_ctx();
2365+
unsigned long min0 = g_ctx.phys_base_min;
2366+
unsigned long max0 = g_ctx.phys_base_max;
2367+
run_inference_phase(&g_ctx, KASLD_INFER_PHASE_POST_COLLECTION);
2368+
assert(g_ctx.phys_base_min == min0);
2369+
assert(g_ctx.phys_base_max == max0);
2370+
}
2371+
2372+
/* Note on test setup: every kernel_image_phys_bound test that expects
2373+
* tightening also injects a low PHYS/DRAM `ram_base` witness. This pins
2374+
* dram_bound's `min PHYS/DRAM` to the low value, causing dram_bound's
2375+
* tightening check to fail (it can't raise phys_base_min above
2376+
* `phys_kaslr_base_min`). Without this, dram_bound would raise
2377+
* phys_base_min above the kernel_image witness in its same convergence
2378+
* pass, blocking kernel_image_phys_bound from firing — an order-dependence
2379+
* that doesn't occur in production parallel mode (where ram_base witnesses
2380+
* from /sys/firmware/memmap or /proc/zoneinfo are present alongside cr3).
2381+
*/
2382+
#define KIPB_RAM_BASE (0x1000ul)
2383+
2384+
/* Single kernel_image witness → both bounds tighten symmetrically around
2385+
* the witness, with the lower bound separated by MAX_IMAGE_SIZE. */
2386+
static void test_kernel_image_phys_single_witness_tightens(void) {
2387+
reset_state();
2388+
unsigned long cr3 = 0x119446000ul;
2389+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, KIPB_RAM_BASE,
2390+
KASLD_REGION_RAM_BASE);
2391+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, cr3, "kernel_bss:cr3");
2392+
init_inference_ctx();
2393+
run_inference_phase(&g_ctx, KASLD_INFER_PHASE_POST_COLLECTION);
2394+
/* phys_base_max ≤ cr3, aligned down to phys_kaslr_align (2 MiB). */
2395+
unsigned long align = g_ctx.arch->phys_kaslr_align;
2396+
assert(g_ctx.phys_base_max <= cr3);
2397+
assert((g_ctx.phys_base_max & (align - 1)) == 0);
2398+
/* phys_base_min ≥ cr3 - MAX_IMAGE_SIZE + 1, aligned up. */
2399+
unsigned long expected_min =
2400+
(cr3 - KIPB_MAX_IMAGE_SIZE + 1 + align - 1) & ~(align - 1);
2401+
assert(g_ctx.phys_base_min == expected_min);
2402+
}
2403+
2404+
/* BSS-resident refinement: cr3 witness *plus* a VIRT/TEXT and VIRT/DATA
2405+
* pair → phys_base_max contribution is `cr3 - virt_gap` (tighter than
2406+
* cr3 alone). */
2407+
static void test_kernel_image_phys_bss_refinement_with_gap(void) {
2408+
reset_state();
2409+
unsigned long cr3 = 0x119446000ul;
2410+
unsigned long vtext_min = KERNEL_BASE_MIN + 0x1000000ul; /* +16 MiB */
2411+
/* Place max(VIRT DATA) such that gap = 32 MiB (well within image). */
2412+
unsigned long gap = 32ul * 1024 * 1024;
2413+
unsigned long vdata_max = vtext_min + gap;
2414+
2415+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, KIPB_RAM_BASE,
2416+
KASLD_REGION_RAM_BASE);
2417+
inject_result(KASLD_ADDR_VIRT, KASLD_SECTION_TEXT, vtext_min,
2418+
KASLD_REGION_KERNEL_TEXT);
2419+
inject_result(KASLD_ADDR_VIRT, KASLD_SECTION_DATA, vdata_max,
2420+
KASLD_REGION_KERNEL_DATA);
2421+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, cr3, "kernel_bss:cr3");
2422+
init_inference_ctx();
2423+
run_inference_phase(&g_ctx, KASLD_INFER_PHASE_POST_COLLECTION);
2424+
/* phys_base_max ≤ cr3 - gap (BSS-resident refinement), aligned down. */
2425+
unsigned long align = g_ctx.arch->phys_kaslr_align;
2426+
unsigned long expected_max = (cr3 - gap) & ~(align - 1);
2427+
assert(g_ctx.phys_base_max == expected_max);
2428+
}
2429+
2430+
/* Non-cr3 kernel_image witness (no name match) → BSS refinement does NOT
2431+
* apply, even with a virt gap present. */
2432+
static void test_kernel_image_phys_no_bss_refinement_for_unknown_name(void) {
2433+
reset_state();
2434+
unsigned long w = 0x119446000ul;
2435+
unsigned long vtext_min = KERNEL_BASE_MIN + 0x1000000ul;
2436+
unsigned long gap = 32ul * 1024 * 1024;
2437+
unsigned long vdata_max = vtext_min + gap;
2438+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, KIPB_RAM_BASE,
2439+
KASLD_REGION_RAM_BASE);
2440+
inject_result(KASLD_ADDR_VIRT, KASLD_SECTION_TEXT, vtext_min,
2441+
KASLD_REGION_KERNEL_TEXT);
2442+
inject_result(KASLD_ADDR_VIRT, KASLD_SECTION_DATA, vdata_max,
2443+
KASLD_REGION_KERNEL_DATA);
2444+
/* Region kernel_image (not kernel_bss) → BSS refinement does NOT apply
2445+
* regardless of name. The discriminant is the region tag, not the name. */
2446+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, w,
2447+
"kernel_image:unknown_symbol");
2448+
init_inference_ctx();
2449+
run_inference_phase(&g_ctx, KASLD_INFER_PHASE_POST_COLLECTION);
2450+
/* phys_base_max ≤ W (no gap subtraction), aligned down. */
2451+
unsigned long align = g_ctx.arch->phys_kaslr_align;
2452+
assert(g_ctx.phys_base_max == (w & ~(align - 1)));
2453+
}
2454+
2455+
/* Conflicting witnesses (spread > MAX_IMAGE_SIZE) → skip entirely. */
2456+
static void test_kernel_image_phys_contradictory_witnesses_noop(void) {
2457+
reset_state();
2458+
unsigned long lo_w = 0x119446000ul;
2459+
unsigned long hi_w = lo_w + KIPB_MAX_IMAGE_SIZE + 0x100000ul; /* +1 MiB */
2460+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, KIPB_RAM_BASE,
2461+
KASLD_REGION_RAM_BASE);
2462+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, lo_w, "kernel_bss:cr3");
2463+
inject_result(KASLD_ADDR_PHYS, KASLD_SECTION_DRAM, hi_w,
2464+
KASLD_REGION_KERNEL_IMAGE);
2465+
init_inference_ctx();
2466+
unsigned long max0 = g_ctx.phys_base_max;
2467+
run_inference_phase(&g_ctx, KASLD_INFER_PHASE_POST_COLLECTION);
2468+
/* The conflict guard refused to emit any bound from this plugin. With
2469+
* the spread exceeding MAX_IMAGE_SIZE, the plugin returns before
2470+
* computing new_phys_max. The rest of the convergence loop may still
2471+
* shift things but the plugin under test must not have pinned
2472+
* phys_base_max to lo_w. */
2473+
assert(g_ctx.phys_base_max > lo_w || g_ctx.phys_base_max == max0);
2474+
}
2475+
2476+
#undef KIPB_RAM_BASE
2477+
#undef KIPB_MAX_IMAGE_SIZE
2478+
23462479
#endif /* __x86_64__ */
23472480

23482481
/* =========================================================================
@@ -2698,6 +2831,14 @@ int main(void) {
26982831
RUN_TEST(test_randomize_memory_unaligned_candidate_noop);
26992832
RUN_TEST(test_randomize_memory_non_ram_base_witness_noop);
27002833
printf("\n");
2834+
2835+
printf("inference plugins (kernel_image_phys_bound):\n");
2836+
RUN_TEST(test_kernel_image_phys_no_witness_noop);
2837+
RUN_TEST(test_kernel_image_phys_single_witness_tightens);
2838+
RUN_TEST(test_kernel_image_phys_bss_refinement_with_gap);
2839+
RUN_TEST(test_kernel_image_phys_no_bss_refinement_for_unknown_name);
2840+
RUN_TEST(test_kernel_image_phys_contradictory_witnesses_noop);
2841+
printf("\n");
27012842
#endif
27022843

27032844
#if defined(__aarch64__)

0 commit comments

Comments
 (0)