kharness is a local-first MVP harness for authorized KernelCTF and local-lab kernel exploitability triage.
- Cases are isolated in
kharness/cases/<case-id>/. - Facts are stored as append-only JSONL in
evidence.jsonl. - Trace events are stored as append-only JSONL in
trace.jsonl. - Runtime claims are derived from typed schemas and replayable artifacts.
target import-kctfdefaults to the current KernelCTF latest-LTS runtime profile, not raw.configreachability.- The single autonomous entrypoint is
kharness run: it can refresh scout recon/plan context, execute bounded scout workers, then run the deep worker loop that chooses source/artifact/scout/probe actions.
The latest-LTS profile follows the public KernelCTF server rules and qemu.sh shape:
- unprivileged user namespaces disabled with
sysctl.user.max_user_namespaces=1 io_uringdisabled withsysctl.kernel.io_uring_disabled=2- nftables treated as unavailable
- unprivileged BPF treated as unavailable
- post-2025 BPF JIT hardening enabled with
sysctl.net.core.bpf_jit_harden=2 - QEMU profile records
3.5GRAM and 2 vCPUs
Local kenv cpio workspaces still differ from the live KernelCTF environment in one important way: they do not model the read-only ext4 rootfs_v3.img plus ramdisk_v1.img boot flow. Treat page-cache, setuid-binary, mount, and flag-drive behavior as unproven until tested against a KernelCTF-style ext4 rootfs or the live target.
If you have a rootfs_v3.img-style raw disk, import it with:
PYTHONPATH=src python3 -m kharness.cli target import-kctf \
--name lts-6.12.95 \
--bzimage /path/to/bzImage \
--config /path/to/.config \
--rootfs /path/to/rootfs_v3.img \
--rootfs-kind kernelctf-ext4-rootfs_v3.img \
--uid 1000Disk-mode probe execution is supported through kharness probe qemu-run. Probes build with a local compiler, then qemu-run overlays the probe into a copy of ramdisk_v1.img and boots QEMU with the read-only raw disk unchanged.
PYTHONPATH=src python3 -m kharness.cli --root /path/to/research-root probe qemu-run \
--case <case-id> \
--source /path/to/case/probes/condition/probe.c \
--base-initrd /path/to/ramdisk_v1.img \
--probe-cc /usr/bin/gcc \
--qemu-bin /usr/bin/qemu-system-x86_64For initramfs/cpio targets that do not run scripts/<stage> hooks, qemu-run
falls back to a direct /init wrapper and records the selected hook mode in
runs/<run-id>/initrd-hook.json and the QEMU result JSON.
- Python 3.12+
- A writable checkout of this repository.
kenvfor local kernel workspace execution (optional but supported).
Default model provider is the local Codex executor:
- provider:
codex_exec - model:
x-preview-f-free - reasoning effort:
xhigh - executor:
bin/codex-free --yolo exec(configurable Codex profile) - default autonomous profile:
run - stage budgets:
run,critic,probe_generator,reflection,summary, anddelta_context
Deep-worker lanes run as one stateful codex exec --json turn. Kharness is
attached as a required stdio MCP server, so source reads, artifact reads,
candidate changes, generated probes, QEMU runs, judgements, and finish events
remain artifact-backed while Codex keeps its plan and reasoning context across
tool calls. A generated worker hook blocks shell, file-edit, and subagent tools,
and web search is disabled, preventing those paths from bypassing the ledger.
Codex automatic compaction handles long turns.
export KHARNESS_CODEX_BIN="$PWD/bin/codex-free"
export KHARNESS_CODEX_ARGS="--yolo"
export KHARNESS_CODEX_MODEL=x-preview-f-free
export KHARNESS_CODEX_REASONING_EFFORT=xhighOverride defaults without editing code:
export KHARNESS_RUN_REASONING_EFFORT="xhigh"
export KHARNESS_RUN_TIMEOUT=1800
export KHARNESS_RUN_BACKGROUND=falseEach run records the Codex thread ID, sanitized JSON event stream, usage,
compaction count, MCP calls, transcript, and final response. --resume-run
resumes that same Codex thread with a small ledger delta rather than rebuilding
the full prompt. KHARNESS_MODEL_PROVIDER and alternate API providers were
removed; setting the old provider variable is an explicit configuration error.
When kharness run uses --budget-profile auto, kharness selects the run
profile so the LLM has enough room to choose strategy before the harness narrows
anything.
source index remains available as source inventory/context for model runs. It
is not a ranking or pre-filtering policy.
The live target is lts-6.12.95. Its payout slot is already occupied; use it
for current-target validation while preparing lts-6.12.96, scheduled to go
live on 2026-08-07. Recheck the live server before beginning a campaign rather
than relying on the lagging public releases.yaml.
PYTHONPATH=src python3 -m kharness.cli target import-kctf \
--name kernelctf-lts-6.12.95 \
--bzimage /path/to/assets/kernelctf/releases/lts-6.12.95/bzImage \
--config /path/to/assets/kernelctf/releases/lts-6.12.95/.config \
--rootfs /path/to/orig/rootfs.cpio \
--uid 1000
PYTHONPATH=src python3 -m kharness.cli surface map --case kernelctf-lts-6.12.95-default-000000 --run-probe
PYTHONPATH=src python3 -m kharness.cli --root /path/to/research-root scout recon \
--case kernelctf-lts-6.12.95-default-000000 \
--source-root /path/to/linux-6.12.95 \
--path net --path fs --path drivers
PYTHONPATH=src python3 -m kharness.cli --root /path/to/research-root run \
--case kernelctf-lts-6.12.95-default-000000 \
--source-root /path/to/linux-6.12.95 \
--base-initrd /path/to/ramdisk_v1.img \
--scout-max-tasks 200 \
--parallel 50 \
--qemu-parallel 2
PYTHONPATH=src python3 -m kharness.cli --root /path/to/research-root judge qemu \
--case kernelctf-lts-6.12.95-default-000000
PYTHONPATH=src python3 -m kharness.cli --root /path/to/research-root probe next \
--case kernelctf-lts-6.12.95-default-000000
PYTHONPATH=src python3 -m kharness.cli score --case kernelctf-lts-6.12.95-default-000000
PYTHONPATH=src python3 -m kharness.cli replay --case kernelctf-lts-6.12.95-default-000000probe qemu-run automatically writes judge.result.json and
primitive-ladder.result.json beside the QEMU result, plus durable case-level
entries under judgements/ and primitive_ladders/.
kharness target import-kctf ...kharness surface map --case <case-id> [--run-probe]kharness run --case <case-id> --source-root <linux-tree> [--base-initrd <ramdisk_v1.img>]- Stateful Codex workers have no harness-imposed model/tool-call ceiling by default.
--max-steps <n>sets an optional finite budget;--max-steps 0is unlimited. With--resume-run, a positive value appends up to<n>more steps after the existing transcript.--parallel <n>is the harness-wide fanout policy. It applies to scout execution, deep-worker lane scheduling, and read-only action fanout. Use--model-parallel,--io-parallel, and--qemu-parallelonly as resource caps.--scout-max-tasks <n>executes that many narrow scout tasks before the deep worker. Use--scout-onlyto stop after scout artifacts are written.- With
--parallel > 1,kharness runwritesscheduler_runs/<id>/scheduler-run.result.jsonand launches independent worker lanes from unvalidated probe plans and scout measurement questions. - Run prompts include generic loop-health context from the transcript, such as source-only streaks, repeated source paths, recent source retirements, and recent probe/QEMU activity. This nudges the model to probe, finish/retire, or pivot without adding harness-owned candidate filters.
kharness scout recon --case <case-id> --source-root <linux-tree> [--path <relative-path>]kharness scout plan --case <case-id> --source-root <linux-tree> [--max-tasks <n>]kharness scout validate --case <case-id> --result <scout/runs/.../result.json>kharness scout summarize --case <case-id> [--manifest <manifest-id>]kharness source index --case <case-id> --source-root <linux-tree> [--path <relative-path>]kharness delta mine --case <case-id> --patch <patch> [--source-root <linux-tree>]as patch inventory/context onlykharness probe register --case <case-id> --source <probe.c> --stage <reachability|trigger|condition|primitive>kharness probe qemu-run --case <case-id> --source <probe.c> --base-initrd <ramdisk_v1.img>kharness judge qemu --case <case-id> [--run-result <qemu-run.result.json>]kharness probe next --case <case-id> [--judge-result <judge.json>]kharness model budget --case <case-id> [--purpose run]kharness eval builtinkharness env preflight [--case <case-id>] [--base-initrd <ramdisk.img>] [--probe-cc <cc>] [--source-root <linux-tree>]- With
--case, preflight records target asset, source root, base-initrd, QEMU, and local compiler readiness inenv_preflight.json, includingcase_setup_blockedfailure subtypes when local QEMU cannot run.
- With
kharness replay --case <case-id>kharness score --case <case-id>