test harness: kernel_range unit tests + coverage report + register_all helper

Three coupled improvements to the test harness:

1. New tests/test_kernel_range.c — 32 pure unit tests covering
   kernel_range_is_patched(), skeletonkey_host_kernel_at_least(),
   and skeletonkey_host_kernel_in_range(). These are the central
   comparison primitives every module routes through; a regression
   in any of them silently mis-classifies entire CVE families. Tests
   cover exact boundary, one-below, mainline-only, multi-LTS,
   between-branch, and NULL-safety cases. Builds and runs
   cross-platform (no Linux syscalls).

2. tests/test_detect.c additions:
   - mk_host(base, major, minor, patch, release) builder so new
     fingerprint-based tests don't duplicate 14-line struct literals
     to override one (major, minor, patch) triple.
   - Post-run coverage report that iterates the runtime registry and
     warns about modules without at least one direct test row. Output
     is informational (no CI fail) so coverage grows incrementally.
   - 7 new boundary tests for the kernel_patched_from entries added
     by tools/refresh-kernel-ranges.py (commit 8de46e2):
       - af_unix_gc 6.4.12 → VULNERABLE / 6.4.13 → OK
       - vmwgfx 5.10.127 → OK
       - nft_set_uaf 5.10.179 → OK / 6.1.27 → OK
       - nft_payload 5.10.162 → OK
       - nf_tables 5.10.209 → OK

3. core/registry_all.c — extracts the 27-line 'call every
   skeletonkey_register_<family>()' enumeration from skeletonkey.c
   into a shared helper. skeletonkey.c main() now calls
   skeletonkey_register_all_modules() once; the detect-test main()
   does the same. Kept in its own translation unit so registry.c
   stays standalone for the lean kernel_range unit-test binary
   (which links core/ only, no modules).

Makefile: builds two test binaries now —
  skeletonkey-test     — detect() integration tests (full corpus)
  skeletonkey-test-kr  — kernel_range unit tests (core/ only)
'make test' runs both.

Verification:
  - macOS: 32/32 kernel_range tests pass; detect tests skipped
    (non-Linux platform, stubbed bodies).
  - Linux (docker gcc:latest): 32/32 kernel_range + 51/51 detect.
    Coverage report identifies 2 modules without direct tests
    (copy_fail, entrybleed) out of 31 registered.

Test counts: 44 -> 83 (+39).
This commit is contained in:
2026-05-23 01:09:30 -04:00
parent 8de46e212e
commit 8243817f7e
7 changed files with 466 additions and 37 deletions
+29 -8
View File
@@ -23,6 +23,11 @@ BIN := skeletonkey
CORE_SRCS := core/registry.c core/kernel_range.c core/offsets.c core/finisher.c core/host.c
CORE_OBJS := $(patsubst %.c,$(BUILD)/%.o,$(CORE_SRCS))
# Register-every-module helper. Lives in its own translation unit so
# the kernel_range unit-test binary can link just CORE_OBJS without
# pulling in every module symbol via registry_all.o.
REGISTRY_ALL_OBJ := $(BUILD)/core/registry_all.o
# Family: copy_fail_family
# All DIRTYFAIL .c files contribute; skeletonkey_modules.c is the bridge.
CFF_DIR := modules/copy_fail_family
@@ -186,16 +191,26 @@ MODULE_OBJS := $(CFF_OBJS) $(DP_OBJS) $(EB_OBJS) $(PK_OBJS) $(NFT_OBJS) \
$(SAM_OBJS) $(SEQ_OBJS) $(SUE_OBJS) $(VMW_OBJS) \
$(DDC_OBJS) $(FGN_OBJS) $(P2TR_OBJS)
ALL_OBJS := $(TOP_OBJ) $(CORE_OBJS) $(MODULE_OBJS)
ALL_OBJS := $(TOP_OBJ) $(CORE_OBJS) $(REGISTRY_ALL_OBJ) $(MODULE_OBJS)
# Tests — `make test` builds and runs the detect() unit-test harness.
# Links against the same module objects as the main binary minus the
# top-level dispatcher (which provides main(); the test has its own).
# Tests — `make test` builds and runs both unit-test binaries.
#
# skeletonkey-test — detect() integration tests against
# synthetic host fingerprints. Links
# the full module corpus.
# skeletonkey-test-kr — pure unit tests for kernel_range +
# host comparison helpers. Tiny binary
# (core/ only); runs cross-platform.
TEST_DIR := tests
TEST_SRCS := $(TEST_DIR)/test_detect.c
TEST_OBJS := $(patsubst %.c,$(BUILD)/%.o,$(TEST_SRCS))
TEST_BIN := skeletonkey-test
TEST_ALL_OBJS := $(TEST_OBJS) $(CORE_OBJS) $(MODULE_OBJS)
TEST_ALL_OBJS := $(TEST_OBJS) $(CORE_OBJS) $(REGISTRY_ALL_OBJ) $(MODULE_OBJS)
TEST_KR_SRCS := $(TEST_DIR)/test_kernel_range.c
TEST_KR_OBJS := $(patsubst %.c,$(BUILD)/%.o,$(TEST_KR_SRCS))
TEST_KR_BIN := skeletonkey-test-kr
TEST_KR_ALL_OBJS := $(TEST_KR_OBJS) $(CORE_OBJS)
.PHONY: all clean debug static help test
@@ -207,8 +222,14 @@ $(BIN): $(ALL_OBJS)
$(TEST_BIN): $(TEST_ALL_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lpthread $(P2TR_LIBS)
test: $(TEST_BIN)
@echo "[*] running test suite ($(TEST_BIN))"
$(TEST_KR_BIN): $(TEST_KR_ALL_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
test: $(TEST_BIN) $(TEST_KR_BIN)
@echo "[*] running kernel_range unit tests ($(TEST_KR_BIN))"
./$(TEST_KR_BIN)
@echo
@echo "[*] running detect() integration tests ($(TEST_BIN))"
./$(TEST_BIN)
# Generic compile: any .c → corresponding .o under build/
@@ -223,7 +244,7 @@ static: LDFLAGS += -static
static: clean $(BIN)
clean:
rm -rf $(BUILD) $(BIN) $(TEST_BIN)
rm -rf $(BUILD) $(BIN) $(TEST_BIN) $(TEST_KR_BIN)
help:
@echo "Targets:"