Skip to content

Commit 49e3566

Browse files
committed
tests: fail a test binary that reads the host
A test that reads a kernel fact from the machine running it asserts against that machine's contents -- or against what it happens to lack, which the test's own text does not reveal. Test builds define KASLD_HERMETIC_PROBE, under which kasld_resolve records any fact path resolved with no sysroot set and the harness fails the binary at its tally, listing them. Reported at the tally rather than at the read, because a test capturing a component's output may have stderr pointed at /dev/null when it happens. Runtime rather than a source scan, because the read is normally several frames below the test: tests/test_render.c names no path and calls no wrapper, yet reaches 13 of them through container detection, the LSM probe and the group database. It catches staging done too late for the same reason -- the prefix is resolved once and cached, so a read before the setenv resolves live. Never defined for a shipped build. Also wires check-absence-vs-denial into `make lint` and documents both checks.
1 parent 72c2f8f commit 49e3566

5 files changed

Lines changed: 146 additions & 29 deletions

File tree

Makefile

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,13 @@ run : build
371371

372372
# Unit tests
373373
TEST_DIR := ./tests
374+
375+
# Test binaries carry the hermeticity probe: kasld_resolve records any kernel
376+
# fact path resolved with no KASLD_SYSROOT set, and the harness fails the binary
377+
# on it. A test that reads the machine it runs on is asserting against that
378+
# machine's contents -- or against what that machine happens to lack, which its
379+
# source does not reveal. Never set for a shipped build.
380+
TEST_ALL_CFLAGS = $(ALL_CFLAGS) -DKASLD_HERMETIC_PROBE
374381
TEST_BIN := $(TEST_OBJ_DIR)/test_kasld
375382

376383
# Unit tests of orchestrator internals (parsing, merge, anchor selection,
@@ -381,7 +388,7 @@ TEST_BIN := $(TEST_OBJ_DIR)/test_kasld
381388
# without exporting them across the public API.
382389
$(TEST_BIN): $(TEST_DIR)/test_kasld.c $(KASLD_SRC) $(RENDER_SRC) $(RENDER_MODE_SRCS) $(HDRS) | $(TEST_OBJ_DIR)
383390
$(call ccv,CCLD,$@)
384-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(PTHREAD_CFLAGS) -DKASLD_TESTING -I$(SRC_DIR) $(TEST_DIR)/test_kasld.c $(PTHREAD_LIBS) -o $@
391+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) $(PTHREAD_CFLAGS) -DKASLD_TESTING -I$(SRC_DIR) $(TEST_DIR)/test_kasld.c $(PTHREAD_LIBS) -o $@
385392

386393
# Renderer unit tests (split from test_kasld.c). Same single-TU model — it
387394
# #includes the orchestrator + render translation units directly, hence
@@ -390,29 +397,29 @@ TEST_RENDER_BIN := $(TEST_OBJ_DIR)/test_render
390397

391398
$(TEST_RENDER_BIN): $(TEST_DIR)/test_render.c $(KASLD_SRC) $(RENDER_SRC) $(RENDER_MODE_SRCS) $(HDRS) | $(TEST_OBJ_DIR)
392399
$(call ccv,CCLD,$@)
393-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(PTHREAD_CFLAGS) -DKASLD_TESTING -I$(SRC_DIR) $(TEST_DIR)/test_render.c $(PTHREAD_LIBS) -o $@
400+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) $(PTHREAD_CFLAGS) -DKASLD_TESTING -I$(SRC_DIR) $(TEST_DIR)/test_render.c $(PTHREAD_LIBS) -o $@
394401

395402
# Estimate-core test (Stage A): standalone, links only estimate.c + quantities.c.
396403
TEST_EST_BIN := $(TEST_OBJ_DIR)/test_estimate
397404

398405
$(TEST_EST_BIN): $(TEST_DIR)/test_estimate.c $(ESTIMATE_SRC) $(QUANTITIES_SRC) $(HDRS) | $(TEST_OBJ_DIR)
399406
$(call ccv,CCLD,$@)
400-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_estimate.c $(ESTIMATE_SRC) $(QUANTITIES_SRC) -o $@
407+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_estimate.c $(ESTIMATE_SRC) $(QUANTITIES_SRC) -o $@
401408

402409
# Evidence-store test (Stage B): standalone, links only evidence.c.
403410
TEST_EV_BIN := $(TEST_OBJ_DIR)/test_evidence
404411

405412
$(TEST_EV_BIN): $(TEST_DIR)/test_evidence.c $(EVIDENCE_SRC) $(HDRS) | $(TEST_OBJ_DIR)
406413
$(call ccv,CCLD,$@)
407-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_evidence.c $(EVIDENCE_SRC) -o $@
414+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_evidence.c $(EVIDENCE_SRC) -o $@
408415

409416
# Align-helper test (header-only): exercises kasld_floor_text_base() and its
410417
# pure core against every arch's sub-offset on the host. No .c sources to link.
411418
TEST_ALIGN_BIN := $(TEST_OBJ_DIR)/test_align
412419

413420
$(TEST_ALIGN_BIN): $(TEST_DIR)/test_align.c $(HDRS) | $(TEST_OBJ_DIR)
414421
$(call ccv,CCLD,$@)
415-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_align.c -o $@
422+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_align.c -o $@
416423

417424
# Address-parser test (header-only): drives kasld_addr_parse()'s refusal paths,
418425
# deriving the too-wide inputs from the build's own word so the same source is a
@@ -421,7 +428,7 @@ TEST_ADDRP_BIN := $(TEST_OBJ_DIR)/test_addr_parse
421428

422429
$(TEST_ADDRP_BIN): $(TEST_DIR)/test_addr_parse.c $(HDRS) | $(TEST_OBJ_DIR)
423430
$(call ccv,CCLD,$@)
424-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_addr_parse.c -o $@
431+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_addr_parse.c -o $@
425432

426433
# TASK_SIZE probe test (header-only): drives the boundary search and gap
427434
# detection in task_size.h with a synthetic address space (an injected step, no
@@ -431,7 +438,7 @@ TEST_TS_BIN := $(TEST_OBJ_DIR)/test_task_size
431438

432439
$(TEST_TS_BIN): $(TEST_DIR)/test_task_size.c $(HDRS) | $(TEST_OBJ_DIR)
433440
$(call ccv,CCLD,$@)
434-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_task_size.c -o $@
441+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_task_size.c -o $@
435442

436443
# Prefetch scan edge-detection test (header-only): drives
437444
# prefetch_scan_find_edge() with synthetic timing profiles. The x86_64-only
@@ -440,15 +447,15 @@ TEST_PREFETCH_SCAN_BIN := $(TEST_OBJ_DIR)/test_prefetch_scan
440447

441448
$(TEST_PREFETCH_SCAN_BIN): $(TEST_DIR)/test_prefetch_scan.c $(HDRS) | $(TEST_OBJ_DIR)
442449
$(call ccv,CCLD,$@)
443-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_prefetch_scan.c -o $@
450+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_prefetch_scan.c -o $@
444451

445452
# pin_cpu() cpuset-aware affinity test (header-only, x86_64-only cpu.h; inert
446453
# elsewhere). No .c sources to link.
447454
TEST_CPU_BIN := $(TEST_OBJ_DIR)/test_cpu
448455

449456
$(TEST_CPU_BIN): $(TEST_DIR)/test_cpu.c $(HDRS) | $(TEST_OBJ_DIR)
450457
$(call ccv,CCLD,$@)
451-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_cpu.c -o $@
458+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_cpu.c -o $@
452459

453460
# Component outcome classifier test (header-only): exercises
454461
# kasld_classify_outcome() (outcome.h) — the reaped-status -> outcome mapping,
@@ -457,7 +464,7 @@ TEST_OUTCOME_BIN := $(TEST_OBJ_DIR)/test_outcome
457464

458465
$(TEST_OUTCOME_BIN): $(TEST_DIR)/test_outcome.c $(HDRS) | $(TEST_OBJ_DIR)
459466
$(call ccv,CCLD,$@)
460-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_outcome.c -o $@
467+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_outcome.c -o $@
461468

462469
# seccomp-exec: installs a minimal seccomp-BPF filter then execs its argv, so
463470
# tests/container/run can run kasld under a container-shaped syscall gate
@@ -467,7 +474,7 @@ SECCOMP_EXEC_BIN := $(TEST_OBJ_DIR)/seccomp-exec
467474

468475
$(SECCOMP_EXEC_BIN): $(TEST_DIR)/container/seccomp-exec.c | $(TEST_OBJ_DIR)
469476
$(call ccv,CCLD,$@)
470-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(TEST_DIR)/container/seccomp-exec.c -o $@
477+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) $(TEST_DIR)/container/seccomp-exec.c -o $@
471478

472479
# fork-fail.so: LD_PRELOAD shim that fails a fraction of fork() calls with
473480
# EAGAIN, so tests/container/run can verify kasld stays coherent under a pids
@@ -483,7 +490,7 @@ TEST_TEXT_ORDER_BIN := $(TEST_OBJ_DIR)/test_text_order
483490

484491
$(TEST_TEXT_ORDER_BIN): $(TEST_DIR)/test_text_order.c $(HDRS) | $(TEST_OBJ_DIR)
485492
$(call ccv,CCLD,$@)
486-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_text_order.c -o $@
493+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_text_order.c -o $@
487494

488495
# Kernel image-size readers test (header-only): exercises the Image header / ELF
489496
# / System.map / gzip-ISIZE parsers in kasld/kernel_image.h against crafted
@@ -492,7 +499,7 @@ TEST_KIMG_BIN := $(TEST_OBJ_DIR)/test_kernel_image
492499

493500
$(TEST_KIMG_BIN): $(TEST_DIR)/test_kernel_image.c $(HDRS) | $(TEST_OBJ_DIR)
494501
$(call ccv,CCLD,$@)
495-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_kernel_image.c -o $@
502+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_kernel_image.c -o $@
496503

497504
# Engine test (Stage C/D): links the engine core + ALL ported rules. Linking the
498505
# whole rules/ wildcard (rather than a hand-maintained subset) means adding a
@@ -502,52 +509,52 @@ TEST_ENG_BIN := $(TEST_OBJ_DIR)/test_engine
502509

503510
$(TEST_ENG_BIN): $(TEST_DIR)/test_engine.c $(ENGINE_CORE) $(RULE_SRCS) $(HDRS) | $(TEST_OBJ_DIR)
504511
$(call ccv,CCLD,$@)
505-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_engine.c $(ENGINE_CORE) $(RULE_SRCS) -o $@
512+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_engine.c $(ENGINE_CORE) $(RULE_SRCS) -o $@
506513

507514
# Integration test: the FULL production rule registry (engine_rules.c + every
508515
# rules/*.c) against leak-bearing synthetic evidence.
509516
TEST_INT_BIN := $(TEST_OBJ_DIR)/test_engine_integration
510517
$(TEST_INT_BIN): $(TEST_DIR)/test_engine_integration.c $(ENGINE_CORE) $(ENGINE_RULES_SRC) $(RULE_SRCS) $(HDRS) | $(TEST_OBJ_DIR)
511518
$(call ccv,CCLD,$@)
512-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_engine_integration.c $(ENGINE_CORE) $(ENGINE_RULES_SRC) $(RULE_SRCS) -o $@
519+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_engine_integration.c $(ENGINE_CORE) $(ENGINE_RULES_SRC) $(RULE_SRCS) -o $@
513520

514521
# Component parser test: dmesg_mem_init_kernel_layout's layout-dump parser,
515522
# exercised by #including the component (its main renamed). No extra link inputs
516523
# — the component pulls its helpers from headers.
517524
TEST_DMESG_BIN := $(TEST_OBJ_DIR)/test_dmesg_layout
518525
$(TEST_DMESG_BIN): $(TEST_DIR)/test_dmesg_layout.c $(SRC_DIR)/components/dmesg_mem_init_kernel_layout.c $(HDRS) | $(TEST_OBJ_DIR)
519526
$(call ccv,CCLD,$@)
520-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_dmesg_layout.c -o $@
527+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_dmesg_layout.c -o $@
521528

522529
# BTF reader parser test: btf_struct_page_size's struct-size parser, exercised
523530
# by #including the component (its main renamed) against hand-built BTF blobs.
524531
TEST_BTF_BIN := $(TEST_OBJ_DIR)/test_btf
525532
$(TEST_BTF_BIN): $(TEST_DIR)/test_btf.c $(SRC_DIR)/components/btf_struct_page_size.c $(HDRS) | $(TEST_OBJ_DIR)
526533
$(call ccv,CCLD,$@)
527-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_btf.c -o $@
534+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_btf.c -o $@
528535

529536
# dmesg_backtrace block parser: #includes the component (main renamed), driven
530537
# over a staged KASLD_SYSROOT /var/log/dmesg covering the CR3 context tagging.
531538
TEST_BACKTRACE_BIN := $(TEST_OBJ_DIR)/test_dmesg_backtrace
532539
$(TEST_BACKTRACE_BIN): $(TEST_DIR)/test_dmesg_backtrace.c $(SRC_DIR)/components/dmesg_backtrace.c $(HDRS) | $(TEST_OBJ_DIR)
533540
$(call ccv,CCLD,$@)
534-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_dmesg_backtrace.c -o $@
541+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_dmesg_backtrace.c -o $@
535542

536543
# boot_config provenance: #includes the component (main renamed), driven over a
537544
# staged KASLD_SYSROOT to assert keyed configs stay CONF_PARSED while the
538545
# unkeyed /boot/config is demoted to CONF_HEURISTIC (and never shadows a keyed).
539546
TEST_BOOTCFG_BIN := $(TEST_OBJ_DIR)/test_boot_config
540547
$(TEST_BOOTCFG_BIN): $(TEST_DIR)/test_boot_config.c $(SRC_DIR)/components/boot_config.c $(HDRS) | $(TEST_OBJ_DIR)
541548
$(call ccv,CCLD,$@)
542-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_boot_config.c -o $@
549+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_boot_config.c -o $@
543550

544551
# dmesg_kaslr_disabled classification: #includes the component (main renamed),
545552
# driven over a staged KASLD_SYSROOT /var/log/dmesg to assert only whitelisted
546553
# opt-out phrases pin to default and unrecognized lines emit nothing.
547554
TEST_KASLRDIS_BIN := $(TEST_OBJ_DIR)/test_dmesg_kaslr_disabled
548555
$(TEST_KASLRDIS_BIN): $(TEST_DIR)/test_dmesg_kaslr_disabled.c $(SRC_DIR)/components/dmesg_kaslr_disabled.c $(HDRS) | $(TEST_OBJ_DIR)
549556
$(call ccv,CCLD,$@)
550-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_dmesg_kaslr_disabled.c -o $@
557+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_dmesg_kaslr_disabled.c -o $@
551558

552559
# sysfs_devicetree_memory covering completeness: #includes the component (main
553560
# renamed), driven over a staged KASLD_SYSROOT binary device tree to assert a
@@ -556,38 +563,38 @@ $(TEST_KASLRDIS_BIN): $(TEST_DIR)/test_dmesg_kaslr_disabled.c $(SRC_DIR)/compone
556563
TEST_DTMEM_BIN := $(TEST_OBJ_DIR)/test_sysfs_devicetree_memory
557564
$(TEST_DTMEM_BIN): $(TEST_DIR)/test_sysfs_devicetree_memory.c $(SRC_DIR)/components/sysfs_devicetree_memory.c $(HDRS) | $(TEST_OBJ_DIR)
558565
$(call ccv,CCLD,$@)
559-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_sysfs_devicetree_memory.c -o $@
566+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_sysfs_devicetree_memory.c -o $@
560567

561568
# proc_net_sock_ptr hashed-pointer rejection: the component is #included (main
562569
# renamed) so its classify_sock_ptr() is unit-tested, and it is driven over a
563570
# staged KASLD_SYSROOT /proc/net/unix to assert the batch-decline + real-emit.
564571
TEST_SOCKPTR_BIN := $(TEST_OBJ_DIR)/test_proc_net_sock_ptr
565572
$(TEST_SOCKPTR_BIN): $(TEST_DIR)/test_proc_net_sock_ptr.c $(SRC_DIR)/components/proc_net_sock_ptr.c $(HDRS) | $(TEST_OBJ_DIR)
566573
$(call ccv,CCLD,$@)
567-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_proc_net_sock_ptr.c -o $@
574+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_proc_net_sock_ptr.c -o $@
568575

569576
# proc_timer_list hashed-pointer rejection: same slab/pointer-alignment gate as
570577
# proc_net_sock_ptr, unit-tested (classify_timer_base) + staged /proc/timer_list.
571578
TEST_TIMERLIST_BIN := $(TEST_OBJ_DIR)/test_proc_timer_list
572579
$(TEST_TIMERLIST_BIN): $(TEST_DIR)/test_proc_timer_list.c $(SRC_DIR)/components/proc_timer_list.c $(HDRS) | $(TEST_OBJ_DIR)
573580
$(call ccv,CCLD,$@)
574-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_proc_timer_list.c -o $@
581+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_proc_timer_list.c -o $@
575582

576583
# Build/target width check (header-only): the two mismatch signals and, mostly,
577584
# the paths that must NOT report one. Driven over a staged KASLD_SYSROOT.
578585
TEST_TWIDTH_BIN := $(TEST_OBJ_DIR)/test_target_width
579586

580587
$(TEST_TWIDTH_BIN): $(TEST_DIR)/test_target_width.c $(HDRS) | $(TEST_OBJ_DIR)
581588
$(call ccv,CCLD,$@)
582-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_target_width.c -o $@
589+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_target_width.c -o $@
583590

584591
# proc_kallsyms masked-probe + address width: the kptr_restrict all-zero
585592
# detection and the refusal of a symbol address wider than this build's word,
586593
# over a staged /proc/kallsyms (main renamed).
587594
TEST_KALLSYMS_BIN := $(TEST_OBJ_DIR)/test_proc_kallsyms
588595
$(TEST_KALLSYMS_BIN): $(TEST_DIR)/test_proc_kallsyms.c $(SRC_DIR)/components/proc_kallsyms.c $(HDRS) | $(TEST_OBJ_DIR)
589596
$(call ccv,CCLD,$@)
590-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_proc_kallsyms.c -o $@
597+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_proc_kallsyms.c -o $@
591598

592599
# dmesg physical-reservation parsers: the four restructured components
593600
# (reserved_mem / swiotlb / crashkernel / cma) #included (main renamed) and
@@ -599,22 +606,22 @@ TEST_DMESG_RESV_SRCS := $(SRC_DIR)/components/dmesg_reserved_mem.c \
599606
TEST_DMESG_RESV_BIN := $(TEST_OBJ_DIR)/test_dmesg_reservations
600607
$(TEST_DMESG_RESV_BIN): $(TEST_DIR)/test_dmesg_reservations.c $(TEST_DMESG_RESV_SRCS) $(HDRS) | $(TEST_OBJ_DIR)
601608
$(call ccv,CCLD,$@)
602-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_dmesg_reservations.c -o $@
609+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_dmesg_reservations.c -o $@
603610

604611
# boot_params_e820 RAM-covering test: the component #included (main renamed) and
605612
# driven over a staged KASLD_SYSROOT zero-page; asserts the per-RAM-entry extents.
606613
TEST_BPE820_BIN := $(TEST_OBJ_DIR)/test_boot_params_e820
607614
$(TEST_BPE820_BIN): $(TEST_DIR)/test_boot_params_e820.c $(SRC_DIR)/components/boot_params_e820.c $(HDRS) | $(TEST_OBJ_DIR)
608615
$(call ccv,CCLD,$@)
609-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_boot_params_e820.c -o $@
616+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_boot_params_e820.c -o $@
610617

611618
# proc_kcore ELF program-header scan: the component #included (main renamed) and
612619
# driven over a staged KASLD_SYSROOT /proc/kcore; the only coverage of the parse
613620
# (the live component is CAP_SYS_RAWIO-gated, so it is dark in the fixtures).
614621
TEST_KCORE_BIN := $(TEST_OBJ_DIR)/test_kcore
615622
$(TEST_KCORE_BIN): $(TEST_DIR)/test_kcore.c $(SRC_DIR)/components/proc_kcore.c $(HDRS) | $(TEST_OBJ_DIR)
616623
$(call ccv,CCLD,$@)
617-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_kcore.c -o $@
624+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_kcore.c -o $@
618625

619626
# sysfs / ACPI / DT leak-parser tests: each component #included (main renamed)
620627
# and driven over a staged KASLD_SYSROOT fixture tree reproducing the kernel ABI.
@@ -635,7 +642,7 @@ TEST_PARSERS_SRCS := $(SRC_DIR)/components/sysfs_efi_runtime_map.c \
635642
TEST_PARSERS_BIN := $(TEST_OBJ_DIR)/test_sysfs_parsers
636643
$(TEST_PARSERS_BIN): $(TEST_DIR)/test_sysfs_parsers.c $(TEST_PARSERS_SRCS) $(HDRS) | $(TEST_OBJ_DIR)
637644
$(call ccv,CCLD,$@)
638-
$(Q)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_sysfs_parsers.c -o $@
645+
$(Q)$(CC) $(TEST_ALL_CFLAGS) $(ALL_LDFLAGS) -I$(SRC_DIR) $(TEST_DIR)/test_sysfs_parsers.c -o $@
639646

640647
.PHONY: test
641648
test : $(KASLD_BIN) $(TEST_BIN) $(TEST_RENDER_BIN) $(TEST_EST_BIN) $(TEST_EV_BIN) $(TEST_ALIGN_BIN) $(TEST_ADDRP_BIN) $(TEST_TWIDTH_BIN) $(TEST_TS_BIN) $(TEST_PREFETCH_SCAN_BIN) $(TEST_CPU_BIN) $(TEST_OUTCOME_BIN) $(TEST_TEXT_ORDER_BIN) $(TEST_KIMG_BIN) $(TEST_ENG_BIN) $(TEST_INT_BIN) $(TEST_DMESG_BIN) $(TEST_BACKTRACE_BIN) $(TEST_BOOTCFG_BIN) $(TEST_KASLRDIS_BIN) $(TEST_DTMEM_BIN) $(TEST_SOCKPTR_BIN) $(TEST_TIMERLIST_BIN) $(TEST_KALLSYMS_BIN) $(TEST_BTF_BIN) $(TEST_DMESG_RESV_BIN) $(TEST_BPE820_BIN) $(TEST_PARSERS_BIN) $(TEST_KCORE_BIN)
@@ -654,6 +661,7 @@ lint :
654661
@$(TEST_DIR)/check-extent-callers
655662
@$(TEST_DIR)/check-truncation
656663
@$(TEST_DIR)/check-addr-parse
664+
@$(TEST_DIR)/check-absence-vs-denial
657665
@$(TEST_DIR)/check-component-output
658666
@$(TEST_DIR)/check-component-meta
659667
@$(TEST_DIR)/check-component-cap

docs/testing.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,33 @@ chosen for what they say rather than how wide they are. The target-identity line
6969
is exempt for the same reason — it interpolates an unbounded kernel version
7070
string.
7171

72+
Every test binary also carries the hermeticity probe. Test builds define
73+
`KASLD_HERMETIC_PROBE`, under which `kasld_resolve` records any kernel fact path
74+
resolved while `KASLD_SYSROOT` is unset — a read that went to the machine
75+
running the test rather than to a tree the test supplied — and the harness fails
76+
that binary at its tally, listing the paths:
77+
78+
```
79+
7/7 tests passed
80+
read 1 kernel fact path from the host:
81+
/proc/version
82+
Stage a tree and point KASLD_SYSROOT at it before the first read.
83+
```
84+
85+
A test that reads the host asserts against whatever that machine holds, or
86+
against what it happens to lack, which the test's own text does not reveal. The
87+
check is a runtime one because a source scan cannot see it: the read is normally
88+
several frames below the test, so a renderer test that names no path still
89+
reaches container detection, the LSM probe and the group database. It equally
90+
catches staging done too late, since the prefix is resolved once and cached and
91+
a read before the `setenv` resolves live.
92+
93+
The fix is to supply the source rather than borrow it: stage a directory, write
94+
the files the test needs under it, and set `KASLD_SYSROOT` to it before the
95+
first read. An empty staged tree is a legitimate answer, and the correct one
96+
where the test wants the source absent. The probe is never defined for a shipped
97+
build.
98+
7299
Run one driver in isolation:
73100

74101
```sh
@@ -105,6 +132,7 @@ and `make` halts on the first.
105132
| `check-extent-callers` | only reviewed whole-map components call `kasld_result_extent` (the covering-completeness contract; a partial map would carve a false gap) |
106133
| `check-truncation` | no silent 64-bit→word narrowing when compiled for 32-bit (compiles a TU with `i686-linux-gnu-gcc`) |
107134
| `check-addr-parse` | kernel addresses are converted with `kasld_addr_parse` outside a reviewed allowlist — `sscanf("%lx")` reports success on an address wider than the word and hands back a truncated one |
135+
| `check-absence-vs-denial` | no component reports a denied source as an absent one — a failed probe's reason is in `errno`, and UNAVAILABLE claims the target's build while NOPERM reports its hardening |
108136
| `check-component-output` | components write only wire lines to stdout (stdout is the machine channel; diagnostics go to stderr) |
109137
| `check-component-meta` | every component declares `KASLD_META` with a `method:` key |
110138
| `check-component-cap` | `MAX_COMPONENTS` keeps a margin above the in-tree component count — a component directory that overruns it silently drops the excess |

0 commit comments

Comments
 (0)