Adds the infrastructure the 7 🟡 PRIMITIVE modules can wire into for
full-chain root pops.
core/offsets.{c,h}: four-source kernel-symbol resolution chain
1. env vars (IAMROOT_MODPROBE_PATH, IAMROOT_INIT_TASK, …)
2. /proc/kallsyms (only useful when kptr_restrict=0 or root)
3. /boot/System.map-$(uname -r) (world-readable on some distros)
4. embedded table keyed by uname-r glob (entries are
relative-to-_text, applied on top of an EntryBleed kbase leak;
seeded empty in v0.2.0 — schema-only — to honor the
no-fabricated-offsets rule).
core/finisher.{c,h}: shared root-pop helpers given a module's
arb-write primitive.
Pattern A (modprobe_path):
write payload script /tmp/iamroot-mp-<pid>.sh, arb-write
modprobe_path ← that path, execve unknown-format trigger,
wait for /tmp/iamroot-pwn-<pid> sentinel + setuid bash copy,
spawn root shell.
Pattern B (cred uid): stub — needs arb-READ too; modules use
Pattern A unless they have read+write.
On offset-resolution failure: prints a verbose how-to-populate
diagnostic and returns EXPLOIT_FAIL honestly.
core/module.h: + bool full_chain in iamroot_ctx
iamroot.c: + --full-chain flag (longopt 7, sets ctx.full_chain)
+ help text describing primitive-only-by-default + the
opt-in to attempt the full chain.
Makefile: add core/offsets.o + core/finisher.o to CORE_SRCS.
Build clean on Debian 6.12.86; --help renders the new flag.
iamroot.c: bump IAMROOT_VERSION from 0.1.0-phase1 → 0.1.0
README.md: replace "bootstrap phase" status with v0.1.0 corpus
breakdown (13🟢 / 7🟡 across 2016→2026 timeline)
CVES.md: redefine 🟡 to mean "primitive fires + groom + witness,
stops short of cred-overwrite chain — refuses to claim
root unless empirically demonstrated"; flip 7 entries
from 🔵 → 🟡; add the two missing 🟢 entries
(cgroup_release_agent, overlayfs_setuid); extend the
operations matrix from 7 → 20 rows.
ROADMAP.md: mark all Phase-7 items landed; add Phase 8 covering
full-chain promotions (nf_tables / xtcompat / af_packet
prioritized — each has a public reference exploit;
IAMROOT's no-fabricated-offsets rule means each needs
an env-var offset table or System.map auto-resolve).
Build clean on Debian 6.12.86; iamroot --version reports 0.1.0.
10th module. Ubuntu-specific userns + overlayfs LPE that injects file
capabilities cross-namespace.
- modules/overlayfs_cve_2021_3493/iamroot_modules.{c,h}:
- is_ubuntu() — parses /etc/os-release for ID=ubuntu or
ID_LIKE=ubuntu. Non-Ubuntu hosts get IAMROOT_OK immediately (the
bug is specific to Ubuntu's modified overlayfs).
- unprivileged_userns_clone gate — sysctl=0 → PRECOND_FAIL
- Active probe (--active): forks a child that enters userns +
mountns and attempts the overlayfs mount inside /tmp. Mount
success on Ubuntu = VULNERABLE. Mount denied = patched / AppArmor
block. Child-isolated so parent's namespace state is untouched.
- Version fallback: kernel < 5.13 = vulnerable-by-inference for
Ubuntu kernels; recommend --active for confirmation.
- Exploit: detect-only stub. Reference vsh's exploit-cve-2021-3493
for full version (mount overlayfs in userns, drop binary with
cap_setuid+ep into upper layer, re-exec outside ns).
- Embedded auditd rules: mount(overlay) syscall + security.capability
xattr writes (the exploit's two-step footprint).
Verified end-to-end on kctf-mgr (Debian):
iamroot --scan → 'not Ubuntu — bug is Ubuntu-specific' → IAMROOT_OK
Module count: 10. Active-probe pattern now applies to dirty_pipe,
entrybleed, and overlayfs (and copy_fail_family via existing
dirtyfail_active_probes global). Detect quality across the corpus
materially improved this session.
dirty_pipe detect: active sentinel probe (Phase 1.5-ish improvement)
- New dirty_pipe_active_probe(): creates a /tmp probe file with known
sentinel bytes, fires the Dirty Pipe primitive against it, re-reads
via the page cache, returns true if the poisoning landed.
- detect() gated on ctx->active_probe: --scan does version-only check
(fast, no side effects); --scan --active fires the empirical probe
and overrides version inference with the empirical verdict. Catches
silent distro backports that don't bump uname() version.
- Three verdicts now distinguishable:
(a) version says patched, no active probe → 'patched (version-only)'
(b) version says vulnerable, --active fires + probe lands → CONFIRMED
(c) version says vulnerable, --active fires + probe blocked → 'likely
patched via distro backport'
- Probe is safe: only /tmp, no /etc/passwd.
nf_tables CVE-2024-1086 (detect-only, new module):
- Famous Notselwyn UAF in nft_verdict_init. Affects 5.14 ≤ K, fixed
mainline 6.8 with backports landing in 5.4.269 / 5.10.210 / 5.15.149
/ 6.1.74 / 6.6.13 / 6.7.2.
- detect() checks: kernel version range, AND unprivileged user_ns clone
availability (the exploit's reachability gate — kernel-vulnerable
but userns-locked-down hosts report PRECOND_FAIL, signalling that
the kernel still needs patching but unprivileged path is closed).
- Ships auditd + sigma detection rules: unshare(CLONE_NEWUSER) chained
with setresuid(0,0,0) on a previously-non-root process is the
exploit's canonical telltale.
- Full Notselwyn-style exploit (cross-cache UAF → arbitrary R/W → cred
overwrite or modprobe_path hijack) is the next commit.
9 modules total now. CVES.md and ROADMAP.md updated.
- modules/entrybleed_cve_2023_0458/ (promoted out of _stubs):
- iamroot_modules.{c,h}: full EntryBleed primitive (rdtsc_start/end
+ prefetchnta + KASLR-slot timing sweep) wired into the standard
iamroot_module interface. x86_64 only; ARM/other gracefully
return IAMROOT_PRECOND_FAIL.
- detect(): reads /sys/.../vulnerabilities/meltdown to decide
KPTI status. Mitigation: PTI → VULNERABLE. Not affected → OK.
- exploit(): sweeps the 16MiB KASLR range, prints leaked kbase
(and KASLR slide). JSON-mode emits {"kbase":"0x..."} to stdout.
- entrybleed_leak_kbase_lib(off) declared as a public library
helper so future LPE chains needing a stage-1 leak can just
#include the module's header and call it.
- entry_SYSCALL_64 slot offset overridable via
IAMROOT_ENTRYBLEED_OFFSET (default 0x5600000 for lts-6.12.x).
- __always_inline fallback added since glibc/Linux-kernel macro
isn't universal; module now builds clean under macOS clangd lint
and on musl.
- iamroot.c registers entrybleed alongside the other families;
Makefile gains it as a separate object set.
Verified end-to-end on kctf-mgr (Debian 6.12.86):
iamroot --exploit entrybleed --i-know
→ [+] entrybleed: leaked kbase = 0xffffffff8d800000
This is the FIRST WORKING-EXPLOIT module in IAMROOT (5
copy_fail_family modules wrap existing code from DIRTYFAIL;
dirty_pipe is detect-only). EntryBleed is x86_64 stage-1 brick
that future chains can compose.
- core/kernel_range.{c,h}: branch-aware patched-version comparison.
Every future module needs 'is the host kernel in the affected
range?'; centralized here. Models stable-branch backports
(e.g. 5.10.102, 5.15.25) so a 5.15.20 host correctly reports
VULNERABLE while a 5.15.50 host reports OK.
- modules/dirty_pipe_cve_2022_0847/ (promoted out of _stubs):
- iamroot_modules.{c,h}: dirty_pipe module exposing detect() that
parses /proc/version and compares against the four known patched
branches (5.10.102, 5.15.25, 5.16.11, 5.17+ inherited). Returns
IAMROOT_OK / IAMROOT_VULNERABLE / IAMROOT_TEST_ERROR with stderr
hints in human-readable scan mode.
- exploit() returns IAMROOT_PRECOND_FAIL with a 'not yet
implemented' message; landing the actual exploit needs Phase 1.5
extraction of passwd/su helpers into core/.
- detect/auditd.rules: splice() syscall + passwd/shadow file watches
- detect/sigma.yml: non-root modification of /etc/passwd|shadow|sudoers
- iamroot.c main() calls iamroot_register_dirty_pipe() alongside
the copy_fail_family registration.
- Makefile gains the dirty_pipe family as a separate object set.
Verified end-to-end on kctf-mgr (kernel 6.12.86): build clean, 6
modules in --list, --scan correctly reports dirty_pipe as patched,
JSON output ingest-ready.