From 1571b88725a0828aab1f5335fb89ecba6f599b52 Mon Sep 17 00:00:00 2001 From: KaraZajac Date: Fri, 22 May 2026 23:52:10 -0400 Subject: [PATCH] core/host: skeletonkey_host_kernel_at_least + 9 new detect() tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit core/host helper: - Adds bool skeletonkey_host_kernel_at_least(h, M, m, p) — the canonical 'kernel >= X.Y.Z' check. Replaces the manual 'v->major < X || (v->major == X && v->minor < Y)' pattern that many modules use for their 'predates the bug' pre-check. Returns false when h is NULL or h->kernel.major == 0 (degenerate cases), true otherwise iff the host kernel sorts at or above the supplied version. - dirtydecrypt migrated as the demo: the 'kernel < 7.0 → predates' pre-check now reads 'if (!host_kernel_at_least(ctx->host, 7, 0, 0))'. Other modules still using the manual pattern continue to work unchanged; migrating them is incremental polish. tests/test_detect.c expansion (8 → 17 cases): New fingerprints: - h_kernel_4_4 — ancient (Linux 4.4 LTS); used for 'predates the bug' on dirty_pipe. - h_kernel_6_12 — recent (Linux 6.12 LTS); above every backport threshold in the corpus — modules report OK via the 'patched by mainline inheritance' branch of kernel_range_is_patched. - h_kernel_5_14_no_userns — vulnerable-era kernel (5.14.0, past every relevant predates check while below every backport entry) with unprivileged_userns_allowed deliberately false; lets the userns gate fire after the version check confirms vulnerable. New tests (9): - dirty_pipe + kernel 4.4 → OK (predates 5.8 introduction) - dirty_pipe + kernel 6.12 → OK (above every backport) - dirty_cow + kernel 6.12 → OK (above 4.9 fix) - ptrace_traceme + kernel 6.12 → OK (above 5.1.17 fix) - cgroup_release_agent + kernel 6.12 → OK (above 5.17 fix) - nf_tables + vuln kernel + userns=false → PRECOND_FAIL - fuse_legacy + vuln kernel + userns=false → PRECOND_FAIL - cls_route4 + vuln kernel + userns=false → PRECOND_FAIL - overlayfs_setuid + vuln kernel + userns=false → PRECOND_FAIL Process note: initial 8th and 9th userns tests failed because the chosen test kernel (5.10.0) tripped each module's predates check (nf_tables bug introduced 5.14; overlayfs_setuid 5.11). Switched to 5.14.0, which is past every predates threshold AND below every backport entry in this batch — the version verdict is now genuinely 'vulnerable' and the userns gate fires next. The bug-finding tests caught a real-but-narrow modeling gap in the original picks. Verification: - Linux (docker gcc:latest, non-root user): 17/17 pass. - macOS (local): builds clean, suite reports 'skipped — Linux-only' as designed. --- core/host.c | 10 ++ core/host.h | 15 +++ .../skeletonkey_modules.c | 2 +- tests/test_detect.c | 107 ++++++++++++++++++ 4 files changed, 133 insertions(+), 1 deletion(-) diff --git a/core/host.c b/core/host.c index c1df73f..670324e 100644 --- a/core/host.c +++ b/core/host.c @@ -242,6 +242,16 @@ const struct skeletonkey_host *skeletonkey_host_get(void) return &g_host; } +bool skeletonkey_host_kernel_at_least(const struct skeletonkey_host *h, + int major, int minor, int patch) +{ + if (!h || h->kernel.major == 0) + return false; + if (h->kernel.major != major) return h->kernel.major > major; + if (h->kernel.minor != minor) return h->kernel.minor > minor; + return h->kernel.patch >= patch; +} + void skeletonkey_host_print_banner(const struct skeletonkey_host *h, bool json) { if (json || h == NULL) return; diff --git a/core/host.h b/core/host.h index cd47cf7..e171b35 100644 --- a/core/host.h +++ b/core/host.h @@ -88,4 +88,19 @@ const struct skeletonkey_host *skeletonkey_host_get(void); * --auto / --scan verbose output. Silent on JSON mode. */ void skeletonkey_host_print_banner(const struct skeletonkey_host *h, bool json); +/* True iff h->kernel >= the (major, minor, patch) provided. Returns + * false if h is NULL or its kernel version was never populated (major + * == 0). Replaces the manual `v->major < X` / `(v->major == X && + * v->minor < Y)` patterns scattered across detect()s — cleaner reads + * and one place to get the comparison right. + * + * Examples: + * if (!host_kernel_at_least(h, 7, 0, 0)) // kernel predates 7.0 + * return SKELETONKEY_OK; + * if ( host_kernel_at_least(h, 6, 8, 0)) // kernel post-fix + * return SKELETONKEY_OK; + */ +bool skeletonkey_host_kernel_at_least(const struct skeletonkey_host *h, + int major, int minor, int patch); + #endif /* SKELETONKEY_HOST_H */ diff --git a/modules/dirtydecrypt_cve_2026_31635/skeletonkey_modules.c b/modules/dirtydecrypt_cve_2026_31635/skeletonkey_modules.c index b20500f..32417c6 100644 --- a/modules/dirtydecrypt_cve_2026_31635/skeletonkey_modules.c +++ b/modules/dirtydecrypt_cve_2026_31635/skeletonkey_modules.c @@ -697,7 +697,7 @@ static skeletonkey_result_t dd_detect(const struct skeletonkey_ctx *ctx) } /* Predates the bug: rxgk RESPONSE-handling code was added in 7.0. */ - if (v->major < 7) { + if (!skeletonkey_host_kernel_at_least(ctx->host, 7, 0, 0)) { if (!ctx->json) fprintf(stderr, "[i] dirtydecrypt: kernel %s predates the rxgk " "RESPONSE-handling code added in 7.0 — not applicable\n", diff --git a/tests/test_detect.c b/tests/test_detect.c index fd1c1e1..33bacee 100644 --- a/tests/test_detect.c +++ b/tests/test_detect.c @@ -33,6 +33,14 @@ extern const struct skeletonkey_module dirtydecrypt_module; extern const struct skeletonkey_module fragnesia_module; extern const struct skeletonkey_module pack2theroot_module; extern const struct skeletonkey_module overlayfs_module; +extern const struct skeletonkey_module dirty_pipe_module; +extern const struct skeletonkey_module dirty_cow_module; +extern const struct skeletonkey_module ptrace_traceme_module; +extern const struct skeletonkey_module cgroup_release_agent_module; +extern const struct skeletonkey_module nf_tables_module; +extern const struct skeletonkey_module fuse_legacy_module; +extern const struct skeletonkey_module cls_route4_module; +extern const struct skeletonkey_module overlayfs_setuid_module; static int g_pass = 0; static int g_fail = 0; @@ -132,6 +140,54 @@ static const struct skeletonkey_host h_ubuntu_24_userns_ok = { .has_dbus_system = true, .has_systemd = true, }; + +/* Ancient kernel that predates many bugs (Linux 4.4 LTS). Useful for + * the "kernel predates the bug → OK" path in dirty_pipe (bug + * introduced 5.8). */ +static const struct skeletonkey_host h_kernel_4_4 = { + .kernel = { .major = 4, .minor = 4, .patch = 0, + .release = "4.4.0-ancient" }, + .arch = "x86_64", + .nodename = "test", + .distro_id = "debian", + .is_linux = true, + .is_debian_family = true, + .unprivileged_userns_allowed = true, +}; + +/* Recent kernel (Linux 6.12 LTS). Above virtually every backport + * threshold in the corpus — modules should report OK via the + * "patched by mainline inheritance" branch of kernel_range_is_patched. */ +static const struct skeletonkey_host h_kernel_6_12 = { + .kernel = { .major = 6, .minor = 12, .patch = 0, + .release = "6.12.0-recent" }, + .arch = "x86_64", + .nodename = "test", + .distro_id = "debian", + .is_linux = true, + .is_debian_family = true, + .unprivileged_userns_allowed = true, +}; + +/* Vulnerable-era kernel (5.14.0) with userns DISABLED. Most + * netfilter / overlayfs / cgroup-class modules need both an in-range + * kernel AND unprivileged userns. Kernel 5.14 was deliberately + * chosen to clear every module's "predates the bug" pre-check in + * this batch (nf_tables introduced 5.14; overlayfs_setuid 5.11; + * cls_route4/fuse_legacy older still) while remaining below every + * stable-branch backport entry (5.15.x / 5.18.x / 5.19.x in the + * relevant tables). The version check therefore says "VULNERABLE by + * version", and the userns gate fires next. */ +static const struct skeletonkey_host h_kernel_5_14_no_userns = { + .kernel = { .major = 5, .minor = 14, .patch = 0, + .release = "5.14.0-vuln-no-userns" }, + .arch = "x86_64", + .nodename = "test", + .distro_id = "debian", + .is_linux = true, + .is_debian_family = true, + .unprivileged_userns_allowed = false, +}; #endif /* __linux__ */ /* ── tests ───────────────────────────────────────────────────────── */ @@ -175,6 +231,57 @@ static void run_all(void) run_one("overlayfs: distro=fedora → not Ubuntu → OK", &overlayfs_module, &h_fedora_no_debian, SKELETONKEY_OK); + + /* ── kernel-version-gate cases (post-migration coverage) ──── */ + + /* dirty_pipe: bug introduced in 5.8; kernel 4.4 predates → OK */ + run_one("dirty_pipe: kernel 4.4 predates 5.8 → OK", + &dirty_pipe_module, &h_kernel_4_4, + SKELETONKEY_OK); + + /* dirty_pipe: kernel 6.12 is above every backport entry → OK */ + run_one("dirty_pipe: kernel 6.12 above all backports → OK", + &dirty_pipe_module, &h_kernel_6_12, + SKELETONKEY_OK); + + /* dirty_cow: fix in mainline 4.9; kernel 6.12 is far above → OK */ + run_one("dirty_cow: kernel 6.12 above 4.9 fix → OK", + &dirty_cow_module, &h_kernel_6_12, + SKELETONKEY_OK); + + /* ptrace_traceme: fix in 5.1.17; kernel 6.12 above → OK */ + run_one("ptrace_traceme: kernel 6.12 above 5.1.17 fix → OK", + &ptrace_traceme_module, &h_kernel_6_12, + SKELETONKEY_OK); + + /* cgroup_release_agent: fix in mainline 5.17; kernel 6.12 above → OK */ + run_one("cgroup_release_agent: kernel 6.12 above 5.17 fix → OK", + &cgroup_release_agent_module, &h_kernel_6_12, + SKELETONKEY_OK); + + /* ── userns-gate cases ───────────────────────────────────── */ + + /* nf_tables: vulnerable kernel 5.10.0 + userns off → PRECOND_FAIL */ + run_one("nf_tables: vuln kernel + userns=false → PRECOND_FAIL", + &nf_tables_module, &h_kernel_5_14_no_userns, + SKELETONKEY_PRECOND_FAIL); + + /* fuse_legacy: vulnerable kernel + userns off → PRECOND_FAIL */ + run_one("fuse_legacy: vuln kernel + userns=false → PRECOND_FAIL", + &fuse_legacy_module, &h_kernel_5_14_no_userns, + SKELETONKEY_PRECOND_FAIL); + + /* cls_route4: vulnerable kernel + userns off → PRECOND_FAIL */ + run_one("cls_route4: vuln kernel + userns=false → PRECOND_FAIL", + &cls_route4_module, &h_kernel_5_14_no_userns, + SKELETONKEY_PRECOND_FAIL); + + /* overlayfs_setuid: vulnerable kernel (5.14, past the 5.11 + * introduction and below every backport) + userns off + * → PRECOND_FAIL via userns gate */ + run_one("overlayfs_setuid: vuln kernel + userns=false → PRECOND_FAIL", + &overlayfs_setuid_module, &h_kernel_5_14_no_userns, + SKELETONKEY_PRECOND_FAIL); #else fprintf(stderr, "[i] non-Linux platform: detect() bodies are stubbed; " "tests skipped (would tautologically pass).\n");