| name | add-exploit-primitive |
| description | Add a Linux or Android kernel exploit primitive to ingots_tools/primitives/src/primitive_data in the exact format consumed by primitives/src/primitives/__init__.py. Use when creating a new primitive entry with metadata.json, PRIMITIVE.md, and primitive.c, or when updating an agent to generate primitives for this repository. |
Add Exploit Primitive
Add new primitives under primitives/src/primitive_data/<primitive_name>/.
The absolute path in this checkout is /home/jack/Documents/college/purdue/research/kernelcveanalysis/ingots_tools/primitives/src/primitive_data/<primitive_name>/.
Use that absolute path when the current working directory is not the repository root.
Use this exact file layout:
primitives/src/primitive_data/<primitive_name>/
├── metadata.json
├── PRIMITIVE.md
└── primitive.c
Absolute path:
/home/jack/Documents/college/purdue/research/kernelcveanalysis/ingots_tools/primitives/src/primitive_data/<primitive_name>/
├── metadata.json
├── PRIMITIVE.md
└── primitive.c
Use snake_case for the directory name. Keep metadata.json["name"] equal to the directory name unless there is a strong reason not to.
Read The Real Schema First
Treat primitives/src/primitives/__init__.py as the source of truth.
The parser loads each child directory only if all three files exist:
metadata.json
PRIMITIVE.md
primitive.c
The metadata schema is:
name: string
description: string
target: one of linux, android, or any
version: optional string
arch: list of x86, amd64, or aarch64
Do not invent other architecture names. In particular, use aarch64, not arm64.
Write metadata.json
Keep it short and machine-parseable.
Requirements:
- Make
description one or two sentences about the primitive's effect.
- Set
target to the narrowest correct value.
- Omit
version only when the primitive is not tied to a kernel range.
- Use only parser-valid architecture values.
Template:
{
"name": "example_primitive",
"description": "One or two sentences describing what the primitive gives the exploit.",
"target": "linux",
"arch": ["amd64", "aarch64"],
"version": "any"
}
Write PRIMITIVE.md
Write for a reader who wants to reuse the primitive in another exploit.
Required content:
- A title.
- A short opening paragraph describing the primitive.
## Preconditions
## Usage
## How It Works
Recommended content:
## Key Concepts for critical caveats, allocator constraints, structure fields, or kernel-version notes.
Expectations for each section:
Preconditions: spell out the bug class, heap/layout assumptions, required leaks, target cache/object sizes, and any environmental requirements.
Usage: describe the intended call flow against the C API in primitive.c.
How It Works: explain the kernel mechanism the primitive abuses, not just the user-facing steps.
Prefer concrete constraints over vague prose. If the primitive depends on a specific slab cache, object overlap, refcount state, or timing window, say so explicitly.
Write primitive.c
Make the code sample reusable, not exploit-specific glue.
Requirements:
- Use
_GNU_SOURCE.
- Include the headers needed for the sample to make sense.
- Define a context/config struct when the primitive has state.
- Provide setup and usage functions.
- Add cleanup helpers when resources must be released.
- Add comments where the behavior is non-obvious.
- Add a short sample-usage comment if the function flow is not already obvious from the API.
Preferred naming:
typedef struct { ... } <primitive_name>_ctx_t;
int init_<primitive_name>(...)
int execute_<primitive_name>(...) or multiple execute_<primitive_name>_<action>(...)
void cleanup_<primitive_name>(...) when needed
Keep the sample focused on the primitive:
- Include only the code needed to initialize, trigger, and clean up the primitive.
- Stub or comment assumptions that depend on exploit-specific context.
- Prefer small helper functions over one monolithic function.
Use Existing Entries Carefully
Use primitives/src/primitive_data/pipe_spray/ and primitives/src/primitive_data/pipe_buffer_rw/ as style references for layout and tone.
Do not blindly copy field values from existing examples. Some existing example metadata is stale relative to the parser; new entries must satisfy primitives/src/primitives/__init__.py.
Validate Before Finishing
After adding the new directory, verify that the parser can load it.
From primitives/, run:
uv run python - <<'PY'
from pathlib import Path
from primitives import load_primitives
prims = load_primitives(Path("src/primitive_data"))
print("loaded:", [p.name for p in prims])
PY
If the new primitive is missing, fix the metadata values or required filenames first.
Final Checklist
- Create
primitives/src/primitive_data/<primitive_name>/.
- Use
/home/jack/Documents/college/purdue/research/kernelcveanalysis/ingots_tools/primitives/src/primitive_data/<primitive_name>/ when an absolute path is safer.
- Add
metadata.json, PRIMITIVE.md, and primitive.c.
- Keep the metadata parser-valid.
- Include
Preconditions, Usage, and How It Works in the markdown.
- Provide commented setup and usage functions in C.
- Validate by loading the directory with the repository parser.